WebGL - 我什么时候应该调用bindBuffer和vertexAttribPointer?

时间:2017-09-27 05:39:46

标签: performance optimization webgl vertex-buffer

此问题特定于WebGL,并假设VAO不可用。

我试图通过限制低级别状态更改的数量来对3D引擎进行一些改进。但事实证明我对使用bindBuffervertexAttribPointer的正确方法感到困惑。

假设我想绘制2个对象:

  • 第一个对象使用两个缓冲区 A C ,带有元素缓冲区 E ;
  • 第二个对象使用缓冲区 B C ,使用相同的元素缓冲区 E

缓冲区 A B 使用相同的布局,并且都由位置0引用,而 C 由位置1引用。

最初,ARRAY_BUFFER_BINDING指向null,而ELEMENT_ARRAY_BUFFER_BINDING指向 E

冗余检查器输出以下内容( A B C E )=(3 ,6,5,2):

WebGL Inspector trace

这意味着:

  1. bindBuffer(ELEMENT_ARRAY_BUFFER, [Buffer 2])是不必要的
  2. vertexAttribPointer(1, 2, FLOAT, false, 0, 0)可以避免
  3. 由于WebGL可以直接阅读ELEMENT_ARRAY_BUFFER_BINDING以了解索引的存储位置,1。对我来说很有意义。

    然而,2。暗示缓冲区布局存储在内部 VBO中,这是错误的,因为看不到缓冲区 A B 在第15和30行是多余的。(已经渲染了几个帧,因此它们应该保持其状态)

    我认为我对drawElements如何知道使用什么缓冲区何时/何时存储缓冲区布局感到困惑。

    此示例案例中bindBuffervertexAttribPointer的最佳用途是什么?为什么?

1 个答案:

答案 0 :(得分:0)

实际上,我想通过简单地查看redundancy checker的来源就可以找到答案。

有两件重要的事情要知道:

  • 缓冲区布局绑定每个位置,而不是每个VBO。
  • vertexAttribPointer将当前缓冲区分配给指定位置

在内部,WebGL每个位置保留6个参数:

VERTEX_ATTRIB_ARRAY_SIZE_X
VERTEX_ATTRIB_ARRAY_TYPE_X
VERTEX_ATTRIB_ARRAY_NORMALIZED_X
VERTEX_ATTRIB_ARRAY_STRIDE_X
VERTEX_ATTRIB_ARRAY_POINTER_X
VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_X

以下是vertexAttribPointer的作用:

function vertexAttribPointer(indx, size, type, normalized, stride, offset) {
    this.stateCache["VERTEX_ATTRIB_ARRAY_SIZE_" + indx] = size;
    this.stateCache["VERTEX_ATTRIB_ARRAY_TYPE_" + indx] = type;
    this.stateCache["VERTEX_ATTRIB_ARRAY_NORMALIZED_" + indx] = normalized;
    this.stateCache["VERTEX_ATTRIB_ARRAY_STRIDE_" + indx] = stride;
    this.stateCache["VERTEX_ATTRIB_ARRAY_POINTER_" + indx] = offset;
    this.stateCache["VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_" + indx] = this.stateCache["ARRAY_BUFFER_BINDING"];
}

最后,WebGL Inspector是真的!状态更改第15行和第30行是必要的,因为VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_0正在发生变化。

这是最佳追踪:

bindBuffer(ARRAY_BUFFER, A)
vertexAttribPointer(0, 3, FLOAT, false, 0, 0)
drawElements(TRIANGLES, 768, UNSIGNED_BYTE, 0)
bindBuffer(ARRAY_BUFFER, B)
vertexAttribPointer(0, 3, FLOAT, false, 0, 0)
drawElements(TRIANGLES, 768, UNSIGNED_BYTE, 0)

(不再需要bindBuffer(ARRAY_BUFFER, C),因为我们没有对它做任何事情。)