在 WebGL 2 中更新统一缓冲区数据?

Updating Uniform Buffer Data in WebGL 2?

不同于OpenGL ES 3,没有gl.mapBufferRange gl.bufferSubData(它存在),WebGL中更新统一缓冲区数据的有效方法是什么2? 例如,一个 PerDraw Uniform 块

uniform PerDraw
{
    mat4 P;
    mat4 MV;
    mat3 MNormal;
} u_perDraw;

gl.bufferSubData 存在,所以看起来您创建了一个缓冲区,然后创建了一个并行类型数组。更新 typedArray 并调用 gl.bufferSubData 将其复制到缓冲区中进行更新,gl.bindBufferRange 使用它。

可能还是很快的。首先,所有值操作都保留在 JavaScript 中,因此调用 WebGL 的开销更少。如果你有 10 件制服要更新,这意味着你对 WebGL 进行了 2 次调用,而不是 10 次。

TWGL.js 中,我将所有 uniform 的 ArrayBufferViews 生成到一个单一类型的数组中,因此例如给定上面的 uniform 块,你可以这样做

ubo.MV[12] = tx;
ubo.MV[13] = ty;
ubo.MV[14] = tz;

或者作为另一个例子,如果你有一个数学库将 array/typedarray 作为目标参数,你可以做类似

的事情
var dest = ubo.P;
m4.perspective(fov, aspect, zNear, zFar, dest);

我遇到的一个问题是处理统一优化。如果我编辑一个着色器,假设我正在调试,我只是在片段着色器的顶部插入 output = vec4(1,0,0,1); return; 并且一些统一块得到优化,代码将被破坏。我不知道在 C/C++ 项目中处理这个问题的标准方法是什么。我想在 C++ 中你会声明一个结构

struct PerDraw {
  float P[16];
  float MV[16];
  float MNormal[9];
}

这样问题就解决了。在 twgl.js 中,我在运行时有效地生成了该结构,这意味着如果您的代码期望它存在但它没有生成,因为它已经过优化,那么代码中断。

在 twgl 中,我创建了一个从 JavaScript 对象复制到类型化数组的函数,这样我就可以跳过任何优化的统一块,不幸的是,这会增加一些开销。您可以直接修改类型数组视图并在调试时处理破损或使用结构化复制功能(twgl.setBlockUniforms)。

也许我应该让你在 twgl 中指定一个来自 JavaScript 的结构并生成它,让它与统一块对象匹配由你决定。这将使它更像 C++,删除一个副本,并且在调试优化删除块时更容易处理。