简而言之:什么是"首选"包装OpenGL的缓冲区,着色器和/或矩阵所需的更高级别的模型"对象
我正在尝试用基于核心OpenGL 3.3的C ++编写这个微小的图形引擎,我想实现一个尽可能干净的解决方案来包装更高级别的模型"对象,它将包含其顶点缓冲区,全局位置/旋转,纹理(也可能是着色器?)以及可能的其他信息。
我已经调查了this open source engine, called GamePlay3D,并且不太同意其解决此问题的许多方面。是否有任何好的资源可以为现代OpenGL讨论这个主题?或者有一些简单而干净的方法来做到这一点?
答案 0 :(得分:5)
这很大程度上取决于您希望能够对您的引擎做什么。另请注意,这些概念与DirectX(或任何其他图形API)相同,因此不要过多关注OpenGL的搜索。以下是3D引擎中常见的几点(名称可能不同):
<强>网:强> 网格包含子网格,每个子网格包含顶点缓冲区和索引缓冲区。这个想法是每个子网格将使用不同的材料(例如,在角色的网格中,可能有一个身体的子网格和一个衣服的子网格。)
<强>实例强> 实例(或网格实例)引用网格,材质列表(网格中每个子网格一个),并包含“每个实例”着色器制服(世界矩阵等),通常分组在统一缓冲区中。
材料:(此部分会根据引擎的复杂程度而发生很大变化)。基本版本将包含一些纹理,一些渲染状态(混合状态,深度状态),着色器程序和一些所有实例共有的着色器制服(例如颜色,但也可能在实例中取决于什么你想做什么。)
更复杂的版本通常将传递中的材料(或有时包含传递的技术)分开,其中包含上一段中的所有内容。您可以查看Ogre3D documentation以获取更多相关信息,并查看一个可能的实现。在GPU PRO 3中还有一篇名为设计数据驱动渲染器的非常好的文章,它描述了一个基于相同想法(但也更复杂)的更灵活的系统。
场景(我在这里称它为场景,但它可以被称为任何东西)。它提供了环境中的着色器参数和纹理(光照值,环境贴图,此类事物)。
我认为这是基础知识。考虑到这一点,如果您需要实现细节,您应该能够找到适合任何开源3D引擎代码的方法。
答案 1 :(得分:2)
这是Jerem的优秀答案的补充。
在低级别,没有“模型”这样的东西,只有缓冲区数据和用于处理它的代码。在高层次上,“模型”的概念将因应用而异。国际象棋游戏将为每个国际象棋棋子提供静态网格物体,共享纹理和材料,但第一人称射击游戏可能有复杂的模型,包括多个部分,可更换皮肤,命中框,装配,动画等等。
国际象棋有六种颜色和两种颜色。让我们过度设计图形引擎,以展示如果你需要在同一个屏幕上绘制数千个同步的国际象棋游戏,而不仅仅是一个游戏,它是如何完成的。你可以这样做。
将所有模型存储在一个大缓冲区中。此缓冲区包含所有六个模型的所有顶点和索引数据。这意味着您在绘制工件时无需切换缓冲区/ VAO。此外,此缓冲区永远不会更改,除非用户进入设置并为棋子选择不同的样式。
创建另一个缓冲区,其中包含游戏中每件作品的当前位置,每件作品的颜色以及对该作品模型的引用。此缓冲区每帧都会更新。
加载必要的纹理。也许法线会出现在一个纹理中,漫反射贴图将是一个数组纹理,其中一层为白色,另一层为黑色。纹理的设计使您在绘制棋子时无需更改它们。
要绘制所有部分,您只需要更新一个缓冲区,然后每帧调用glMultiDrawElementsIndirect()
... 一次,它会绘制所有的棋子。如果没有,您可以回退到glDrawElements()
或其他。
你可以看到这种设计对一切都不起作用。
如果您必须将新模型流式传输到内存中并删除旧模型,该怎么办?
如果模型具有不同尺寸的纹理怎么办?
如果模型更复杂,有动画或正向运动学怎么办?
半透明模型怎么样?
点击框和物理数据怎么样?
不同的LOD怎么样?
问题在于,您的解决方案,甚至是“模型”的概念,将根据您的需求而有很大不同。