需要一些帮助来实现使用视锥体裁剪的VBOs。

4

我目前正在为学校项目开发我的第一个3D游戏,游戏世界完全受Minecraft的启发(世界完全由方块组成)。我现在正在尝试通过实现顶点缓冲对象来改善性能,但是遇到了困难。我已经实现了以下方法:视锥体剔除、只绘制暴露的面和距离剔除,但我有以下疑问:

  1. 我目前在我的世界里大约有2^24个方块,分成1024个16*16*64方块的块,现在我正在使用即时模式渲染,它可以很好地与视锥体剔除配合使用,如果我为每个块实现一个VBO,那么我是否需要每次移动相机时更新该VBO(以更新视锥体)?这会影响性能吗?

  2. 我可以动态更改每个VBO的大小吗?还是必须使每个VBO具有可能最大的大小(块被完全填充)?

  3. 我是否需要将每个访问过的块保留在内存中,还是可以高效地删除该VBO并在需要时重新创建它。


虽然这不是 StackOverflow 的主题,但你可能会在 gamedev.stackexchange.com 上找到更多有 OpenGL 经验和注重性能的程序员。 - Kylotan
你说得对,我也打算去试试运气。 - Isracg
2个回答

2
  1. 每次改变相机视锥体时都修改VBO可能不是一个好主意。持续缓冲数据所带来的开销可能会超过从中绘制更少多边形所获得的性能提升。当它们完全移出视锥体时,你最好消除整个VBO。你最终会绘制比严格必要的多边形,但这将被从VBO中绘制明显更快的事实所平衡。
  2. 你可以改变VBO的大小,但只能通过调用glBufferData来完成,如果你正在向图形卡发送数据,则这可能是一次昂贵的调用。
  3. 最好不要在内存中保留为其创建了VBO的所有块,否则很快就会失控。保留你周围的立即环境,并在你离开时将它们丢弃是你最好的选择。

对于第二点:如果他确实每帧都更新整个VBO,那么他应该调用glBufferData,因此他也可以只更改不同的大小。而如果他不更新VBO(就像你在第一点中建议的那样),他也不需要调整其大小。因此,在这种情况下,我认为使用glBufferData没有问题。 - Christian Rau
我只是一般地谈论改变VBO大小,而不是特别针对他的情况。我的意图是表明改变vbo的大小需要完全重新缓冲,因此你不能轻易地在末尾添加几个元素。 - nonVirtualThunk
@nonVirtualThunk 我有另一个问题,我是否必须为每个VBO中的每个顶点保留索引?因为我有非常多的顶点,这似乎很耗费内存。我不能在给定的VBO中绘制所有顶点吗? - Isracg
@Isracg 如果你说的是在调用glDrawElements(...)时使用的索引,那么不,它们并不是严格要求的。如果你愿意,你可以使用glDrawArrays(...)函数代替。这将按顺序使用VBO中的每个顶点来组成基元。然而,如果你可以在多个基元之间共享顶点(例如,一个立方体的一个角被用来绘制它所属的三个面),glDrawElements(...)实际上可以让你使用更少的内存。 - nonVirtualThunk

2
  1. 第一种天真的(并不一定是坏的)方法确实是根据视锥体和隐藏面剔除结果每帧更新VBO。虽然这听起来很邪恶,但请记住,使用立即模式实际上也会做同样的事情(每帧将每个顶点发送到GPU),但需要调用无数次驱动程序(不要低估glVertex),而不仅仅是几个缓冲函数和单个绘制调用。

    因此,使用VBO(当然要使用GL_DYNAMIC_DRAWGL_STREAM_DRAW)很可能仍然比立即模式更快。不仅可能是GPU存储,还有减少的驱动程序调用数量使得VBO(或顶点数组总体而言)比立即模式更快。

    稍后,您还可以使用变换反馈实现一些更复杂的硬件剔除技术,这样您就可以直接在GPU上进行剔除,而不需要每帧将顶点数据发送到GPU。

  2. 由于您每帧都会更新整个缓冲区(因此应该调用glBufferData),因此调整大小绝对不是问题。只需使用不同的大小再次调用glBufferData即可。

  3. 这取决于您有多少块。但是,如果它们的数量越来越多,则某些缓存技术(删除更远、距离剔除的VBO块)可能是一个好主意。


嗨,根据您的建议,我在编写方面取得了非常好的进展,只有一个问题需要询问。在每个VBO中,我是否需要为每个顶点保留索引? - Isracg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接