当前位置: 首页 > 知识库问答 >
问题:

有多少VAO和VBO

农建弼
2023-03-14

在我的理解中:一个VAO代表一个特定的状态。如果我绑定了一个VAO,添加一些VBO和元素缓冲区,用于索引和东西,我可以保存我想绘制和激活的对象的某个状态,然后在我想渲染东西的时候轻松地绘制它们。对吧?

所以VBO保存实际数据,而VAO只是一个“包装器-对象”,保存指向我为它html" target="_blank">定义的所有缓冲区的指针?

更改VAOs成本很高(更改VBO也是如此?!)。目前,我加载网格,并将它们组合到模型中。每个模型都使用自己的VAO,并有一个VBO(带有顶点)和一个带有索引的元素缓冲区。

现在,正如我所理解的,这是胡说八道,因为我的世界中的每个对象(有一个模型)都使用它自己的VAO。对于我的世界中的30个对象来说不是问题,但我想做对,在未来可能会有数百或数千个对象,然后性能会大幅下降。

因此,许多对象在模型方面是“相同的”。我的意思是,例如,如果你在世界上有一个特定的树型,你可能会在不同的位置多次使用相同的模型。

我该怎么做呢?我应该手动跟踪我的VAO吗,比如:(伪代码跟随!)

treesVAOId = 1;
rabbitsVAOId = 2;

然后,如果我加载了一个模型,只需检查ID是否已经绑定(如何绑定?)并在那里添加另一组VBO(或者甚至添加到右边的VBO?如果是,如何添加?)

我在想一场重要的比赛。让我们假设游戏中有几千个角色。当然,并不是所有这些都是在同一时间呈现,但我不能为他们每个创建一个VAO和VBO,对吗?

我觉得少了很大一部分...例如,实例化和(或多或少)为不同的目的再次有效地使用相同的数据。

共有1个答案

纪勇军
2023-03-14

您在这里描述的称为资源管理器或至少是资源管理器的一部分。在外部文件中描述资源是一个很好的做法,因此您需要一个资源文件,其中以某种方式描述了所有网格(考虑使用XML或JSON)。

类层次结构

下面是类层次结构的一种可能方法:

每个VAO代表一个网格,定义它的顶点坐标、纹理坐标、法线、顶点颜色等等。我认为没有理由在几个VAO中使用相同的VBO,除非你有一个非常特殊的可视化案例。因此,假设您只使用每组数据一次,也就是说,使用VAO的类不应该知道任何关于底层VBO的信息,也没有必要为VBO编写类包装器。

一组网格(可能只包含一个网格)表示一个模型。最小模型类应该包括VAO的句柄和几何变换信息(旋转,翻译,任何你想要的)。为什么不严格地每个模型一个网格?有时,您可能需要将一个转换应用到一组网格上,轮到其中的哪一个网格有自己的模型--局部转换。例如,这样的构图可以用于一种骨骼动画,或者仅仅用于渲染具有从可能的武器库中提取的任意武器的角色。此外,您可以将这些模型组合在一起,得到具有相同界面的更复杂的模型,从而得到场景图的相似性。无论如何,对模型类使用复合模式是一个好主意。

场景应该包括模型、光源、力场等集合

资源管理器

但是场景(或类似的游戏对象)从哪里得到它的模型呢?资源管理器应该回答这个问题。使每个模型由某种唯一标识符定义。在最简单的情况下,真实或虚拟文件系统中的路径可以被视为标识符,但它不是很灵活。在我看来,最好使用具有表现力的人类可读的名称来定义资源文件中的所有网格,并将每个名称绑定到一组数据(所有类型的coords、颜色等)和属性。您的所有代码不应该直接使用模型,而是应该使用资源管理器给您的句柄。显然,资源管理器必须在程序执行期间和来自不同地方的调用之间保持状态。它的目的是跟踪哪些网格已经存储在内存中,并保存所有存储网格的VAO标识符。考虑对资源管理器使用单例模式。

示例:

ModelHandle footman = resMan->getModel("footman.model");
//.....
footman->setLocation(x,y,z);
footman->draw();

在这里,对getModel(“footman.model”)的调用开始构造模型,导致如下调用

MeshHandle resMan->getMesh("footman1.mesh");

来获取所有的网格。而getmesh是导致上述解释的作业。它检查之前是否加载了这样的网格,如果是,它只向包含此网格的VAO返回句柄。否则,它将创建新的VAO对象,将请求的数据加载到该对象中,并将句柄返回给新创建的对象。此对象的所有后续请求都不会导致新的VAO分配。

当然,描述的场景图组织只是它应该看起来的粗略近似。例如,它没有区分模型和抽象场景图节点,但是为您的引擎开发和微调这样的层次结构取决于您。

资源管理器类的最终接口是另一个需要讨论和设计的主题。一些问题和想法:

  • 您将使用单例变量还是出于某种原因决定使用全局变量?
  • 如果您决定使用singleton,也许您希望为一些有限的资源设置一些其他私有的非singleton资源管理器?然后考虑将singleton设计为包装模板类,使这样的代码成为可能:
    ResourceHandle h1 = Singleton<ResourceMan>::instance->getResource("foo");
    ResourceMan myPrivateManager;
    ResourceHandle h2 = myPrivateManager.getResource("bar");
  • 您将使用一个综合管理器来管理所有类型的资源,还是为每种资源类型使用特殊的管理器类?第二种方法更好。第二种方法的开发思路,让您的编译器为您编写代码!使用专门化方法的小子集的模板资源管理器类。只需为每个资源类型专门化一种资源创建方法,而不涉及所有其他资源管理代码!
  • 考虑资源生存期。什么时候应该销毁一个particualr VAO?考虑实现引用计数器和\或借用引用。
  • 缓存?将数据加载到设备(视频卡)后立即从主机内存中删除,还是保留一段时间?多久?
  • 流媒体怎么办?它不应该是资源管理器的域,但流支持会影响它。
  • GlisVertexArray函数及其类似函数可能很有用。

排序

VAOs不是渲染场景时需要更改的唯一资源。您还需要更改纹理、着色器甚至帧缓冲区。减少状态更改次数的常见方法是按某些属性对可显示对象进行排序。

有用的文章开始:

http://www.gamedev.net/page/resources/_/technical/game-programming/a-resource-manager-for-game-assets-R3807

http://www.gamedev.net/page/resources/_/technical/game-programming/a-simple-fast-resource-manager-using-c-and-stl-r2503

 类似资料:
  • 我正在编写一个OpenGL3+应用程序,对VAOS的使用有些困惑。现在我只有一个VAO,一个围绕原点设置的正规化的四方。这个单个VAO包含3个VBO;一个用于位置,一个用于曲面法线,一个用于索引的GL_ELEMENT_ARRAY_BUFFER(所以我只能存储4个顶点,而不是6个)。 绑定四方vao. 每立方体面: 创建表示此面孔的模型矩阵。 将模型矩阵上载到顶点着色器变量。 调用将四边形绘制到这个

  • 当第一次尝试绘制VAOS时,它崩溃了。我画没有着色器(所以它不会引起问题)。 在一个VAO和纹理坐标中最多有12个面(12*3个顶点)。有多达50万个VAO。 我如何创造一张脸: 错误如下: 我不认为把整个错误贴在这里是明智的。你知道为什么会这样吗?我找不到任何关于VBOS的错误。

  • 我试图在OpenGL中使用多个VAO和VBO渲染多个对象。使用相同的顶点渲染多个对象我已经做过了,但是我想做的是为每个对象使用不同的顶点,例如画一个正方形和一个圆形。对于一个正方形,我只需要6个顶点,但是对于圆,我需要360个顶点。我有阅读或创建着色器的错误。 以下是顶点着色器: 片段着色器: VAO和VBO的生成与绑定 以及渲染循环中的绘制调用: 我重复一遍,用我做过的相同顶点绘制多个对象。我需

  • Urban Müller 1993年的Brainfuck据说有一个“至少”30000个细胞的磁带寄存器。然而,考虑到语言主要是在base 2中交易,我想知道他的“磁带”(历史上)是否有单元格。 它说了穆勒使用的细胞的确切数量吗?

  • 我在spring文档https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-concurrency-model中读到,当为客户端和服务器使用reactor netty时,事件循环资源是共享的,这意味着当我创建多个webclient实例时,事件循环资源也是共享的?如

  • 问题内容: 这个问题已经在这里有了答案 : 9年前关闭。 可能重复: 数据库中有多少行? 我正在为将有用户的应用程序构建数据库方案,每个用户在诸如“收藏夹”之类的关系表中将有许多行。每个用户可能有数千个收藏夹,并且可能有数千个注册用户(随着时间的推移)。 鉴于永远不会删除用户,因为这会使其他实体变成孤立的实体,或者也将它们删除(这是不希望的),因此这些表将永远增长,我想知道结果表是否可能太大(例如