WebGL Tips

WebGL notes

Khronos定制的WebGL specification,Chrome和Firefox在实现desktop的WEBGL时,开发了一个图形API库ANGLE。ANGLE提供了webgl的API接口,在非原生openGL-es的平台上,通过其他图像API对WGL的API进行模拟和映射。

由于js是动态脚本语言同时非强类型,在js脚本对API的调用较为随意,而图形API的原始API是基于C/C++的。所以ANGLE在gl方法调用时为了确保每次API调用都不会使得底层使用的图像API crash,做了大量的验证。这部分overhead相对于原生的directX和openGL来说是比较大的。所以在desktop中调用webgl会有更多driver层的overhead。

同时对于desktop的WebGL和mobile的webgl来说,由于ANGLE做了一部分保护,部分API的行为方式在不同平台根据实现的差异上会有不同。例如在desktop chrome和iOS webview中,gl.BindBuffer()方法的buffer对象传入undefined是不会报错的,而在Android的微信tencent X5浏览器中就会直接报错。

WebGL insight Tips

  1. WebGL Report 可以查看浏览器的WebGL支持情况,尤其是在调试浏览器或设备相关的问题。
  2. 避免在渲染loop中进行对象内存分配,尽可能重用对象和数组,尽量避免使用mapfilter等内置数据方法。每个新对象的内存分配会有一些GC相关的工作,在一些情况下GC会阻塞渲染循环造成几帧的卡顿。
  3. 在没有必要的情况下,不要使用alpha,depth,stencil,antialias以及将preserveDrawingBuffer设置为false,这样会节约一部分内存。同时需要时刻注意在使用完alpha,depth,antialias之后需要将context状态显示关闭。
  4. 获取attribute和uniform location只在初始化时进行。
  5. int precision 标志在vertex 和fragment shader中并不相同,使用int precision会导致不正确的渲染效果。
  6. 考虑兼容性,在varying和uniform属性是,vs和ps中保持相同的大小,同时在GLSL ES的规范中。考虑使用vec4替代float数组,vec4会有更紧密的内存排布.
  7. 非2次幂的贴图只支持linear或nearest filter以及clamp-to-border,clampmode 支持clamp-to-edge wrapping. Mipmap filtering 和 repeat wrapping不支持。
  8. WEBGL_draw_buffers extesnion下,当使用超过一个draw buffer时,如果不需要往某个draw buffer绘制,将gl.NONE 传递给draw buffer的参数留别。
  9. 始终使用"use strict" 声明编写代码,许多被隐藏的错误会被转换为运行时异常抛出。"use strict"使得在特定情况下浏览器可以对代码进行更好的优化。
  10. Code linters,如JSHint对保持JS代码整洁以及更少错误来说是一个非常有用的工具。
  11. 始终创建一个新的Texture而不是改变原先贴图的大小以及格式。
  12. 避免使用gl.TRIANGLE_FAN,gl.TRIANGLE_FAN是在CPU端进行模拟的。
  13. 在合适的情况下使用gl.STATIC_DRAW标记1buffer,gl.STATIC_DRAW使得浏览器和驱动层可以对静态数据的buffer有更多性能上的优化。
  14. 确保有一个attribute被绑定到gl.bindAttribLocationlocation 0.否则在非openGL-ES得平台上会有较高的overhead,如MacOSX 以及desktop Linux.
  15. 尽可能使用transferable objects在Web Workers直接传递数据。
  16. typed arrays 有更高的性能相对于JS的array。
  17. 在fragment shaders中使用mediump精度会有更好的设备兼容性,但还是有可能在缺少足够测试的情况下影响渲染结果。
  18. 使用highp精度会有更大的性能消耗但是渲染结果更加准确,在vertex shader中推荐使用highp.
  19. 使用mediumplowpprecision进行设备shader的兼容性测试,在Chrome中可以使用emulateprecision使用软件来模拟测试。
  20. 使用RGB framebuffer时,始终实现RGBA格式的fallback在RGB framebuffer不支持的情况下。使用gl.checkFramebufferStatus获得更多信息。
  21. 使用vertex array objects(VAOs)和interleave static vertex data可以减少许多GL的API调用。考虑性能,尽量不要在每帧更新uniform,而只在uniform变化时更新。
  22. 如果在缩放浏览器的窗口大小会有大幅度的性能提升,可以考虑在鼠标拖动的互动时使用一半分辨率的framebuffer。
  23. 分散较慢的任务跨帧执行可以优化加载时间。
  24. 确保所有的WebGL方法调用全部都在requestAnimationFrame方法中执行。
  25. GLSL方法textureProj,如vec4 color = textureProj(sampler,uv.xyw)可以使用vec4 color = texture(sampler,uv.xy/uv.w)进行模拟。
  26. 避免使用Wavefront OBJ或COLLADA这类text-based 3D 数据格式进行资源分发。使用glTF或SRC这类优化过的Web资源格式作为替代方案。
  27. 使用OES_element_index_uint 在一次draw call中绘制indexed超过uint16.Max 65535的模型。
  28. 平滑的相机移动可以使用cosine-base插值对位置和旋转进行计算。相对于线性插值,余弦插值有更少的性能消耗以及更简单的计算公式。