如何使用WebGL异步加载图像、创建纹理、渲染和保存图像?

3
我正在尝试编写一个使用非常大的纹理的应用程序。想法是,在实时修改着色器时,您可以在缩小的纹理版本上工作,完成后,应用程序将应用您的更改到原始未缩放(大)纹理。问题在于分析显示类似以下内容:
- img.src = filename (500ms) - texImage2d(...) (1500ms) - 绑定/渲染 (100ms) - readPixels (300ms) - 放入画布 (1000ms) - 将画布保存到文件 (300ms)
这意味着在保存更大的未缩放纹理时,浏览器几乎要卡住4秒钟,用户无法做任何事情。是否可能以异步方式执行此操作,使浏览器保持响应?它需要完全在JavaScript和客户端中完成,因为我正在使用本地文件(HTML5文件/文件系统)。
Web Workers听起来像是个好主意,但它们无法访问DOM,因此我无法使用浏览器的图像加载和保存功能,它们也无法访问WebGL上下文,因此无法调用花费最长时间的texImage2d。
由于图像的大小和数量,我不能在页面最初加载时将它们全部加载到内存中作为纹理。
有什么方法可以使此操作对用户更加响应灵敏?我希望他们能够在上一个图像渲染时继续处理下一个图像。
2个回答

2
图像加载应该在后台进行,你无法获得进度的信息,但是你可以使用texSubImage2D逐步上传纹理。总体而言可能需要更长的时间,但你应该能够给用户一些反馈并响应其他事件。
此外,你可以直接将webgl画布绘制到canvas 2D中。 drawImage()接受图像、视频和canvas(2D或webgl)元素作为参数。这应该几乎瞬间完成,并节省约1300毫秒。

谢谢,直接将画布传递给drawImage可以节省很多时间。使用texSubImage2D似乎也有很大帮助。 - Daniel
嗯,仔细想想,我错了。drawImage调用速度更快,但事实证明它只是写入黑色矩形而不是图像数据。 - Daniel
现在这真的很奇怪。我用Win7和OS X上的FF可以工作,但当我在Chrome中尝试时,它不仅不起作用,而且在我尝试将其绘制到2D画布时会清除WebGL画布! - andrewmu
1
看起来 preserveDrawingBuffer WebGL 上下文属性可以解决这个问题,例如 canvas.getContext('webgl', { preserveDrawingBuffer: true }); 设置后,现在在 Chrome 中可以正确绘制,所以我实际上可以使用 drawImage! - Daniel

1

虽然这个问题比较老,但对于其他人来说,以下是一些更新的信息。

  • You can consider using OffscreenCanvas which has been shipping in Chrome since January 2019. Unfortunately it's not shipping anywhere else ATM

  • These 3 synchronous steps

    readPixels (300ms)
    Put into canvas (1000ms)
    Save canvas to file (300ms)
    

    can be turned into 1 asynchronous step

    gl.canvas.toBlob((blob) => {
      const url = URL.createObjectURL(blob);
      // url is now something you can give the user to download
    });
    
  • for rendering really large images (say 16k by 16k) you can render smaller portions and assemble them into a larger image.

    There's a library for that here: https://greggman.github.io/dekapng/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接