glDrawArrays如何知道要绘制什么?

68

我正在学习一些初级OpenGL教程,对于以下代码片段有点困惑:

glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); //Bind GL_ARRAY_BUFFER to our handle
glEnableVertexAttribArray(0); //?
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); //Information about the array, 3 points for each vertex, using the float type, don't normalize, no stepping, and an offset of 0. I don't know what the first parameter does however, and how does this function know which array to deal with (does it always assume we're talking about GL_ARRAY_BUFFER?

glDrawArrays(GL_POINTS, 0, 1); //Draw the vertices, once again how does this know which vertices to draw? (Does it always use the ones in GL_ARRAY_BUFFER)

glDisableVertexAttribArray(0); //?
glBindBuffer(GL_ARRAY_BUFFER, 0); //Unbind

我不明白glDrawArrays如何知道要绘制哪些顶点,并且glEnableVertexAttribArray与此有什么关系。能否有人对这种情况进行阐述?

3个回答

55

调用glBindBuffer告诉OpenGL在需要GL_ARRAY_BUFFER时使用vertexBufferObject

glEnableVertexAttribArray表示您想让OpenGL使用顶点属性数组;如果没有此调用,您提供的数据将被忽略。

glVertexAttribPointer如您所说,告诉OpenGL如何处理提供的数组数据,因为OpenGL本身不知道该数据的格式。

glDrawArrays使用上述所有数据绘制点。

请记住,OpenGL是一个大型状态机。大多数调用OpenGL函数会修改您无法直接访问的全局状态。这就是为什么代码以glDisableVertexAttribArrayglBindBuffer(...,0)结束:当您完成使用它时,必须将全局状态放回去。


1
好的,最后一个让我困惑的问题是:glDrawArrays如何知道要使用哪个顶点属性。我假设我可以有多个属性,所以我可以这样启用索引1:glEnableVertexAttribArray(1),然后使用glVertexAttribPointer()给它一些属性,但在我的例子中,glDrawArrays如何知道要使用索引0处的属性来解释数据的格式。 - w4etwetewtwet
1
@handuel:它使用所有启用的顶点属性。每个属性的确切含义是通过顶点着色器的编程定义的。 - datenwolf
1
实际上,当调用glDrawArrays后,顶点着色器才开始起作用。glDrawArrays只是将使用glEnableVertexAttribArray启用的每个活动顶点属性的数据传递到绘图队列中。在顶点着色器中,每个顶点属性数组都有一个绑定,着色器确定哪些元素成为屏幕位置、颜色等。 - datenwolf
1
@datenwolf 好的,着色器接收什么数据?只有GL_ARRAY_BUFFER中的数据吗?还是它们可以从其他缓冲区获取数据? - w4etwetewtwet
5
当调用glVertexAttribPointer(attrib_index, …)时,由glBindBuffer(GL_ARRAY_BUFFER, …)绑定的缓冲区将绑定到glVertexAttribPointer第一个参数指定的顶点属性。要将另一个缓冲区绑定到另一个属性,需要执行另一个glBindBuffer(GL_ARRAY_BUFFER, …); glVertexAttribPointer(…);。调用glEnableVertexAttribArray不是使缓冲区和属性之间绑定的必需操作。但启用顶点属性数组使glDraw…调用使用已启用的属性。 - datenwolf
显示剩余3条评论

5

DrawArrays从ARRAY_BUFFER中获取数据。

数据根据您在glVertexAttribPointer中设置的方式“映射”,该方式告诉您的顶点的定义是什么。

在您的例子中,您有一个顶点属性(glEnableVertexAttribArray)在位置0(通常可以有16个顶点属性,每个属性包含4个浮点数)。 然后,您告诉每个属性将通过从位置0开始读取3个GL_FLOATS来获得缓冲区中的数据。


谢谢,这有助于我理解。glEnableVertexAttribArray函数是做什么用的? - w4etwetewtwet
@handuel 更新了答案,请查看来自arcsynthesis.org的教程。 - fen
但是,如果drawArrays从ARRAY_BUFFER中获取数据,那么这是否意味着我不能在着色器中使用来自多个缓冲区的数据? 因为您无法同时将多个缓冲区绑定到ARRAY_BUFFER。另外,发布的链接不再起作用。 - Jerry Lundegaard

1
作为其他答案的补充,以下是一些OpenGL文档的指针。根据维基百科[1],OpenGL的开发已于2016年停止,改用后继API“Vulkan”[2,3]。最新的OpenGL规范是2017年的4.6版,但它只比3.2版多了一些附加内容[1]。
原始问题中的代码片段不需要完整的OpenGL API,而只需要作为OpenGL ES(最初用于嵌入式系统)[4]编码的子集。例如,广泛使用的GUI开发平台Qt使用OpenGL ES 3.X [5]。
OpenGL的维护者是Khronos联盟[1,6]。最新OpenGL发行版的参考资料在[7],但存在一些不一致性(4.6链接到4.5页面)。如有疑问,请使用[8]处的3.2参考资料。
教程集合位于[9]。
  1. https://en.wikipedia.org/wiki/OpenGL
  2. https://en.wikipedia.org/wiki/Vulkan
  3. https://vulkan.org
  4. https://en.wikipedia.org/wiki/OpenGL_ES
  5. 请参阅函数引用中的链接,例如https://doc.qt.io/qt-6/qopenglfunctions.html#glVertexAttribPointer
  6. https://registry.khronos.org
  7. https://www.khronos.org/opengl
  8. https://registry.khronos.org/OpenGL-Refpages/es3
  9. http://www.opengl-tutorial.org

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接