如何将gl.drawElements"find"对应的顶点数组缓冲?
How gl.drawElements "find" the corresponding vertices array buffer?
提前谢谢你。
我是 Webgl 的新手,我不太了解 drawElements 方法和我要绘制的当前顶点缓冲区之间的 link。
我大致了解 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 绘制成功了:)
([...] 只是制服的矩阵变换);
也许你有一个快速提示可以帮助我理解这个黑魔法,
非常感谢!
drawArray
仅使用一个或多个 ARRAY_BUFFER
从顶点按它们在缓冲区中的顺序绘制的位置,从 first
参数到 count
参数。
drawElements
使用一个或多个 ARRAY_BUFFER
AND 一个 ELEMENT_ARRAY_BUFFER
包含指向要绘制的 ARRAY_BUFFER
顶点的索引.在 drawElements
中,count
参数指定要在 ELEMENT_ARRAY_BUFFER
中读取的索引计数,而 offset
指定开始读取 [=22= 的字节偏移量](通常 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
将根据存储在 ELEMENT_ARRAY_BUFFER
中的索引获取 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];
}
您发布的代码不是 WebGL。您正在使用一些从代码中可以清楚地看出的库。 Program
、IndexBuffer
、ArrayBuffer
之类的内容都是您正在使用的某些库的一部分。该图书馆如何做事取决于该图书馆。
一般来说,WebGL 有着色器,一个顶点着色器,它的工作是将 gl_Position
设置为每个顶点的剪辑 space 坐标和一个片段着色器,它的工作是设置 [=16] =] 到每个像素的颜色。
顶点着色器通常从属性中获取有关位置的数据。属性通常从缓冲区获取数据。您通过首先使用 gl.bindBuffer(gl.ARRAY_BUFFER, someBuffer)
将缓冲区绑定到 ARRAY_BUFFER
绑定点然后调用 gl.vertexAttribPointer
告诉 WebGL 您希望如何从中获取数据来告诉属性从哪个缓冲区获取数据缓冲区(数据是什么类型,每个顶点有多少个值,顶点之间要跳过多少字节,缓冲区从多远开始)。 gl.vertexAttribPointer
保存给定属性的所有信息以及对绑定到 ARRAY_BUFFER
绑定点的当前缓冲区的引用,因此您可以在那里自由绑定不同的缓冲区以设置另一个属性。
当您调用 gl.drawArrays
时,数据将从您指定的缓冲区中提取到着色器的属性中,着色器的每次迭代都有一组值
至于 gl.drawElements
它需要一个缓冲区,绑定到 ELEMENT_ARRAY_BUFFER
并且当你 cll gl.drawElements
你告诉它缓冲区中的数据类型(gl.UNSIGNED_BYTE
或 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)
实际上与
相同
// fill a buffer with numbers 0 to 99 (0 to numVerts)
const numVerts = 100;
const indexData = new Uint16Array(numVerts);
for (let i = 0; i < numVerts; ++i) {
indexData[i] = i;
}
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexData, gl.STATIC_DRAW);
// process 100 vertices from the buffers pointed to by the attributes
// in order 0 to 99
const offset = 0;
gl.drawElements(gl.POINTS, numVerts, gl.UNSIGNED_SHORT, offset);
但当然,因为在第二种情况下您提供了 indexData,所以它不必是连续的。
我建议阅读其他一些 webgl tutorials
提前谢谢你。
我是 Webgl 的新手,我不太了解 drawElements 方法和我要绘制的当前顶点缓冲区之间的 link。 我大致了解 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 绘制成功了:)
([...] 只是制服的矩阵变换);
也许你有一个快速提示可以帮助我理解这个黑魔法,
非常感谢!
drawArray
仅使用一个或多个 ARRAY_BUFFER
从顶点按它们在缓冲区中的顺序绘制的位置,从 first
参数到 count
参数。
drawElements
使用一个或多个 ARRAY_BUFFER
AND 一个 ELEMENT_ARRAY_BUFFER
包含指向要绘制的 ARRAY_BUFFER
顶点的索引.在 drawElements
中,count
参数指定要在 ELEMENT_ARRAY_BUFFER
中读取的索引计数,而 offset
指定开始读取 [=22= 的字节偏移量](通常 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
将根据存储在 ELEMENT_ARRAY_BUFFER
中的索引获取 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];
}
您发布的代码不是 WebGL。您正在使用一些从代码中可以清楚地看出的库。 Program
、IndexBuffer
、ArrayBuffer
之类的内容都是您正在使用的某些库的一部分。该图书馆如何做事取决于该图书馆。
一般来说,WebGL 有着色器,一个顶点着色器,它的工作是将 gl_Position
设置为每个顶点的剪辑 space 坐标和一个片段着色器,它的工作是设置 [=16] =] 到每个像素的颜色。
顶点着色器通常从属性中获取有关位置的数据。属性通常从缓冲区获取数据。您通过首先使用 gl.bindBuffer(gl.ARRAY_BUFFER, someBuffer)
将缓冲区绑定到 ARRAY_BUFFER
绑定点然后调用 gl.vertexAttribPointer
告诉 WebGL 您希望如何从中获取数据来告诉属性从哪个缓冲区获取数据缓冲区(数据是什么类型,每个顶点有多少个值,顶点之间要跳过多少字节,缓冲区从多远开始)。 gl.vertexAttribPointer
保存给定属性的所有信息以及对绑定到 ARRAY_BUFFER
绑定点的当前缓冲区的引用,因此您可以在那里自由绑定不同的缓冲区以设置另一个属性。
当您调用 gl.drawArrays
时,数据将从您指定的缓冲区中提取到着色器的属性中,着色器的每次迭代都有一组值
至于 gl.drawElements
它需要一个缓冲区,绑定到 ELEMENT_ARRAY_BUFFER
并且当你 cll gl.drawElements
你告诉它缓冲区中的数据类型(gl.UNSIGNED_BYTE
或 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)
实际上与
相同 // fill a buffer with numbers 0 to 99 (0 to numVerts)
const numVerts = 100;
const indexData = new Uint16Array(numVerts);
for (let i = 0; i < numVerts; ++i) {
indexData[i] = i;
}
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexData, gl.STATIC_DRAW);
// process 100 vertices from the buffers pointed to by the attributes
// in order 0 to 99
const offset = 0;
gl.drawElements(gl.POINTS, numVerts, gl.UNSIGNED_SHORT, offset);
但当然,因为在第二种情况下您提供了 indexData,所以它不必是连续的。
我建议阅读其他一些 webgl tutorials