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

C++ OpenGL优化网格绘制(VAO?无索引?),c++,opengl,C++,Opengl,好的,在一段时间后,我继续我关于OpenGL3.2+的研究,现在我对如何优化这样的东西感到困惑: // Verts glBindBuffer(GL_ARRAY_BUFFER, VertBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(VERTEX_COORD_ATTRIB); glVertexAttribPointer(VE

好的,在一段时间后,我继续我关于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

为此,您可以使用VAOs:

//设置缓冲区

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);

如果你想画真正大的网格(它们的大小比你的图形卡上可用的克大),你应该对把数据分成小块感兴趣。将所有这些数据放在一个大数组中可能会导致一些糟糕的内存分配和渲染问题(相信我,我曾经在那里工作过;)。

谢谢,这给了我已经非常有价值的信息,事实上我以前使用过三角形条带:)你确切地说了我的示例中最大的问题是什么,以及我想要消除的部分。我真的非常惊讶它竟然如此简单,它也在某种程度上回答了我的VAO问题——也感谢记忆的暗示,我相信我迟早会达到这一点:)会尝试一下,然后回来报告真的很酷。我应该早一点问路,我想我把这件事看得比实际情况更复杂。想知道为什么每个教程都必须将其绑定到索引图形,而不提及如此简单的设置。非常感谢。