OpenGL优化网格绘制(VAO?无索引?)

OpenGL optimize Mesh Drawing (VAO? without indices?)

本文关键字:索引 VAO 优化 网格 绘制 OpenGL      更新时间:2023-10-16

好的,在一段时间后,我正在继续我对OpenGL3.2+的研究,现在我对如何优化这样的东西感到困惑:

// Verts
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(VERTEX_COORD_ATTRIB);
glVertexAttribPointer(VERTEX_COORD_ATTRIB,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);
// Textures
glBindBuffer(GL_ARRAY_BUFFER, TexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * texsize, tex, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(TEXTURE_COORD_ATTRIB);
glVertexAttribPointer(TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, sizeof(float) * TexCoords2D, 0);
//add light color info
glBindBuffer(GL_ARRAY_BUFFER, ColorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * colorsize, lightcolor, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(COLOR_ATTRIB);
glVertexAttribPointer(COLOR_ATTRIB, 4, GL_FLOAT, GL_FALSE, sizeof(float) * ColorInfo, 0);
// Draw
glDrawArrays(GL_TRIANGLES, 0, size);
// Clean up
glDisableVertexAttribArray(VERTEX_COORD_ATTRIB);
glDisableVertexAttribArray(TEXTURE_COORD_ATTRIB);
glDisableVertexAttribArray(COLOR_ATTRIB);

假设这是为几个网格完成的,目前每个网格总是像这样被推动、绑定、缓冲和绘制。需要说的是,这肯定不是一种有效的方法。

现在,当阅读(许多)教程时,我总是看到的一件事是,建议使用VAO来改进这一点,现在我很难理解的是——每一个教程似乎都与索引图形有关。虽然在使用一个非常简单的例子(如2个四边形)时,这种方法似乎非常好,但我现在想知道如何为真正复杂的网格创建索引?或者只是假设这是可用的(由于.obj文件或其他原因)。此外,我还困惑于VAO是否总是需要索引,或者可以在没有索引的情况下使用它?如果是这样的话,既然我读到优化利用了知道索引,那么在没有索引的情况下它是否有意义?你看,这里还有很多困惑,我意识到这可能又是一个愚蠢的问题:)

然而,我最终想要实现的是,不是像这样推动每个网格,而是在图形卡的内存中缓冲每个网格一次,然后从缓冲区重新绘制。我还不知道VAO是否是正确的方法,但我读到的每一篇教程似乎都将VAO作为下一步。

首先,您应该将使用glBufferData()的GRAM写入与使用glDrawArrays()的绘图调用分开。这会显著降低性能,因为在每次图形调用时,基本上将数据从RAM复制到GRAM。

为此,您可以使用VAO:

//设置缓冲区

glBindVertexArray(VertexArrayIndex);
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(VERTEX_COORD_ATTRIB);
glVertexAttribPointer(VERTEX_COORD_ATTRIB,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);
// Textures
glBindBuffer(GL_ARRAY_BUFFER, TexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * texsize, tex, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(TEXTURE_COORD_ATTRIB);
glVertexAttribPointer(TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, sizeof(float) * TexCoords2D, 0);
//add light color info
glBindBuffer(GL_ARRAY_BUFFER, ColorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * colorsize, lightcolor, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(COLOR_ATTRIB);
glVertexAttribPointer(COLOR_ATTRIB, 4, GL_FLOAT, GL_FALSE, sizeof(float) * ColorInfo, 0);
glBindVertexArray(0);

//您的绘图调用

glBindVertexArray(VertexArrayIndex);
 glDrawArrays(GL_TRIANGLES, 0, size);
glBindVertexArray(0);

如果你想画真正大的网格(它们的大小比你的显卡上的GRAM大),你应该把数据分成小块。将所有数据放在一个大数组中可能会导致一些令人讨厌的内存分配和渲染问题(相信我,我已经做到了;)。

我建议您的下一步应该是将顶点atrributes变成一个结构,而不是单独的数组。这样,您只使用一个数组对象,而GPU更喜欢这种内存布局。

除此之外:

是否索引在很大程度上取决于您的数据;这不是对快速性能的要求,但它会有所帮助;另一种选择是使用三角形条带,这也减少了顶点数据的数量。如果在单个数组对象中有多个网格,则可以简单地更改顶点属性指针,使其从数组对象中的不同位置开始,以便绘制不同的网格。这样就不会在数组对象之间切换太多了。

这些决策中的大多数应该由您的约束和性能衡量来驱动!