1

我有一棵代表 3D 模型(场景图)的对象树。树节点具有不同的类型(实现为来自公共基类的派生类)。例如,有一个表示多边形的节点,或者一个对其子节点应用坐标变换(旋转、平移)的节点。这也是一个要求,第三方供应商应该能够实现新的节点类型,并通过插件添加它们(我使用 Qt 作为 GUI 框架)。因此,树中可能存在节点,其类型在编译时是未知的。

现在我想实现一个类,作为这个场景图的视图。对于每个树节点类型,视图必须采取适当的操作(绘制多边形、变换等)。我的想法是为每个节点类型实现视图类,并让顶级视图类根据节点类型委托给这些类。(第三方供应商将能够实现自己的视图委托类)

所以我的问题是:如何以高性能和可扩展的方式确定节点的类型?

到目前为止我的想法:

  1. 我可以为每个节点类添加一个类型标识符。这可能只是一个整数(出于性能原因,字符串不适合)。问题在于第三方供应商的类型标识符管理。如何确保不同的节点类型(例如不同的供应商)不使用相同的标识符?

  2. 我可以实现绘图代码,或者至少直接在节点中调用适当的绘图委托对象。但是我的节点对象最好不知道它们的视图对象。也不可能给每个节点对象一个专用的视图对象(我们正在谈论数万个节点)。

那么,你的想法是什么?是否有完全不同的方法来处理这个问题?请记住:该解决方案不应该需要哈希表查找或其他计算密集型算法,因为我需要实时绘制图形。

提前致谢, McNumber

4

3 回答 3

2

场景图通常位于 MVC 系统的视图层中。毕竟,场景有点暗示你看到的部分。通常,在设置正确的 OpenGL 上下文(或您使用定义为等效的任何绘图 api)之后,您将在场景图的根节点上调用一些“渲染”方法,然后递归地渲染其所有后代。

场景图通常不代表其他类型的状态。例如,在具有物理模拟的游戏中,您会保留一个场景图来执行渲染,但是物理对象的列表由物理引擎单独维护,并且它遵循一个非常独立的结构。如果物理上彼此靠近的对象也以本地方式遍历,则物理引擎效果最佳。如果以本地方式遍历具有相似渲染特性(由相同纹理制成)的对象,则渲染效果最佳。

因此,场景图上的节点将知道如何查找它所代表的模型实例的位置,将其发送给渲染器,然后发出该对象类型的绘图图元。


顺便说一句,实际实现这样的事情可能意味着在全局层面上考虑场景图的根节点必须响应的交互类型。在典型情况下,这可能意味着渲染。

class SceneNode
{
  public:
    virtual void render() = 0;
};

从那里做的最明显的事情是创建一个有子节点的节点,这样我们实际上就有了一个节点树。

class ListSceneNode : public SceneNode
{
  private:
    typedef std::vector<std::shared_ptr<SceneNode> > ChildList;
    ChildList children;

  public:
    void render() { 
      for(ChildList::iterator i = children.begin() ; i != children.end(); ++i)
        i->render();
    }
};
于 2010-11-26T08:15:17.277 回答
0

作为渲染类的一部分,如何将查看操作分解为一组简单的操作(移动到 (x,y) 位置、绘制 N 长度的线等)。然后每个模型节点可以有自己的渲染操作,它调用渲染对象上的操作,该渲染对象在其接口中具有这些简单操作。

渲染类的实现可以通过 Qt 调用来实现这些简单的操作。顶层 View 类然后只调用节点上的渲染方法(它也可以将适当的渲染对象作为参数传递,以防您不希望它成为节点类的永久属性)。

于 2010-11-26T09:33:16.700 回答
0

有一段时间处于非活动状态,但我想知道您从那时起是否取得了进展和/或仍在同一领域工作。

我有一个类似的问题。我将现有的代码库与所有东西集中在一起:模型(SceneGraph)、GUI(win32)和渲染(OpenGL)到一个不错的模型/视图框架(没有单独的控制器)中。GUI 的模型/视图分离有效,现在我正在处理 OpenGL 渲染。作为对我自己的第一个“简单”需求,我开始限制系统,因为模型层中不允许包含 OpenGL 标头。除了模型端的 SceneGraph 之外,这会立即强制您在视图端拥有一个单独的 OpenGL“RenderGraph”。SceneGraph 中的所有可能节点都有自己的视图表示(如您所说)。我有点喜欢这样,因为典型的 OpenGL 渲染数据(如顶点数组)保留在视图端。

SceneGraph 和 Rendergraph 的层次结构目前是相似的,尽管我可以想象一个会根据状态变化具有不同的结构(正如 TokenMacGuy 提到的那样)。当 SceneGraph 更改(由 GUI 触发并由模型传播)时,您必须在 RenderGraph 中本地处理此更改通知。这涉及添加/删除/移动对象等操作。这有点麻烦,但它是可以管理的。

我目前的主要问题是场景图(模型)和“视图图”(视图/GUI)之间的关系与场景图和渲染图(视图/OpenGL)之间的关系有点不同。在第一种情况下,您可以在模型节点和视图节点之间建立“水平”连接,而在第二种情况下,中间节点的更改通常会强制从根节点向上重新渲染整个 RenderGraph。我还没有找到一种优雅的方式将它整合到我的框架中。

例如,假设您的场景图中有一个汽车模型。在一片叶子的某个地方,你有“左前轮胎气门嘴的直径”。这将在 ViewGraph 中的文本控件中表示,并且当用户更改它时,会调整 SceneGraph 中的相应叶子。没问题,这是本地更改。模型收到此更改并向 RenderGraph 发送通知以更新 OpenGL 渲染。接收到这个通知的 RenderGraph 中的节点现在不仅要重新渲染自己,而且整个 RenderGraph 都必须重新绘制。

亲切的问候,丹尼尔·德克斯

于 2012-12-20T16:20:42.653 回答