并提前感谢你。
我是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绘制它:)
([...]只是制服的矩阵转换);
也许你有一个快速的提示,可以帮助我理解这个黑魔法,
非常感谢!
答案 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。您正在使用一些从代码中清楚的库。 Program
,IndexBuffer
,ArrayBuffer
等内容都是您正在使用的某些库的一部分。该库的工作方式取决于该库。
一般来说,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_SHORT
与gl.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