opengl/webgl的性能优化是一个永远的话题,涉及到的东西也不少,这里对本身了解到的性能优化作个总结。web
1. 避免在shader中作逻辑判断,好比if else。性能优化
有的人可能会很疑惑,为什么要这样?这和GPU的基本调度有关系,GPU的基本调度单位叫作wavefront, 就是指一组彻底相同的计算指令,在GPU的几个计算单元中并行执行,每个指令的输入数据不一样而已。这样并行度很高,能够极大程度提升性能。可是一旦引入if else,就会把wavefront破坏掉,好比如今有10个计算单元在并发执行,可是碰到if,在5个计算单元中为true, 在5个计算单元中为false, 这样会形成新的计算指令,那么以前的并行运算将没法继续。新的计算指令须要排队等待执行,或者新的指令要转移到新的计算单元上,这个过程涉及到数据的复制转移,会比较耗时,会严重破坏并行度。并发
可是有些场景下,shader中彻底不用逻辑判断又不行,那该如何呢?能够考虑使用shader的内置函数,好比step函数,案例以下:函数
float a;性能
if(b >1){测试
a = 1;优化
}else{webgl
a = 0.5;线程
}orm
能够优化为:
float a;
float temp = step(b, 1);
a = temp * 0.5 + (1 - temp);
2. 减小三角形数量
较少三角形的数量大致上能够从如下几个角度入手:
(1). 空间分割技术:包括八叉树,四叉树作空间分割,将不在当前可视区域物体剔除掉
(2). 遮挡检测技术:视锥体范围内,有些物体会被前面的物体遮挡,这些被遮挡的物体实际上是不须要渲染的。遮挡查询有多种技术方案实现,好比经过扩扑性,硬件遮挡查询。扩扑性比较麻烦,我这里推荐硬件遮挡查询技术,实现起来相对比较容易。
(3). LOD技术:根据物体距离摄像头的距离,动态调节物体三角形的数量。
(4). 图元类型的优化:使用GL_TRIANGLE_FAN或者GL_TRIANGLE_STRIP替代GL_TRIANGLES,由于这样能够重用顶点,减小三角形的数量。
(5). 使用顶点索引的方法作渲染:使用glDrawElements替代glDrawArrays,由于前者经过索引的方式能够减小三角形的数量。
3. 纹理的优化
(1). 纹理的长宽最好是2的幂。
(2). 纹理压缩:纹理压缩在opengl es 3.0和webgl 2.0上有比较好的支持,经压缩后的纹理能够减小图形数据,节省宽带。常见的压缩格式为ETC,Khronos公司提供有ETC格式压缩的免费压缩包,在opengl/webgl程序中使用glCompressedTexImage2D函数加载被压缩的纹理。
(3). 纹理的上传:传统的纹理上传比较耗时,能够考虑使用两个PBO上传纹理,性能会有较大的提高。
(4). 纹理的合成:若是有不少个小的纹理,每个纹理单独加载,效率比较低下。能够考虑将多个小纹理合成到一个纹理上,仅仅加载一次,而后在程序中使用的时候,使用不一样的纹理坐标范围来加载不一样的纹理。
4. 减小系统内存向GPU内存传送数据的次数
具体能够从以下方面入手:
(1). 尽量使用VBO/VAO
(2). 在opengl es 3.0/webgl 2.0上能够使用Transform Feedback, 该方案能够使用GPU作通用运算,把计算的结果存入VBO中,在后期的渲染流程中使用该VBO做为输入。
(3). 批次合并:好比一个最小包围体内有多个物体,能够将这些物体的三角形合并在一块儿,一次性的发送到GPU。
(4). 使用instance: 若是要渲染多个重复的物体,能够使用instance特性。
5. 针对在复杂计算的优化:
(1). 使用延迟着色:针对在片断着色器中有复杂计算,而且不少顶点不能经过深度测试的场景,延迟着色能够很大程度上提升渲染性能。
(2). 开启多个渲染线程: 每一个渲染线程的viewPort设置为屏幕的一个区域,能够充分利用CPU和GPU