【问题标题】:In WebGL how does an ARRAY_ELEMENT_BUFFER know which ARRAY_BUFFER to reference在 WebGL 中,ARRAY_ELEMENT_BUFFER 如何知道要引用哪个 ARRAY_BUFFER
【发布时间】:2015-10-01 03:38:43
【问题描述】:

我对 ARRAY_INDEX_BUFFER(索引缓冲区)与 ARRAY_BUFFER(数组缓冲区)的用法有点困惑,希望得到澄清/更好的理解。

具体来说,我很困惑(鉴于存在多个数组缓冲区)WebGL 和索引缓冲区如何知道要引用哪个数组缓冲区?*

使用从Mozilla's Creating 3D objects using WebGL Demo获得的代码作为基础,我理解数组缓冲区被分配和初始化为

cubeVerticesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);
var vertices = [
    // Front face
    -1.0, -1.0,  1.0,
     1.0, -1.0,  1.0,
     1.0,  1.0,  1.0,
    -1.0,  1.0,  1.0,

    // Back face
    -1.0, -1.0, -1.0,
    -1.0,  1.0, -1.0,
     1.0,  1.0, -1.0,
     1.0, -1.0, -1.0,

    // Top face
    -1.0,  1.0, -1.0,
    -1.0,  1.0,  1.0,
     1.0,  1.0,  1.0,
     1.0,  1.0, -1.0,

    // Bottom face
    -1.0, -1.0, -1.0,
     1.0, -1.0, -1.0,
     1.0, -1.0,  1.0,
    -1.0, -1.0,  1.0,

    // Right face
     1.0, -1.0, -1.0,
     1.0,  1.0, -1.0,
     1.0,  1.0,  1.0,
     1.0, -1.0,  1.0,

    // Left face
    -1.0, -1.0, -1.0,
    -1.0, -1.0,  1.0,
    -1.0,  1.0,  1.0,
    -1.0,  1.0, -1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

然后索引存储在索引缓冲区中

cubeVerticesIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);  
var cubeVertexIndices = [
    0,  1,  2,      0,  2,  3,    // front
    4,  5,  6,      4,  6,  7,    // back
    8,  9,  10,     8,  10, 11,   // top
   12, 13, 14,     12, 14, 15,   // bottom
   16, 17, 18,     16, 18, 19,   // right
   20, 21, 22,     20, 22, 23    // left
 ]
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);

但假设还有一个颜色数组缓冲区定义为

var colors = [
    1.0,  1.0,  1.0,  1.0,    // Front face: white
    1.0,  0.0,  0.0,  1.0,    // Back face: red
    0.0,  1.0,  0.0,  1.0,    // Top face: green
    0.0,  0.0,  1.0,  1.0,    // Bottom face: blue
    1.0,  1.0,  0.0,  1.0,    // Right face: yellow
    1.0,  0.0,  1.0,  1.0     // Left face: purple
];
var generatedColors = [];
for (j=0; j<6; j++) {
    var c = colors[j];
    for (var i=0; i<4; i++) {
      generatedColors = generatedColors.concat(c);
    }
}

cubeVerticesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(generatedColors), gl.STATIC_DRAW);

但是一旦进入绘图例程,顺序是

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);
gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesColorBuffer);
gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

我假设 bindBuffer 方法告诉 WebGL“状态机”使通用缓冲区“活动”并且 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER根据当前的通用缓冲区激活新的索引缓冲区

不知何故,我认为我对发生的事情的理解并不完全正确。任何澄清将不胜感激。具体来说,我想在某个时候添加具有不同缓冲区的其他对象(例如球体或圆环,具有完全不同的配色方案)

但我理解 drawElements( 只是根据索引绘制而不是 drawArrays(

完成的实际数组

正确吗?

【问题讨论】:

标签: javascript arrays opengl-es buffer webgl


【解决方案1】:

OpenGL 及其变体(WebGL 等)的隐藏诅咒是状态机。当您调用glBindBuffer(GL_ARRAY_BUFFER, buffer) 时,状态机将buffer 设置为活动数组缓冲区。同样,当您调用glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuffer) 时,状态机将indexbuffer 设置为活动元素数组缓冲区(或活动索引缓冲区)。

当调用glVertexAttribPointer 时,给定属性索引的数据来自活动数组缓冲区。这正是您在上一个代码 sn-p 中描述的方式。当你来发出一个绘图调用(例如glDrawElements)时,活动索引缓冲区用于对属性进行索引。

具体来说,我很困惑(鉴于存在多个数组缓冲区)WebGL 和索引缓冲区如何知道要引用哪个数组缓冲区?

要认识到的最重要的一点是,单个顶点不仅仅是它的位置,而是它所有属性的组合。在您的情况下,位置和颜色构成一个顶点。现在,查看您指定的属性:

Position: | pos0   | pos1   | pos2   | pos3   | pos4   | pos5   | pos6   |
Color:    | color0 | color1 | color2 | color3 | color4 | color5 | color6 |

索引缓冲区中的每个索引都引用位置和颜色属性的组合。也就是说,索引 0 将获取 pos0color0;索引 5 将获取 pos5color5

为了回答您的问题,索引缓冲区是指调用glVertexAttribPointer 时已引用的所有数组缓冲区。

(严格来说,索引缓冲区指的是所有启用的属性glVertexAttribPointer 的最后一个参数允许您指定活动数组缓冲区的偏移量,以便可以从相同的数组缓冲区。)

【讨论】:

    【解决方案2】:

    gl.vertexAttribPointer 告诉 webgl 在当前由gl.bindBuffer 绑定的缓冲区中期望什么样的数据。然后在着色器中编程您希望如何使用缓冲区中提供的数据。

    有点像这样。假设在着色器中我想使用 2 个缓冲区 A 和 B,我希望每个顶点有 3 个来自 A 的浮点数和 2 个来自 B 的浮点数。

    gl.bufferData 向 GPU 发送连续浮点数组*,而 GPU 不知道如何解释连续浮点数组。

    所以我需要使用gl.vertexAttribPointer 告诉 GPU 数据是如何格式化的,这基本上就是它的作用。

    但是,webgl/opengl API 的编写方式我不能只做bufferA.vertexAttribPointer(),而是我必须首先使用“gl.bindBuffer”设置一个虚构的全局变量BOUND_BUFFER。然后你可以想象vertexAttribPointer被实现来作用于全局BOUND_BUFFER“实例”并做它需要做的任何事情。

    • float 当然可以是任何有效的 webgl 类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-13
      • 2018-05-05
      • 1970-01-01
      • 2021-10-14
      • 2016-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多