我正在关注basic tutorial on OpenGL 3.0。我不清楚为什么/如果我必须绑定,启用和取消绑定/禁用每个帧的所有顶点缓冲区和纹理。
对我来说似乎有太多的gl ****来电,我猜有些开销。例如here,您会看到每个框架有几个块,如:
// do this for each mesh in scene
// vertexes
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glVertexAttribPointer( 0, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normal_buffer );
glVertexAttribPointer( 1, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// UVs
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, uv_buffer );
glVertexAttribPointer( 2, 2, GL_FLOAT,GL_FALSE,0,(void*)0);
// ...
glDrawArrays(GL_TRIANGLES, 0, nVerts );
// ...
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
想象你不仅有一个而是100个不同的网格,每个网格都有自己的顶点,标准,紫外线的VBO。我是否真的应该为每个人执行这个程序?当然我可以将这种复杂性封装到一些函数/对象中,但我担心这个gl ****函数调用的开销。
此机制的某些部分是否可能从per frame loop
转移到scene setup
?
另外I read VAO是一种如何将一个对象的相应VBO打包在一起的方法。并且绑定VAO会自动绑定相应的VBO。所以我在想,每个网格(不是实例)可能只有一个VAO应该如何完成 - 但根据this answer它似乎不是这样吗?
答案 0 :(得分:0)
您应该使用顶点数组对象(由glGenVertexArrays
生成)。多亏了你,你不必每次都进行这些电话。顶点缓冲区对象存储:
glEnableVertexAttribArray
或glDisableVertexAttribArray
。glVertexAttribPointer
进行顶点属性配置。glVertexAttribPointer
。也许this会是更好的教程。
这样你就可以生成vao对象,然后绑定它,执行调用和取消绑定。现在在绘图循环中你只需要绑定vao。
glUseProgram(shaderId);
glBindVertexArray(vaoId);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0);
答案 1 :(得分:0)
首先要做的事情:通过引入顶点数组对象解决了对GL调用开销的担忧(参见@Criss的回答)。然而,您的思路的真正问题在于,您将VBO与几何网格等同,即为每个几何体提供自己的VBO。
这不是你应该如何看待和使用VBO。 VBO是大块的内存,你可以把几个对象的数据放到一个VBO中;你不必绘制整个东西,你可以限制绘制调用VBO的子集。 和您可以使用相似或甚至相同的绘图设置来合并几何图形,并使用单个绘图调用一次性绘制它们。通过使用正确的顶点索引列表,或通过使用实例化。
说到纹理的绑定状态......好吧,是的,这有点烦人。切换纹理时,你真的必须完成整个绑定舞蹈。这就是为什么通常在绘制之前按纹理/着色器对几何体进行排序,以便最小化纹理切换量。
最后3或4代GPU(截至2016年末)确实支持无绑定纹理,您可以通过64位句柄访问纹理(实际上是某些地址空间)。然而,无绑定纹理尚未成为核心OpenGL标准,您必须使用供应商扩展来使用它。
另一种有趣的方法(由Id Tech 4推广)是虚拟纹理。您可以在其可寻址大小中分配 huge 的稀疏填充纹理对象,但只有部分实际填充了数据。在程序执行期间,您可以确定需要纹理的哪些区域,并根据需要交换所需的数据。