在 OpenGL 中加载统一变量是否昂贵?

Is loading uniform variables in OpenGL expensive?

通常我会在绘制网格之前加载所有统一变量(无论是否需要)。例如(在 WebGL 中):

gl.uniformMatrix4fv(program.ModelView, false, ModelView.array);
var MVP = Projection.mult(ModelView);
gl.uniformMatrix4fv(program.ModelViewProjection, false, MVP.array);
var NormalMatrix = ModelView.normal();
gl.uniformMatrix3fv(program.NormalMatrix, false, NormalMatrix);
gl.uniform3fv(program.materalDiffuse, materialDiffuse);
gl.uniform3fv(program.materalAmbient, [1.0, 1.0, 1.0]);
// ...etc...
// ... draw mesh via gl.drawArrays or gl.drawElements

其中一些制服自上次调用 gl.draw(Arrays|Elements) 以来可能没有改变,因此加载它们通常是多余的。我应该担心这个开销吗?

我可以向客户端变量添加一个 dirty 位,并且只加载需要更改的统一变量;例如:

if (ModelView.dirty || Projection.dirty) {
   gl.uniformMatrix4fv(program.ModelView, false, ModelView.array);
   var MVP = Projection.mult(ModelView);
   gl.uniformMatrix4fv(program.ModelViewProjection, false, MVP.array);
   ModelView.dirty = Projection.dirty = false;
}

然后,每当 ModelViewProjection 发生突变时,我都会设置相应的 dirty 位。

尝试限制统一变量加载是否值得?

根据我的经验,与 openGL 相比,webGL 中的统一更新有明显的开销。话虽如此,您仍然可以期望每秒能够进行数千次这些统一更新,并且仍能达到 60 FPS。

实际上,我认为对于大多数应用程序,如果您使用统一作为模型实例化的手段,统一更新只会成为一个问题。那么您可能 运行 由于统一更新开销和所需绘制调用次数的组合而遇到问题。

否则,我不会太担心缓存制服。这样做当然不是一个坏主意,只是不要指望它会成为让你从 30 FPS 升到 60 FPS 的灵丹妙药。