【问题标题】:best way to wrap opengl models包装opengl模型的最佳方法
【发布时间】:2015-01-17 03:24:44
【问题描述】:

简而言之:包装更高级别“模型”对象所需的 OpenGL 缓冲区、着色器和/或矩阵的“首选”方式是什么?

我正在尝试用基于核心 OpenGL 3.3 的 C++ 编写这个微型图形引擎,我想实现一个尽可能干净的解决方案来包装更高级别的“模型”对象,该对象将包含其顶点缓冲区、全局位置/旋转、纹理(也许还有着色器?)和可能的其他信息。

我已经研究了this open source engine, called GamePlay3D 并且不太同意它解决这个问题的许多方面。有没有什么好的资源可以讨论现代 OpenGL 的这个主题?还是有一些简单而干净的方法来做到这一点?

【问题讨论】:

  • 您能告诉我们您不同意 GamePlay3D 的哪些方面吗?
  • 我注意到您说您正在创建一个图形引擎。您是否有任何构建您将使用该引擎的东西的经验?我问这个是因为开发人员陷入框架/引擎开发作为避免应用程序/游戏开发的一种常见模式。
  • 我同意并且已经亲自经历了开发中的这些障碍 =) 但是在研究了这个自制引擎的可能替换之后,我得出的结论是,添加其他人的库会强制执行某些限制,因为它是带有图形引擎的案例对于实现干净、可重用的代码库是非常有害的,而这正是我非常看重的东西。此外,我计划制作的这个引擎应该是简约的,我正在同时开发我更大项目的其他部分。
  • @Jerem 有几点我不同意 GamePlay3D,我只是觉得写得太多了,也太有争议了,但我会在这里解释一下。 GamePlay3D 试图不仅仅是一个图形引擎,包括声音和物理库——我的目标是保持它的清洁。在查看了其中内置的一些应用程序示例后,我看到仍然需要在相当低的级别上配置多少高级对象,而我的目标是简化并为应用程序开发人员提供更抽象的编程接口。在某种程度上,我会说我的思维方式受到了 arch linux 的启发。

标签: opengl game-engine


【解决方案1】:

这在很大程度上取决于您希望能够使用引擎做什么。另请注意,这些概念与 DirectX(或任何其他图形 API)相同,因此不要将搜索过多地集中在 OpenGL 上。以下是 3D 引擎中非常常见的几点(名称可能不同):

网格: 一个网格包含子网格,每个子网格包含一个顶点缓冲区和一个索引缓冲区。这个想法是每个子网格将使用不同的材料(例如,在角色的网格中,可能有一个用于身体的子网格和一个用于衣服的子网格。)

实例: 一个实例(或网格实例)引用一个网格,一个材质列表(网格中的每个子网格一个),并包含“每个实例”着色器制服(世界矩阵等),通常分组在一个统一缓冲区中。

材料:(这部分根据引擎的复杂程度变化很大)。基本版本将包含一些纹理、一些渲染状态(混合状态、深度状态)、一个着色器程序和一些所有实例通用的着色器统一(例如颜色,但也可能在实例中,具体取决于什么)你想做。)

更复杂的版本通常将包含上一段中所有内容的passes(或有时包含passes技术)中的材料分开。您可以查看Ogre3D documentation 了解更多信息并查看一种可能的实现。 GPU PRO 3 中还有一篇名为 Designing a Data-Driven Renderer 的非常好的文章,它描述了基于相同想法(但也更复杂)的更灵活的系统。

场景:(我在这里称其为场景,但实际上它可以被称为任何东西)。它提供来自环境的着色器参数和纹理(光照值、环境贴图等)。

我认为这就是基础。考虑到这一点,如果您想了解实现细节,您应该能够找到任何开源 3D 引擎代码的方法。

【讨论】:

  • 这个答案正是我一直在寻找的,但有点不相关,这如何与延迟渲染方法一起工作?由于渲染是在帧缓冲区中完成的,这个答案的结构在大多数情况下仍然有效吗?或者核心区别是什么?
  • 另一方面,这个答案的方法有多现代?这种结构是什么时候普及的,没有更新的方法可以充分利用 OpenGL 3.3 吗?
  • @nOvoid:延迟渲染器也是如此。唯一的区别是您不在场景中存储照明信息(但场景仍然可以提供其他信息)。我不知道它什么时候普及,但据我所知,没有更现代的方法可以以通用的方式组织模型数据。现在,我在这里描述的内容非常模糊,现代性可能更多地取决于引擎的实现方式(例如,实例化是当今非常重要的技术,但必须在上面添加我所描述的。)
【解决方案2】:

这是对 Jerem 出色回答的补充。

在底层,没有“模型”之类的东西,只有缓冲区数据和用于处理它的代码。在高层次上,“模型”的概念会因应用程序而异。国际象棋游戏中的每个棋子都有一个静态网格,具有共享的纹理和材质,但第一人称射击游戏可能有复杂的模型,其中包含多个部分、可更换的皮肤、命中框、索具、动画等。

案例研究:国际象棋

国际象棋有六种棋子和两种颜色。让我们对图形引擎进行过度设计,以展示如果您需要在同一个屏幕上同时绘制数千个国际象棋游戏,而不仅仅是一个游戏,它是如何完成的。以下是您可以执行的操作。

  • 将所有模型存储在一个大缓冲区中。该缓冲区将所有六个模型的所有顶点和索引数据聚集在一起。这意味着您在绘图时无需切换缓冲区/VAO。此外,这个缓冲区永远不会改变,除非用户进入设置并为棋子选择不同的样式。

  • 创建另一个缓冲区,其中包含游戏中每个棋子的当前位置、每个棋子的颜色以及对该棋子模型的引用。该缓冲区每帧更新一次。

  • 加载必要的纹理。也许法线会在一个纹理中,而漫反射贴图将是一个数组纹理,其中一层用于白色,另一层用于黑色。纹理经过精心设计,因此您在绘制棋子时无需更改它们。

  • 要绘制所有棋子,您只需更新一个缓冲区,然后调用glMultiDrawElementsIndirect()...每帧一次,它会绘制所有棋子。如果这不可用,您可以回退到 glDrawElements() 或其他方式。

分析

您可以看到这种设计并非适用于所有事物。

  • 如果您必须将新模型流式传输到内存中并删除旧模型怎么办?

  • 如果模型有不同大小的纹理怎么办?

  • 如果模型更复杂,带有动画或正向运动学怎么办?

  • 半透明模型呢?

  • hit box 和物理数据呢?

  • 不同的 LOD 呢?

这里的问题是,您的解决方案,甚至是“模型”的概念,都会因您的需求而大不相同。

【讨论】:

  • 虽然我认为您对图形引擎的潜在复杂性提出了一个很好的观点,但我想要实现的是良好的开箱即用可用性,允许许多常见用例轻松完成并拥有强大、可扩展的代码结构,允许添加 LOD、半透明度等,而无需对现有系统进行太多更改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
  • 2011-03-12
  • 2021-08-31
  • 1970-01-01
相关资源
最近更新 更多