什么时候释放顶点数组对象?

When to release a Vertex Array Object?

释放顶点数组对象的准则是什么,例如绑定到 null?

有趣的是,我似乎可以拥有 similar 着色器,我只需要在一些分组后释放...或者是在每个分组着色器之后执行此操作的最佳实践?

我想还有另一种可能在每次绘制调用之后都这样做,即使它们是由着色器批处理的,但我认为没有必要...

不清楚你在问什么。 "When to release a texture"。你什么时候用完?我认为你的意思是 "unbind" 而不是 "release"。 "release" 在大多数编程中意味着从内存中删除或至少允许从内存中删除。

假设您的意思是何时取消绑定顶点数组对象 (VAO),事实是您永远不必取消绑定 VAO。

如其他解释,其中 VAO 包含所有属性状态和 ELEMENT_ARRAY_BUFFER 绑定所以

currentVAO = {
  elementArrayBuffer: someIndexBuffer,
  attributes: [
    { enabled: true, size: 3, type: gl.FLOAT, stride: 0, offset: 0, buffer: someBuffer, },
    { enabled: true, size: 3, type: gl.FLOAT, stride: 0, offset: 0, buffer: someBuffer, },
    { enabled: true, size: 3, type: gl.FLOAT, stride: 0, offset: 0, buffer: someBuffer, },
    { enabled: false, size: 3, type: gl.FLOAT, stride: 0, offset: 0, buffer: null, },
    { enabled: false, size: 3, type: gl.FLOAT, stride: 0, offset: 0, buffer: null, },
    { enabled: false, size: 3, type: gl.FLOAT, stride: 0, offset: 0, buffer: null, },
    ...
    ... up to MAX_VERTEX_ATTRIBS ...
  ]
};

只要你记得 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, someBuffer) 影响当前 VAO 内的状态,而不是像 gl.bindBuffer(gl.ARRAY_BUFFER) 这样的全局状态。

我认为这是最令人困惑的部分。大多数 WebGL 方法使受影响的内容变得更清楚 gl.bufferXXX 影响缓冲区,gl.texXXX 影响纹理。 gl.renderbufferXXX 渲染缓冲区,gl.framebufferXX 帧缓冲区,gl.vertexXXX 影响顶点属性(VAO)。等等。但是 gl.bindBuffer 至少在这种情况下是不同的,它在绑定到 ARRAY_BUFFER 时影响全局状态,但在绑定到 ELEMENT_ARRAY_BUFFER 时影响 VAO 状态。

我的建议是在初始化期间按以下顺序执行这些步骤

for each object
  1. create VAO
  2. create vertex buffers and fill with data
  3. setup all attributes
  4. create index buffers (ELEMENT_ARRAY_BUFFER) and fill with data

在渲染时

for each object
  1. use program (if program is different)
  2. bind VAO for object (if different)
  3. set uniforms and bind textures
  4. draw

重要的是要记住,如果您调用 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ...) 您会影响当前的 VAO。

我为什么要绑定 null VAO?主要是因为我经常忘记上面的段落,因为在 VAOs ELEMENT_ARRAY_BUFFER 之前是全局状态。因此,当我忘记这一点并随机绑定一些 ELEMENT_ARRAY_BUFFER 以便我可以在其中放置一些索引时,我刚刚更改了当前 VAO 中的 ELEMENT_ARRAY_BUFFER 绑定。可能不是我想做的事。通过绑定 null,比如在初始化所有对象和渲染循环之后,我不太可能导致该错误。

另请注意,如果我确实想更新某些几何图形的索引,这意味着我想调用 gl.bufferDatagl.bufferSubData 我可以确定我正在影响 2 之一中的正确缓冲区方法。一种方法是将该缓冲区绑定到 ELEMENT_ARRAY_BUFFER,然后调用 gl.bufferData。另一个通过绑定适当的 VAO。

如果这没有意义,那么假设我有 3 个 VAO

 // pseudo code
forEach([sphere, cube, torus])
  create vao
  create buffers and fill with data
  create indices (ELEMENT_ARRAY_BUFFER)
  fill out attributes

现在我有 3 个形状,假设我想更改球体中的索引。我可以通过两种方式做到这一点

一,我可以直接绑定球体的ELEMENT_ARRAY_BUFFER

 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereElementArrayBuffer)
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER...);  // update the indices

这有一个问题,如果绑定了其他一些 VAO,我只是将其更改为 ELEMENT_ARRAY_BUFFER 绑定

第二,我可以绑定球体的 VAO,因为它已经绑定了 ELEMENT_ARRAY_BUFFER

 gl.bindVertexArray(sphereVAO);
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, ...);  // update the indices

在我看来,这似乎更安全。

重申一下,ELEMENT_ARRAY_BUFFER 绑定是 VAO 状态的一部分。