WebGL - 如何渲染大型纹理?

8

我正在使用WebGL进行图像处理。但是如果我尝试在移动设备上加载大图片(例如相机拍摄的8MP照片)到一个GLSL纹理中,浏览器会崩溃。小图片则可以正常工作。所以我认为是因为内存不足。

我已经搜索了很多,但没有找到解决方案。我认为最好的方法是实现“分块”渲染。将8MP图片分成较小的部分,渲染它们并将它们粘合在一起。但是将会出现问题,例如应用模糊效果时可能会看到“子渲染”的边缘。所以我必须渲染重叠的像素并将它们“淡化”在一起。听起来并不好。

是否有任何解决方案我没有想到的?如何处理移动设备上真正巨大的纹理?


我看过一个很好的基于WebGL瓦片处理的例子在这里。它在我的Nexus 7上运行良好。 - user625860
不是我要找的。他正在将许多瓷砖绘制到一个大画布上。我正在寻找一种将着色器效果应用于大型图像的解决方案。不知道最好的方法是什么。通过“基于瓦片的渲染”,我的意思是将大图像分成许多小图像,并对每个小图像应用着色器。然后把它们全部放在一起。但是这在某些效果(如模糊效果)下效果不佳。当模糊(或锐化等)时,您必须考虑周围的像素。因此,如果您模糊每个小图像并将它们再次组合,您将看到每个小图像的边缘。 - André Fiedler
所以我的问题是,如何在WebGL中处理大图像/纹理?有哪些可能性? - André Fiedler
2个回答

4

一个8mp的图片不太可能超过可用的内存。在RGB(字节)下,它将占用24mb的内存。即使在半浮点精度下,它也需要50mb的内存。ARM系统使用统一的内存架构,其中GPU和CPU共享内存。例如,iPhone有1GB可用的内存。

纹理支持应该达到所需的大小(例如3264x2248),这在高端手机上似乎没有问题(81%的手机支持4096x4096)。

最大绘图缓冲区大小可能比最大支持的纹理大小小(您可以查询)。

除此之外,您可能只是遇到了一个错误,这很烦人。因此,处理方法是将图像分成较小的图块,逐个处理每个图块。

如果您有滤波器核心,则有两种方法可以处理边框。

  • 您可以传递9个纹理,并分支以寻址正确的纹理(这可能会很慢,某些GPU不支持分支并将执行所有代码路径)。边框纹理只需为2x2,因此占用的内存很小。注意,在纹理之间不会进行插值,因此不要依赖它,或使用自己的替代品。
  • 您可以在每个图块周围添加一个一半大小的边框,在预处理步骤中从相邻的图块中取像素。

太有帮助了,非常感谢!在桌面浏览器上一切都运行正常,但在移动设备上崩溃了。我原本以为是内存不足,但你说得对,应该有足够的内存。因此,我将首先实现一些GL函数调用日志记录,并查看在哪个调用时崩溃。再次感谢您的精彩文章! - André Fiedler

3
要让瓷砖工作,您需要在边界提供足够的输入来覆盖图像处理效果的非局部性,例如模糊核的半径。我能想到的最简单的方法是:
对于每个输出图像的瓷砖,请加载相应的输入瓷砖及其8个邻居。然后使用所有9个作为输入运行模糊滤镜:通常情况下会调用texture2D,而现在需要使用一个(自定义)函数,该函数接受坐标并在9个纹理之一中查找它们。
为了使用更少的纹理,请将输出瓷砖与输入瓷砖相比,在两个维度上将其偏移半个边长;然后您只需要为每个瓷砖计算使用4个输入瓷砖,但如果使用足够的瓷砖覆盖所有输入,则输出瓷砖将具有额外的边框。(另一方面,如果您在修剪后聪明地使用,则可以成为一个好东西;例如,如果我对输入图像应用阴影,我希望阴影扩大输出而不是被截断在原始边界处。)
如果您正确执行此操作,则瓷砖边界处应该没有任何伪影。
(免责声明:虽然此解决方案对我来说似乎简单,明显且正确,但我既不是图像处理专家也不是GPU资源保护专家。这可能无法正常工作,或者有更好的想法存在。)

这是一个非常好的想法,不需要像给每个瓷砖添加一些“边距”和“淡入淡出”那样进行大量计算。你的解决方案应该更容易实现。谢谢!:)也许有更好的GLSL解决方案吗?有专家在场吗? - André Fiedler

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