如何使用OpenGL 3.x VBO渲染动态世界?

虽然OpenGL 3.x本身似乎很少有最新的参考,但OpenGL的实际低级操作相对简单。 然而,我在试图甚至概念化如何操纵VBO以呈现动态世界时遇到了严重的麻烦。

显然,旧的直接模式方式是不适用的,但从那里我去哪里? 我是否编写某种场景结构,然后将其转换为一组顶点并将其传输到VBO,我将如何存储翻译数据? 如果是这样,那么代码看起来会如何?

基本上真的不确定如何继续。

如果您的整个世界都是真正的动态,您可以使用GL_STREAM_DRAW_ARB用法标志并重置每个帧上的数据。 不要费心操纵它,只是尝试尽可能高效地流动。

但是,我假设您有一个由多个相对于彼此移动的刚性对象组成的场景。 在这种情况下,为每个对象使用一个VBO并指定GL_STATIC_DRAW_ARB用法标志。 然后,您可以为对象的每个实例设置模型视图变换,并使用每个实例的一次绘制调用来渲染它们。

经验法则(在PC上)是每CPU的CPU发出不超过一次的绘图调用。 这是一个粗略的估计,但它有一些道理。 如果您保持低于此限制,请不要担心将多个独立对象放入单个VBO或其他性能技巧。

简短回答:

使用glMapBufferRange只更新需要修改的子范围。

答案很长:

诀窍是用glMapBufferRange映射已经存在的缓冲区,然后只映射你需要的范围。 鉴于这些假设:

  • 您的几何体使用每顶点动画变形
  • 模型的顶点数在动画期间是不变的。

然后你可以使用glMapBufferRange只更新变化的部分,并保留其余的数据。 使用glBufferData的完整上传作为乌龟很慢,因为它们删除旧的内存存储并分配一个新的内存存储。 这是上传新数据的补充。 glMapBufferRange只允许您读/写现有数据,它不进行分配或释放。

但是,如果使用骨架动画,而是将顶点变换作为每顶点4×4矩阵传递到顶点着色器,并在那里进行计算。 每个顶点数据当然是用glVertexAttribPointer指定的。

另外,请记住,您可以在顶点着色器中读取纹理数据,并且OpenGL 3.1引入了一些新的实例绘制调用; glDrawArraysInstancedglDrawElementsInstanced 。 这些组合可用于特定于实例的查找。 也就是说,您可以使用相同的几何数据绑定来实例绘制调用,但是发送位置或您需要的每个顶点数据作为纹理或纹理数组。 这可以避免混合和匹配不同的顶点数组数据。

想象一下,如果您想要渲染相同模型的100个实例,但具有不同的位置或颜色方案。 甚至纹理贴图。

使用VBO并不意味着您只需要使用单个绘制调用来渲染整个场景。 您仍然可以发出多个绘制调用,并在此过程中设置不同的转换矩阵。

例如,如果您使用的是场景图,则场景图中的每个模型都可以对应一个绘图调用。 在这种情况下,使用VBO的最简单方法是为每个模型创建一个单独的VBO。

作为优化,您可以将多个模型组合到一个VBO中,然后在进行绘制调用时传递非零偏移; 这从VBO中剔除了正确的模型。 将多个绘制调用组合到一个绘制调用中也是可取的,但如果它们需要独立的变换则不可能。 (实际上,如果你使用实例化或顶点混合,在某些情况下可能的,但我建议首先将基础知识放在首位。)