【问题标题】:Simple curiosity about scene graph conception对场景图概念的简单好奇
【发布时间】: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


【解决方案1】:

Anton 所说的另一种说法:如果您想优化状态更改,您不希望场景图中的节点直接进行任何绘制调用。将其委托给您的渲染器,然后渲染器将能够构建一个中间表示,在此基础上它可以重新排序 OpenGL 调用以进行优化。

为您的渲染器定义一个干净的 API 还可以让您分离您的关注点:

  • 画什么,对比
  • 如何绘制。

然后您甚至可以使用双重分派(如进化的访问者模式)来使事情更通用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2022-12-04
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    相关资源
    最近更新 更多