翻译自Mozila开发者文档-WebGL_best_practices
本文提供的建议和技巧可以用来提高的WebGL的表现。遵循这些建议可以使您的Web程序的兼容更多的设备和浏览器,并且提高性能。
需要避免的事情
- 你应该确保程序运行中不产生任何WebGL报错(这些报错是通过
getError()捕获的)。在Firefox的默认设置下,WebGL报错将在控制台中产生一个特殊的JavaScript警告。建议你打开webgl.verbose偏好设置。设置webgl.verbose将使每一个WebGL的错误,和其他一些WebGL的问题,合并为一个带有描述的JavaScript警告消息。你应该不想让一大波报错喷涌到控制台吧?当然。 - 不应该在WebGL的着色器使用
#ifdef GL_ES语句;尽管一些早期的例子中这样做了,不过这是没有必要的。 - 除非你真的需要这么做,否则不要显式设置片段着色器的精度为highp。试着用mediump精度。使用highp精度的片段着色器可能导致你的程序在最新的手机硬件上不工作。从Firefox 11开始,
webgl.getShaderPrecisionFormat()方法可以用来检查硬件对highp精度的支持,并且输出当前平台所有能支持的精度。
要记住的东西
- 一些WebGL的功能依赖于客户端。在使用这些功能之前,你应该使用
webgl.getParameter()函数来检查哪些功能是被支持的。例如,一个2D纹理能被支持的最大尺寸是由webgl.getParameter(webgl.max_texture_size)的值决定的。在Firefox 10中,可以设置名为webgl.min_capability_mode的偏好设置,允许用户模拟WebGL最小值环境,来测试程序可移植性。 - 需要注意的是,你只能在
webgl.getParameter(webgl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)大于0的情况下在顶点着色器中使用纹理(译者:即使用顶点纹理拾取)。通常情况下,移动硬件并不支持此功能。 - 大多数WebGL扩展是否可用取决于客户端。当你使用WebGL扩展的时候,尽量做到向下兼容。Firefox 10中的
webgl.disable-extensions偏好设置,可以模拟所有扩展不可用的情况,借此来测试程序的可移植性。 - 即使
oes_texture_float扩展支持的情况下,在某些移动硬件上,渲染图像到浮点尺寸的纹理也可能失败。要检查是否真的可以,需要调用webgl.checkFramebufferStatus()方法。
一般性能的技巧
- 任何需要同步CPU和GPU的操作都可能非常慢,所以如果可能的话,你应该尽量避免在主循环中这样做。这包括webgl中的操作:
getError(),readPixels(),和finish()。webgl中getter的调用如getParameter()和getUniformLocation()也很缓慢,所以尽量在一个JavaScript变量中缓存获取结果。 - 合并绘制操作将提高性能。如果你有1000个精灵需要绘制,试图只用一次
drawarrays()或drawelements()调用完成。你可以使用DRAW_TRIANGLE模式,来实现一次drawarrays()调用绘制很多不连续的对象。 - 减少状态切换也将提高性能。比如,你可以将多个图像打包成一个单一的纹理,并通过设置恰当的纹理坐标来使用它们,这可以帮助做更少的纹理切换,从而提高性能。
- 使用小纹理比使用大纹理性能更好。因此,mipmapping技术可以提高性能。
- 简单比复杂的着色器执行。特别是,如果你从中删除一个if语句,这将使它运行速度更快。math函数如
log()的开销也是相当大的。 - 总是保证
vertex attrib 0 array启用。如果你在vertex attrib 0 array没有启用的情况下进行绘制,桌面端运行OpenGL时,浏览器会做复杂的模拟(例如在Mac OSX上)。这是因为在桌面端的OpenGL,如果在vertex attrib 0 array没有启用的情况下是绘制不出任何东西的。你可以使用bindAttribLocation()强迫数组使用0号地址,并使用enableVertexAttribArray()启用数组。 - 如果你使用
drawElements()绘制,尽量保证耗尽整个元素数组缓冲区的资源。这是如果你在乎性能,不要只利用数组缓冲区的一部分:保持first=0并且count=数组缓冲区的大小。这样做的原因是,浏览器必须验证所有的索引都在范围内,因此,当你使用整个元素数组缓冲区时很容易,但缓存任意子数组将更难。 - 出于同样的原因,调用
bufferData()或者bufferSubData()更新数组缓冲区将导致下一次drawElements()调用要慢,因为缓存失效了。