OpenGL 优化网格绘图(VAO?没有索引?)
OpenGL optimize Mesh Drawing (VAO? without indices?)
好的,超时后我继续我的 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 作为下一步。
我建议你的下一步应该是将你的顶点属性变成一个结构而不是单独的数组。这样,您只使用一个数组对象,而 GPU 更喜欢这种内存布局。
除此之外:
是否编入索引在很大程度上取决于您的数据;这不是快速性能的要求,但它可以提供帮助;另一种选择是使用三角形带,这也减少了顶点数据量。如果在单个数组对象中有多个网格,您可以简单地更改顶点属性指针以从数组对象中的不同位置开始,以便绘制不同的网格。那么你就不会在数组对象之间切换太多了。
这些决策中的大部分应该由您的约束和性能测量来驱动!
首先,您应该将使用 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 大),您应该对将数据分成小块感兴趣。将所有这些数据放在一个大数组中可能会导致一些令人讨厌的内存分配和渲染问题(相信我 - 我去过那里;))。
好的,超时后我继续我的 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 作为下一步。
我建议你的下一步应该是将你的顶点属性变成一个结构而不是单独的数组。这样,您只使用一个数组对象,而 GPU 更喜欢这种内存布局。
除此之外:
是否编入索引在很大程度上取决于您的数据;这不是快速性能的要求,但它可以提供帮助;另一种选择是使用三角形带,这也减少了顶点数据量。如果在单个数组对象中有多个网格,您可以简单地更改顶点属性指针以从数组对象中的不同位置开始,以便绘制不同的网格。那么你就不会在数组对象之间切换太多了。
这些决策中的大部分应该由您的约束和性能测量来驱动!
首先,您应该将使用 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 大),您应该对将数据分成小块感兴趣。将所有这些数据放在一个大数组中可能会导致一些令人讨厌的内存分配和渲染问题(相信我 - 我去过那里;))。