优化场景以提高WebGL性能
这里是我们推荐的一些用于优化交互式网页应用的实用技巧。这些技术经过项目实战验证,非常有效。本章节内容主要基于Soft8Soft在Verge3Day Europe2019会议上的 演讲文稿 。
几何体/网格
几何体构成了模型的主要形状,是模型的根基。若要获得更平滑的反射和更快的渲染,应尽量遵守网格规则。您应该在一开始就规划好场景所拥有的细节层次,并在建模时始终坚持这一点。

在建模折痕/褶皱时,尽量选择平滑组而非添加更多的多边形。

在处理圆柱形时,尽量减少其中心的多边形数量。

不要在用户无论如何都看不到的地方增加额外的细节加重模型负担。如下图所示,用突出显示的橙色线定义模型细节程度,用作整体建模参考。

法线贴图
优化WebGL性能的一种常见方法,通过烘焙从高多边形模型到低多边形模型的法线贴图,来减少多边形的数量。

然而,由于8比特图像的精度有限,法线贴图可能会产生可见的伪影。下面是一些常见但并不实际的解决方案:第一种方法,使用更高精度的图像将生成更重的场景资产;第二种方法(平滑组+法线贴图)相当耗时,且也不能保证得到干净的结果;第三种方法(添加噪点)在某些情况下可用:如果您有相当粗糙的表面,建议在材质中添加噪点以减少瑕疵。

根据我们的经验,对于有光泽的物体,最好的解决方案是使用带平滑组的中等面多边形,而不使用法线贴图。

最后,下面是一些可能您倾向使用法线贴图而非高精度网格的情况:
- 您的物体由许多不同的表面组成;
- 您有一个不会产生清晰伪影的粗糙表面;
- 您的物体很远或很小,用户不会注意到任何细节效果。

纹理化
这里是一组PBR渲染管线中常用的典型纹理。

如您所见,大多数都是黑白图片。所以您可以将黑白纹理组合到单个图像的RGBA通道里,每个图像最多可包含4张贴图。

如果您只有一个黑白纹理,可以打包到任何现有的RBG纹理的alpha通道中。如果没有可供合并的纹理,建议将该黑白纹理转换为jpg格式,使用95%的压缩比并启用灰度模式。

另一种减少纹理大小的方法是优化UV空间。UV展开越紧凑,图像使用纹理空间的效率就越高。因此,您可以用更小的图像而不担心质量损失。

顶点色
使用顶点颜色代替图像纹理也可以加快加载速度并有效提高WebGL应用整体性能。但这样做是以消耗额外的边为代价的,为了分离不同的顶点颜色,您必须将这些边添加到模型中。

您也可以使用顶点色来定义粗糙度、金属度、镜面及任何其他参数。从下图您可看到仅使用顶点色的材质示例。

着色器数量
在场景中使用较少的材质/着色器非常有好处。WebGL中对着色器的处理会导致加载时间延长,在Windows系统上尤为明显。因此,如果您的着色器较少,则引擎在渲染时将花费更少的时间在它们之间进行切换,从而提高了性能。
如果您的场景中有仅纹理不同的相似材质,则可以仅使用一种材质,并在运行时环境中加载或交换纹理。为此,您可以使用 replace texture(替换纹理) 拼图或使用JavaScript来完成设置。这样不仅将减少使用着色器的数量,还将减少在应用启动时所加载图像的数量。

这是一个此类优化的例子。所有这些轮胎仅由一种材质表现,并通过交换其纹理进行配置。

为了减少着色器的数量,可以将2种或更多种简单材质组合为一种较大的材质。如果您打算在这些材质之间切换(例如,您正在制作配置器应用),则此技术特别有效。以这种方式应用可更快地运行,并且还可以进行动画过渡。

绘制调用
此外,还有一个非常重要的方面,绘制调用。绘制调用(DrawCall),是指CPU对图形绘制接口的调用,通过调用图形库(DirectX/OpenGL)接口,命令GPU进行渲染操作。绘制调用的数量是对性能影响的一个重要方面。可以通过 print performance info(打印性能信息) 拼图输出的Geometry Buffer(几何缓存)部分来获取数据。如果每个对象只分配一种材质,则此数据大致对应了单独对象的数量,而多材质对象则需要更多的绘制调用来渲染。
因此,在可能的情况下,应尽量连接网格,并使用较少的独立材质,以减少绘制调用的次数并提高性能。

如果有已设置动画的对象,您仍然可以将各部分结合在一起,并使用骨骼进行动画控制。这有时甚至比为单独的对象设置动画时更为方便。

HDR照明
如果只使用HDR图像而不使用任何光源来照亮场景,亦可以大幅度提高性能。HDR文件的体积有的甚至小于1 Mb。

阴影
只在有助于更好地展现物体时才使用动态阴影。如下图,工业机器人案例中使用的动态阴影强调了机器的模型形状。因为允许旋转模型,所以阴影中的任何细节都会直接显示。另一个案例中,电动滑板车的阴影则会隐藏掉很多细节。

如果对象在应用中不移动,则可以烘焙阴影和环境光遮蔽贴图,并将其置于对象下的平面上。

另请参阅
请查看 性能瓶颈 章节了解如何发现应用中的性能瓶颈,以及 资产压缩 章节,了解如何使场景更加紧凑。
遇到问题?
欢迎您随时在 论坛上提问!您还可以加入中文用户社区QQ群(171678760),在线寻求帮助。