【发布时间】:2014-06-12 09:41:59
【问题描述】:
我正在使用 OpenGL 编写一个简单的 3D 引擎。我已经使用以下模式实现了一个简单的场景图:
ISceneNode
IMeshSceneNode
StaticMeshSceneNode
ICameraSceneNode
StaticCameraSceneNode
TrackBallCameraSceneNode
ILightSceneNode
PointLightSceneNode
但我想知道“渲染器”(实现着色器程序的类)是否也可以是场景节点(将渲染代码从 MeshSceneNode 提取到 RenderSceneNode)。对我来说这可能是一个正确的选择,因为如果我必须使用相同的顶点和片段着色器渲染多个网格(例如 42 个网格),那么绑定和取消绑定着色器程序一次而不是 42 次应该很有用!
那么您如何看待以下架构:
第一个代表我当前的概念(为简单起见,我不代表“灯光”和“相机”场景节点)。
所以,在这里,如果我想渲染我的 3 个网格(使用相同着色器的 3 个着色器程序),我将为每帧绑定和取消绑定 3 次着色器程序(在每个网格节点的“渲染”方法中) .
这是另一个概念:
正如您在上面看到的,这次我将在渲染节点中为所有子节点绑定一个唯一的着色器程序。所以它可能会更快。
你觉得我的想法怎么样?
【问题讨论】:
-
任何减少你认真改变绑定的 GLSL 着色器程序的次数的东西都会表现得更好(当你完成绘图时使用程序 0 “取消”绑定实际上是非常没有意义,只需保留该状态,直到您真正需要发出与其相关的命令并且许多冗余更改将自行解决)。由于驱动程序必须执行复杂的状态验证,GLSL 程序和帧缓冲区对象通常是更改成本最高的状态。更改顶点状态、制服等要便宜得多。
-
你描述的想法肯定已经被使用过,从概念上讲这不是一个坏主意 - 但是请意识到场景树是[所有]对象的集合体,并且这个想法改变了节点的基本布局(即在具有多个对象的优化图中),取消场景图的应用(对象的层次和逻辑分组)。单个对象现在可能有多个散布在树周围的叶节点,但缺少任何逻辑上的共同祖先。
-
感谢您的回答。那么,你认为场景图应该只由网格、相机、灯光和根组成吗?渲染部分应该只在网格场景节点内的“渲染”方法中是精确的?所以所有节点都必须有一个共同的转换矩阵(对于渲染器,情况并非如此......)。所以要优化我的着色器程序绑定,我必须找到另一个解决方案,但不在场景图中?是这样吗?
-
是的,场景图不一定会生成图形命令的最佳顺序。您始终可以在您的软件中添加一个附加层,以获取场景图生成的批次并对其进行排序,以最大限度地减少更昂贵的状态更改。例如,不透明几何体没有太多顺序依赖性,您可以按着色器 ID 对不透明绘制批次进行排序,以防止更改着色器。同样,如果您从不“取消”绑定着色器,那效果最好;在适当设计的软件中,不需要“取消”绑定资源,只需在需要时绑定不同的东西。
-
其实我刚才提到的很多都是here讨论的。您可能会发现 Qt Quick 的场景图渲染器的实现细节值得一读。
标签: opengl openscenegraph scenegraph