gl.drawElements如何“找到”相应的顶点数组缓冲区?

时间:2017-11-10 23:28:09

标签: javascript drawing webgl

并提前感谢你。

我是Webgl的新手,我不太了解drawElements方法和我想绘制的当前顶点缓冲区之间的联系。 我近似理解drawArray方法发生了什么(例如创建缓冲区,将其绑定到上下文,用数据填充它,指向相应的属性,绘制它)。但是当我尝试使用索引数组和较少的顶点数据时,我会遇到这种类型的错误:

[.Offscreen-For-WebGL-0x7fae2b940800]GL ERROR :GL_INVALID_OPERATION : glDrawElements: bound to target 0x8893 : no buffer

也许我的代码暗示可以帮到你。

    const cube = new Program(renderer.gl, vertex3d, fragment); // my webgl program
    const cubeData = new Cube(); // Only array of vertices/indices
    const cubeVertexPosition = new ArrayBuffer(renderer.gl, cubeData.vertices, 'STATIC_DRAW'); // ARRAY_BUFFER
    const cubeVertexIndices = new IndexBuffer(renderer.gl, renderer.gl.UNSIGNED_SHORT, cubeData.indices, 'STATIC_DRAW'); // ELEMENT_ARRAY_BUFFER
cubeVertexPosition.attribute('aPosition', 3, 'FLOAT', false); // define attribute corresponding in vertex shader
    cubeVertexPosition.attributePointer(cube); // enableVertexAttribArray + vertexAttribPointer
    [...]
    cubeVertexIndices.draw('TRIANGLES', 0, 36); // drawElements with gl.UNSIGNED_SHORT type

我成功用drawArray绘制它:)

([...]只是制服的矩阵转换);

也许你有一个快速的提示,可以帮助我理解这个黑魔法,

非常感谢!

2 个答案:

答案 0 :(得分:1)

drawArray仅使用ARRAY_BUFFER参数的first参数中的一个或多个count来自顶点的位置,以便它们位于缓冲区中。

drawElements使用一个或多个ARRAY_BUFFER AND 一个ELEMENT_ARRAY_BUFFER,其中包含指向要绘制的ARRAY_BUFFER个顶点的索引。在drawElements中,count参数指定要在ELEMENT_ARRAY_BUFFER中读取的索引计数,而offset指定以字节为单位的偏移量,以便开始读取ELEMENT_ARRAY_BUFFER }(usualy FirstIndex*sizeof(type)其中type可以是UNSIGNED_BYTE(1个字节),UNSIGNED_SHORT(2个字节)或UNSIGNED_INT(4个字节)。

ELEMENT_ARRAY_BUFFER

[0][1][2][1][2][0][1][2][3][3][1][2][3][4][5][...

ARRAY_BUFFER

|   0   |   1    |    2   |    3   |    4   | ...
[x][y][z][x][y][z][x][y][z][x][y][z][x][y][z][...

要正常工作,offset + count*sizeof(type)不应大于字节中的ELEMENT_ARRAY_BUFFER大小。此外,ELEMENT_ARRAY_BUFFER中的元素索引应小于ARRAY_BUFFER中包含的顶点数。

drawArray类似,drawElements将当前绑定的缓冲区(配置了属性指针)作为数据源。与drawElements的区别在于您必须使用ELEMENT_ARRAY_BUFFER目标指定一个附加元素(索引)缓冲区,如下所示:

gl.bindBuffer(gl.ARRAY_BUFFER, myVerticesA);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, myIndicesA);
// configure attributes pointers here
gl.drawElements(gl.TRIANGLES, 12345, gl.UNSIGNED_SHORT, 0);

“how”drawElements将根据ARRAY_BUFFER中存储的索引获取ELEMENT_ARRAY_BUFFER缓冲区中的属性,具体取决于您如何配置属性指针。

假设以下顶点缓冲区具有交错位置,法线和纹理坐标:

|    p0    ||    n0    ||  t0  ||    p1    ||    n1    ||  t1  |
[px][py][pz][nx][ny][nz][tu][tv][px][py][pz][nx][ny][nz][tu][tv][...

我们将属性指针定义如下:

let stride = 8*4;  // 8*float (8 * 4 bytes)
let offp = 0;   // positions at beginning
let offn = 3*4; // normals after 3*float position.
let offt = 6*4; // tex coords after 3*float position + 3*float normal 
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, stride, offp);
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, stride, offn);
gl.vertexAttribPointer(2, 2, gl.FLOAT, false, stride, offt);

使用元素(索引)缓冲区,GL将根据存储在ELEMENT_ARRAY_BUFFER缓冲区中的索引简单地移位指针位置:

 // pseudo-code
 for(let i = start_elem; i < start_elem+count_elem; i++) {

   let index = ELEMENT_ARRAY_BUFFER[i];

   attrib[0] = ARRAY_BUFFER[(index*stride)+offp];
   attrib[1] = ARRAY_BUFFER[(index*stride)+offn];
   attrib[2] = ARRAY_BUFFER[(index*stride)+offt];

 }

答案 1 :(得分:0)

您发布的代码不是WebGL。您正在使用一些从代码中清楚的库。 ProgramIndexBufferArrayBuffer等内容都是您正在使用的某些库的一部分。该库的工作方式取决于该库。

一般来说,WebGL有着色器,顶点着色器的作用是将gl_Position设置为每个顶点的剪辑空间坐标,而片段着色器的作用是将gl_FragColor设置为颜色为每个像素。

顶点着色器通常从属性获取有关位置的数据。属性通常从缓冲区获取数据。通过首先使用ARRAY_BUFFER将缓冲区绑定到gl.bindBuffer(gl.ARRAY_BUFFER, someBuffer)绑定点,然后调用gl.vertexAttribPointer告诉WebGL如何从中获取数据,告诉属性从哪个缓冲区获取数据缓冲区(数据的类型,每个顶点有多少个值,顶点之间要跳过多少个字节,缓冲区要启动多远)。 gl.vertexAttribPointer保存给定属性的所有信息以及对绑定到ARRAY_BUFFER绑定点的当前缓冲区的引用,以便您可以自由地绑定不同的缓冲区以设置另一个属性。

当您调用gl.drawArrays时,数据将从您指定的缓冲区中的缓冲区中拉出,为着色器的每次迭代设置一组值

对于gl.drawElements,它需要一个缓冲区,绑定到ELEMENT_ARRAY_BUFFER,当你cll gl.drawElements时,你告诉它缓冲区中的数据类型(gl.UNSIGNED_BYTE或{ {1}})。然后,它使用该缓冲区的值从属性缓冲区中提取值。

如果在缓冲区中放入一个简单的增加值,

gl.UNSIGNED_SHORTgl.drawElements完全相同。实施例

gl.drawArrays

实际上与

相同
 const offset  = 0;
 const numVerts = 100;

 // process 100 vertices from the buffers pointed to by the attributes
 // in order 0 to 99
 gl.drawArrays(gl.POINTS, offset, numVerts)

但当然,因为在第二种情况下你提供了indexData,所以它不必是连续的。

我建议阅读其他一些webgl tutorials