5

我对在 OpenGL 程序中正确使用 VBO 感到有点困惑。

我想创建一个地形分页算法,使用从 4096x4096 灰度高度图调用的地图作为“整体”地图。

根据我的阅读,存储在 VBO 中的每个顶点将占用 64 个字节。

我遇到的问题是大多数消息来源都指出单个 VBO 的大小应该在 1-4mb 之间,并且 VBO 越少越好。然而根据我的计算,存储每个顶点总共需要大约 1 GB 的数据!(4096x4096x64) 这不包括每个顶点可能需要为每个三角形存储多次。

一旦我得到了代码的地形部分,这也不能适应这张地图上的不同车辆和人。

我看到的另一个解决方案是在程序运行时从硬盘驱动器中分页数据,但另一个消息来源说,在程序运行时创建和销毁是一个坏主意,而且最好的做法是尽可能少的 VBO可能的。

我真正想知道的是,我错过了什么?我确定我在这里进行了某种大规模的疏忽,因为 4mb 的最大 VBO 大小似乎非常低,即使我在 64x64 块中加载纹理,以及将填充地图的不同交互式对象也是如此。

还是我对我能取得的成就的期望是不切实际的?有没有更好的方法可供我使用,我不知道?我正在研究诸如 Oblivion 或 Fallout 3 之类的游戏,以及某种程度上的 Boundless Planet,看到了巨大的地形,并想知道这到底是怎么可能的。

我了解如何编码,这不是我第一次深入研究 OpenGL,而是我第一次尝试理解和利用 VBO。

如果有人能阐明我对 VBO 的理解出错的地方,将不胜感激。

4

6 回答 6

9

根据我的阅读,存储在 VBO 中的每个顶点将占用 64 个字节。

它可以占用任意数量的字节,具体取决于顶点格式。
position + normal + texcoords = 4*(3+3+2) = 32 bytes per vertex
position + normal + texcoords + 切线向量(凹凸)= 4*(3+3+2+3) = 44 bytes

这不包括每个顶点可能需要为每个三角形存储多次。

不应多次存储相同的顶点。使用索引图元(三角形列表或三角形条)。为索引绑定缓冲区,然后使用glDrawElementsglDrawRangeElements。请记住,您可以在 OpenGL 中使用四边形——您不必只使用三角形。

(4096x4096x64)

您不需要为地图上的每个像素创建四边形。有些区域是完全平坦的(即高度不变),因此添加额外的三角形会浪费资源。如果您在完成的景观中添加某种网格简化算法,您应该能够丢弃相当多的三角形。此外,过多的多边形会导致问题 - 三角形或四边形应该占用多个像素。如果有多个图元应该占用相同的像素,则渲染结果会有点“嘈杂”。因此,您必须考虑所需的详细程度。

我遇到的问题是大多数消息来源都指出单个 VBO 的大小应该在 1-4mb 之间,并且 VBO 越少越好。

我不会相信每个来源,尤其是在互联网上。很多写教程的人远非“专家”。另一件事是,在 DirectX(不是 OpenGL)中,建议尽可能将所有内容(即所有具有兼容顶点格式的对象)放入一个大型静态顶点缓冲区(VBO 模拟),并避免切换缓冲区以减少渲染的 CPU 开销来电。因此,“VBO 不应大于 4 MB”的建议对我来说非常可疑。

只有来自 API 开发人员或驱动程序开发人员(ATI 或 NVidia)的信息才可能值得信赖。或者当绝对确定(教程或文章的)作者在该领域拥有丰富的经验,而不是另一个毫无头绪的游戏开发者时。来自 GDC、Siggraph、ATI、NVidia 的文档可能是可信的。应该检查由匿名“某人”编写的一些教程是否实际上是正确的。

无论如何,关于性能,微软有两个文档: “Windows 标题的热门问题” “性能优化(Direct3D 9)”(DirectX 的东西,但一些建议可以适用于 OpenGL)。

此外,NVidia 拥有一系列OpenGL 资源,其中包括与性能相关的实用程序(GLexpert可能对您有用,还有 NVIdia OpenGL SDK 等)。通常,当您尝试提高性能时,请尝试不同的技术并衡量结果,而不是盲目地听从别人的建议。查看使用一种或另一种技术每秒获得多少额外帧。

然而根据我的计算,存储每个顶点总共需要大约 1 GB 的数据!(4096x4096x64)

如果您以这种方式构建整个地图,这是正确的。但是没有理由一次加载整个地图,因此您只需要立即可见的地图块。

我正在研究诸如 Oblivion 或 Fallout 3 之类的游戏,以及某种程度上的 Boundless Planet,看到了巨大的地形,并想知道这到底是怎么可能的。

他们不会一次加载所有内容。只有可见的对象、当前的地形“块”和少数附近地形块的低多边形版本在任何单个时刻被加载。游戏仅存储当前使用或即将使用的对象。它不断地从 HDD 获取数据。

于 2010-07-10T09:12:30.547 回答
1

顶点的大小决定了它将在顶点缓冲区中占用多少空间。如果您的顶点仅包含 3D 位置,则每个顶点将有 12 个字节。

这不包括每个顶点可能需要为每个三角形存储多次。

您可以使用索引缓冲区对数据进行索引,以消除重复顶点的需要。

我看到的另一个解决方案是在程序运行时从硬盘驱动器中分页数据,但另一个消息来源说,在程序运行时创建和销毁是一个坏主意,而且最好的做法是尽可能少的 VBO可能的。

是的,创建和销毁将对性能产生负面影响,但与拥有巨大顶点缓冲区的影响相去甚远。如果你想拥有一个巨大的地形;在此期间加载/释放较小部分的地形数据是可行的方法。

我确定我在这里进行了某种大规模的疏忽,因为 4mb 的最大 VBO 大小似乎非常低,即使我在 64x64 块中加载纹理,以及将填充地图的不同交互式对象也是如此。

如果您使用的是 64 字节的顶点;4MB 为您购买 65536 个顶点。(256x256) 这对于任何事情都应该足够了,如果你需要更多的顶点,你可以在几个顶点缓冲区之间分割它们。

免责声明:就我个人而言,我最近才开始使用 OpenGL,对回答 OpenGL 特定问题没有多大帮助。

于 2010-07-10T08:00:20.713 回答
1

如前所述,VBO 中顶点的大小取决于您的顶点格式,因此没有固定格式,因此大小不固定。最佳 VBO 尺寸的统计数据往往会过时,不要指望第一次就能做到这一点,只需使用尺寸和配置文件就不会花费你那么长时间。

关于您可以拥有多少个 VBO,对许多 VBO 来说是的,这意味着很多抽奖电话。也没有人说您已经完全销毁它们,您可以根据需要多次重复使用它们。

您所考虑的某种分页算法一点也不差,有一种众所周知的地形渲染算法使用这种称为Chunked LOD的方法。该算法使用单独的分页线程进行静态地形的核外渲染。

不要试图找到最终完美的解决方案,要学会接受不完美。不要指望每个人都给你答案或者所有的细节你自己做看看。当它实际上成为一个问题时,您总是可以在以后重构和/或优化,否则您将永远无法完成。

于 2010-07-10T08:23:40.143 回答
1

我怀疑您没有按预期使用高度图。您有一个 4096x4096 图像,它是一个像素数组,不打算用作 vertices。在纹理(也称为高度图)中存储高度的全部目的是避免几何体中的这种细节级别(即,在顶点缓冲区中)。

确切的使用技术取决于您的上下文。如果地形仅用于可视化,我建议将其呈现在单个四边形(4 个顶点)上,并使用光照贴图置换贴图视差贴图等着色器。如果它旨在与其他对象进行一些交互(例如,在其上行走的角色),那么一些几何图形是有序的 - 但肯定不是 4096x4096。这是通过局部细节级别自适应地对高度图进行采样的一种方法。

于 2010-07-10T09:16:34.473 回答
0

If you page data in/out, you'll need at least 4 VBOs in case you're rendering near a "four corners" boundary. But as you move around, you can replace the data within these four VBOs instead of creating/releasing them all the time. For this method you should use one of the "dynamic" usage flags, to let OpenGL know that the data may change, but it will be used more than once each time.

于 2010-07-10T09:20:01.677 回答
0

Not sure about some of these things but from what I understand you can have any sized vbo using 1 vbo per texture, even if the model and texture data span multiple peices of multiple objects. Could be confused however.

http://www.swiftless.com/tutorials/opengl/6_vbo.html

于 2011-01-13T05:27:47.100 回答