C++ 中的 OpenGL VBO 技术细节

发布于 2024-09-08 21:22:48 字数 703 浏览 8 评论 0 原文

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

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

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

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

一旦我计算出代码的地形部分,这也无法适应这张地图上的不同车辆和人员。

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

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

或者我对自己能够实现的目标的期望是否不切实际? 有没有更好的方法可供我使用但我不知道? 我正在研究《湮没》或《辐射 3》等游戏,在某种程度上还有《无边星球》,看到了巨大的地形,想知道这到底是如何可能的。

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

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

I'm a little confused as to the proper usage of VBOs in an OpenGL program.

I want to create a terrain paging algorithm, using a map called from a 4096x4096 greyscale heightmap as the "whole" map.

From what I've read, each vertex stored in the VBO will take up 64 bytes.

The problem I have is that most sources state that a single VBO should be between 1-4mb in size, and less VBOs is better.
Yet according to my calculations, storing each vertex would take a total of about a gigabyte of data! (4096x4096x64)
That's not including that each vertice may need to be stored multiple times for each triangle.

Nor does this accommodate the different vehicles and people that would be on this map once I get the terrain portion of the code worked out.

the other solution I looked at was to page the data from the hard drive while the program is running, but another source says it's a bad idea to create and destroy while the program's running, and that it's also best practice to have as few VBOs as possible.

What I really want to know is, what am I missing?
I'm sure I'm making some kind of massive oversight here, because a maximum VBO size of 4mb just seems extremely low, even if I was loading the texture in 64x64 blocks, and the different interactive objects that would populate the map too.

Or are my expectations of what I can achieve just unrealistic?
Is there a better method available to me that I'm unaware of?
I'm looking at games like Oblivion or Fallout 3, and to some extend Boundless Planet, and seeing massive terrains, and wondering how on earth that can be possible.

I understand how to code, this isn't my first delve into OpenGL, but is my first time attempting to understand and utilize VBOs.

If anyone can shed some light into where my understanding of VBOs is going wrong, it would be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

顾北清歌寒 2024-09-15 21:22:48

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

它可以占用任意数量的字节,具体取决于顶点格式。
位置 + 法线 + 纹理坐标 = 4*(3+3+2) = 每个顶点 32 字节
位置 + 法线 + 纹理坐标 + 切线向量(凹凸)= 4*(3+3+2+3) = 44 字节

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

相同的顶点不应存储多次。使用索引基元(三角形列表或三角形带)。绑定索引缓冲区,然后使用 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等)。一般来说,当您尝试提高性能时,请尝试不同的技术并衡量结果,而不是盲目遵循某人的建议。查看使用一种或另一种技术每秒可以获得多少额外帧。

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

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

我正在玩《湮没》或《辐射 3》等游戏,在某种程度上还有《无边星球》,看到了巨大的地形,想知道这到底是如何实现的。

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

From what I've read, each vertex stored in the VBO will take up 64 bytes.

It can take as many bytes as you want, depending on vertex format.
position + normal + texcoords = 4*(3+3+2) = 32 bytes per vertex
position + normal + texcoords + tangent vector (for bump) = 4*(3+3+2+3) = 44 bytes

That's not including that each vertice may need to be stored multiple times for each triangle.

Identical vertices should not be stored multiple times. Use indexed primitives (triangle lists or triangle strips). Bind buffer for indicies, then use glDrawElements and glDrawRangeElements . Keep in mind that you can use quads in OpenGL - you don't have to use only triangles.

(4096x4096x64)

You don't need to create quad for every pixel on the map. Some areas are completely flat (i.e. height doesn't change), so adding extra triangles there will be a waste of resources. If you add some kind of mesh simplification algorithm to finished landscape, you should be able to drop quite a lot of triangles. Also, too many polygons will lead to problems - A triangle or quad should take several pixels. If there are multiple primitives that should occupy same pixel, the rendered result will be a bit "noisy". So you'll have to take desired level of detail into account.

The problem I have is that most sources state that a single VBO should be between 1-4mb in size, and less VBOs is better.

I wouldn't trust every source, especially on the internet. A lot of people writing tutorials are far from being "experts". Another thing is that in DirectX (not OpenGL), it is recommended to put everything(i.e. all objects with compatible vertex format) into one large static vertex buffer (VBO analog), when possible, and avoid switching buffers to reduce CPU overhead for rendering calls. So advice that "VBO shouldn't be larger than 4 MB" looks extremely suspicious to me.

Information may be trustworthy only if it comes from API developer or from a driver developer (ATI or NVidia). Or when it is absolutely certain that author (of tutorial or article) has a lot of experience in the field and not another clueless wannabe game developer. Documents that come from GDC, Siggraph, ATI, NVidia may be trusted. Some tutorial written by anonymouse "someone" should be checked for being actually correct.

Anyway, regarding performance, microsoft had two documents:
"Top Issues for Windows Titles"
"Performance Optimizations (Direct3D 9)" (DirectX stuff, but some advices can be applicable to OpenGL).

Also, NVidia has a collection of OpenGL resources, that include performance-related utilities (GLexpert may be useful for you, and there is NVIdia OpenGL SDK, etc.). In general, when you're trying to improve performance, try different techniques, and measure results instead of blindly following someone's advice. See how many extra frames per second you get from using one technique or another.

Yet according to my calculations, storing each vertex would take a total of about a gigabyte of data! (4096x4096x64)

This is correct if you'll build entire map this way. But there is no reason to load entire map at once, so you'll just need immediately visible chunk of map.

I'm looking at games like Oblivion or Fallout 3, and to some extend Boundless Planet, and seeing massive terrains, and wondering how on earth that can be possible.

They DON'T load everything at once. Only objects that are visible, current "chunk" of terrain and low-polygonal version of few nearby terrain chunks are loaded at any single moment. Game stores only object that are currently used, or that will be used soon. It constantly gets data from HDD.

霓裳挽歌倾城醉 2024-09-15 21:22:48

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

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

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

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

是的,创建和销毁会对性能产生负面影响,但远不及拥有巨大顶点缓冲区的影响。如果你想拥有广阔的地形;在此期间加载/释放较小部分的地形数据是正确的方法。

我确信我在这里进行了某种大规模的监督,因为 4mb 的最大 VBO 大小似乎非常低,即使我以 64x64 块加载纹理,并且填充不同的交互对象还有地图。

如果您使用的顶点有 64 字节; 4MB 可以购买 65536 个顶点。 (256x256)
这对于任何东西来说应该足够了,如果你需要更多顶点,你可以将它们分割到几个顶点缓冲区中。

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

The size of the vertex determines how much space it will take in the vertex buffer.
If your vertex consists of only a 3D position you will have 12 bytes per vertex.

That's not including that each vertice may need to be stored multiple times for each triangle.

You can index your data using an index buffer to remove the need for duplicate vertices.

the other solution I looked at was to page the data from the hard drive while the program is running, but another source says it's a bad idea to create and destroy while the program's running, and that it's also best practice to have as few VBOs as possible.

Yes, creating and destroying will have a negative impact on performance but no where near the impact of having a huge vertex buffer. If you want to have a huge terrain; loading/releasing smaller parts of terrain data during is the way to go.

I'm sure I'm making some kind of massive oversight here, because a maximum VBO size of 4mb just seems extremely low, even if I was loading the texture in 64x64 blocks, and the different interactive objects that would populate the map too.

If you're using a vertex that has 64 bytes; 4MB buys you 65536 vertices. (256x256)
Which should be enough for just about anything, and if you need more vertices you split them between several vertex buffers.

Disclaimer: Personally I only recently started using OpenGL and won't be much help answering OpenGL specific questions.

合约呢 2024-09-15 21:22:48

正如已经提到的,VBO 中顶点的大小取决于您的顶点格式,因此没有固定的格式,因此大小也不固定。关于最佳 VBO 大小的统计数据往往会过时,不要指望第一次就能正确完成,只需调整大小和配置文件即可,这不会花费您那么长时间。

关于您可以拥有多少个 VBO,是的,许多 VBO 意味着大量绘制调用。也没有人说你已经彻底销毁了它们,你可以根据需要多次重复使用它们。

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

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

As already mentioned the size of a vertex in a VBO depends on your vertex format so there is no fixed format and thus the size is not fixed. Stats on optimal VBO sizes tend to get out of date, don't expect to get this right the first time just play around with the size and profile it's not going to take you that long to do.

About how many VBOs you can have, yes to many VBOs means lots of draw calls. Also nobody said you have destroy them completely, you can reuse them as many times as you want.

What you was thinking about having some kind of paging algorithm isn't bad at all, there is one well known terrain rendering algorithm that uses this approach called Chunked LOD. This algorithm uses a separate paging thread for out-of-core rendering of static terrain.

Don't try to find the ultimate perfect solution, learn to accept imperfection. Don't depend on everyone to give you the answer or all the details just do it yourself and see. You can always refactor and/or optimize later when it actually becomes an issue otherwise you'll never finish.

魄砕の薆 2024-09-15 21:22:48

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

确切的使用技巧取决于您的上下文。如果地形仅用于可视化,我建议将其呈现在单个四边形(4 个顶点)上,并使用诸如 光照贴图位移贴图视差映射。如果它的目的是与其他对象进行某种交互(例如,在其上行走的角色),则需要一些几何图形 - 但当然不是 4096x4096。 这是一种根据局部细节级别自适应采样高度图的方法

I suspect you're not using height maps as intended. You have a 4096x4096 image, which is an array of pixels, not intended to be used as vertices. The whole point of storing heights in a texture (a.k.a. height map) is to avoid such a level of detail in the geometry (i.e., in vertex buffers).

The exact usage technique depends on your context. If the terrain is for visualization only, I'd recommend presenting it on a single quad (4 vertices), and using shaders like light maps, displacement mapping or parallax mapping. If it is intended for some interaction with other objects (e.g., characters walking on it), then some geometry is in order - but certainly not 4096x4096. Here's one way to sample the height map adaptively, by it's local detail level.

陌路终见情 2024-09-15 21:22:48

如果您将数据分页输入/输出,则您将需要至少 4 个 VBO,以防您在“四个角”边界附近进行渲染。但是当您移动时,您可以替换这四个 VBO 中的数据,而不是一直创建/释放它们。对于此方法,您应该使用“动态”使用标志之一,让 OpenGL 知道数据可能会更改,但每次都会使用多次。

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.

甜心小果奶 2024-09-15 21:22:48

不确定其中一些事情,但据我了解,即使模型和纹理数据跨越多个对象的多个部分,您也可以为每个纹理使用 1 个 vbo 来拥有任何大小的 vbo。然而可能会感到困惑。

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文