您在这里描述的称为资源管理器或至少是资源管理器的一部分。在外部文件中描述资源是一种很好的做法,因此您需要一个资源文件,其中所有网格都以某种方式描述(考虑使用 XML 或 JSON)。
类层次结构
这是类层次结构的一种可能方法:
每个 VAO 代表一个网格,定义它的顶点坐标、纹理坐标、法线、顶点颜色等。我认为没有理由在几个 VAO 中使用相同的 VBO,除非你有一个非常特殊的可视化案例。因此,假设您只使用每组数据一次,即使用 VAO 的类不应该知道任何有关底层 VBO 的信息,并且没有必要为 VBO 编写类包装器。
一组网格(可能只包含一个网格)代表一个模型。最小模型类应包括 VAO 的句柄和几何变换信息(旋转、平移,任何你想要的)。为什么不严格每个模型一个网格?有时您可能需要对一组网格应用一个变换,而它们中的哪一个又具有它自己的模型局部变换。例如,这种组合可以用于一种骨骼动画或仅用于使用从可能的武器库中获取的任意武器来渲染角色。此外,您可以将这些模型组合在一起,以获得具有相同界面的更复杂的模型,因此您将获得场景图的相似之处。无论如何,对模型类使用复合模式是个好主意。
场景应包括模型、光源、力场等的集合。
资源管理器
但是场景(或类似的游戏对象)从哪里得到它的模型呢?资源经理应该回答这个问题。使每个模型都由某种唯一标识符定义。在最简单的情况下,可以将真实或虚拟文件系统中的路径视为标识符,但它不是很灵活。在我看来,最好使用富有表现力的人类可读名称定义资源文件中的所有网格,并将每个名称绑定到数据集(所有类型的坐标、颜色等)和属性。您的所有代码都不应直接使用模型,而应使用资源管理器提供给您的句柄。显然,资源管理器必须在程序执行期间和来自不同地方的调用之间保持状态。它旨在跟踪哪些网格已经存储在内存中,并保留所有存储的网格的 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 分配。
当然,所描述的场景图组织只是它应该是什么样子的粗略近似。例如,它不区分模型和抽象场景图节点,但是为您的引擎开发和微调这种层次结构取决于您。
资源管理器类的最终接口是另一个需要讨论和设计的话题。一些问题和想法:
- 您会使用单例还是出于某种原因决定使用全局变量?
- 如果您决定使用单例,也许您希望为某些有限的资源集使用一些其他私有的非单例资源管理器?然后考虑将单例设计为包装模板类,以使这样的代码成为可能:
ResourceHandle h1 = Singleton<ResourceMan>::instance->getResource("foo");
ResourceMan myPrivateManager;
ResourceHandle h2 = myPrivateManager.getResource("bar");
- 您是使用一个综合管理器管理所有类型的资源,还是为每种资源类型使用专门的管理器类?第二种方法更好。第二种方法的开发思路,让你的编译器为你编写代码!将模板资源管理器类与专用方法的小子集一起使用。只需针对每种资源类型专门化一种资源创建方法,并保持所有其他资源管理代码不变!
- 考虑资源生命周期。什么时候应该销毁特定的 VAO?考虑实现引用计数器和/或借用引用。
- 缓存?将数据加载到设备(视频卡)后立即从主机内存中删除数据还是保留一段时间?多长时间?
- 流媒体呢?它不应该是资源管理器的域,但流支持会影响它。
- glIsVertexArray函数及其类似物可能很有用。
排序
VAO 不是渲染场景时需要更改的唯一资源。您还需要更改纹理、着色器甚至帧缓冲区 减少状态更改次数的常用方法是按某些属性对可显示对象进行排序。
例如,您很可能只使用一个着色器来渲染给定的网格。这就是为什么首先您可以按着色器对所有网格进行排序,因此您可以最大限度地减少着色器更改的数量。然后对于每个着色器(即在给定着色器的网格列表中),您可以按 VAO 对网格进行排序,以将 VAO 更改的数量减少到可行最低限度。按质地排序?如果您需要按纹理对对象进行排序以及在哪里进行排序,这取决于您的应用程序。
结论
总而言之,如果您正在编写游戏引擎,那么无论如何您都需要一个资源管理器。如果您为 VAO 编写了一个快速而简单的部分解决方案,那么您将面临完全相同的问题和处理纹理、附加帧缓冲区和许多其他对象的问题,因此最好实现一次好的资源管理器。
有用的文章开始:
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
很实用的书:
http://www.gameenginebook.com/