上传统一块的正确顺序是什么?

What is the correct sequence for uploading a uniform block?

https://www.lighthouse3d.com/tutorials/glsl-tutorial/uniform-blocks/ 的示例页面中有这个:

  1. uniformBlockBinding()
  2. bindBuffer()
  3. 缓冲区数据()
  4. bindBufferBase()

但从概念上讲,这不是更正确吗?

  1. bindBuffer()
  2. 缓冲区数据()
  3. uniformBlockBinding()
  4. bindBufferBase()

想法是上传到缓冲区 (bindBuffer+bufferData) 应该不知道缓冲区将用于什么 - 然后,分别使用 uniformBlockBinding()+bindBufferBase() 来更新这些制服,每个着色器,相关缓冲区何时更改?

两者都不 "more correct";他们都工作。但是如果你在谈论关注点分离,第一个更好地强调正确的分离。

glUniformBlockBinding修改程序;它不会影响缓冲区对象或上下文缓冲区状态的性质。实际上,按所有权利,该调用甚至不应该在同一个 function 中;它是程序对象设置的一部分。在现代 GL 教程中,他们会使用 layout(binding=X) to set the binding,因此该函数甚至不会出现。对于较旧的代码,应在创建程序后将其设置为 已知 常量值,然后保持不变。

因此在为缓冲区分配存储空间和将其绑定到索引绑定点以供使用之间调用函数会造成他们应该在每一帧调用 glUniformBlockBinding 的印象,这是错误的印象。

而且说到错误印象,glBindBufferBase 甚至不应该在那里被调用。该代码的其余部分是缓冲区设置代码;它应该只在申请开始时进行一次。 glBindBufferBase 应该作为渲染过程的一部分调用,而不是设置过程。在一个好的应用程序中,该调用不应靠近 glGenBuffers 调用。

添加答案,因为接受的答案有很多与 WebGL2 无关的信息

在初始时间你调用 uniformBlockBinding。对于给定的程序,它设置特定程序将从哪个统一缓冲区索引绑定点获得特定的统一缓冲区。

在渲染时调用 bindBufferRangebindBufferBase 将特定缓冲区绑定到特定的统一缓冲区索引绑定点

如果您还需要将新数据上传到该缓冲区,您可以调用 bufferData

在伪代码中

// at init time

for each uniform block
   gl.uniformBlockBinding(program, indexOfBlock, indexOfBindPoint)

// at render time

for each uniform block
   gl.bindBufferRange(gl.UNIFORM_BUFFER, indexOfBindPoint, buffer, offset, size)
   if (need to update data in buffer)
      gl.bufferData/gl.bufferSubData(gl.UNIFORM_BUFFER, data, ...)

请注意,没有“正确”的顺序。这里的问题是如何更新缓冲区完全取决于您。由于您可能将多个统一缓冲区数据存储在不同偏移量的单个缓冲区中,因此像上面那样调用 gl.bufferData/gl.bufferSubData 实际上是不“正确”的,它只是 100s 的一种方式。

WebGL2 (GLES 3.0 ES) 不支持已接受答案中提到的 layout(binding = x)。 WebGL2

中也没有glGenBuffers这样的东西