9

尽管 OpenGL 3.x 本身的最新参考资料似乎很少,但 OpenGL 的实际低级操作相对简单。但是,我在尝试将如何操纵 VBO 以呈现动态世界的概念化时遇到了严重的麻烦。

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

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

4

3 回答 3

9

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

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

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

于 2009-11-13T15:27:03.860 回答
9

简短的回答:

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

长答案:

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

  • 您的几何图形使用逐顶点动画变形
  • 模型的顶点数在动画期间是恒定的。

然后您可以使用glMapBufferRange仅更新变化的部分,而保留其余数据。使用glBufferData的完整上传速度像乌龟一样慢,因为它们会删除旧的内存存储并分配一个新的存储。除了上传新数据之外。glMapBufferRange仅允许您读取/写入现有数据,它不会分配或释放。

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

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

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

于 2009-11-14T00:31:45.037 回答
5

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

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

作为一种优化,您可以将多个模型组合成一个 VBO,然后在进行绘图调用时传入非零偏移量;这从 VBO 中提取了正确的模型。还希望将多个绘图调用组合成一个绘图调用,但如果它们需要具有独立的变换,则这是不可能的。(实际上,如果您使用实例化或顶点混合,在某些情况下可能的,但我建议先了解基础知识。)

于 2009-11-13T14:43:53.440 回答