开发者

implementing MVC pattern on c++ scene graph

开发者 https://www.devze.com 2023-01-27 14:10 出处:网络
I have a tree of objects that represent a 3D-model (a scene graph). The tree nodes are of different types (implemented as derived classes from a common base class). For example, there is a node repres

I have a tree of objects that represent a 3D-model (a scene graph). The tree nodes are of different types (implemented as derived classes from a common base class). For example, there is a node representing a polygon, or a node which applies a coordinate transformation (rotation, translation) to its child nodes. It is also a requirement, that third party vendors should be able to implement new node types, and add them by a plugin (I use Qt as GUI framework). Therefore it is possible, that there may be nodes in the tree, of whom the type is unknown when compiling.

Now I want to implement a class, that acts as a vie开发者_JAVA技巧w for this scene graph. For every tree node type the view has to take the appropriate actions (draw the polygon, transform etc.). My idea is to implement view classes for every node type and let the top-level-view class delegate to these classes depending on the node type. (Third party vendors will be able to implement own view delegate classes)

So my question is: how can I determine the type of a node in a performant and extensible way?

My ideas so far:

  1. I could add a type identifier to every node class. This could simply be an integer (strings are not suitable for performance reasons). The problem is the management of type identifiers for third party vendors. How can I make sure that the same identifier is not used for different node types (e.g. by different vendors)?

  2. I could implement drawing code, or at least a call to the appropriate drawing delegate object directly in the node. But my node objects should preferably not know something about their view objects. Also it is not possible to give every node object a dedicated view object (we are talking about tens of thousands of nodes).

So, what are your ideas? Is there perhaps a completely different way to handle this? Remember: the solution should NOT require hash table lookups or other computation intensive algorithms, because I need to draw the graph in real time.

Thanks in advance, McNumber


A scene graph normally lives in the View layer of an MVC system. After all, scene sort of implies the part you see. Typically one would, after setting the proper OpenGL context (or whatever drawing api your using defines as the equivalent), you would call some "render" method on the root node of the scene graph, and it then recursively renders all of its descendants.

Scene graphs do not often represent other kinds of state. For instance in a game with physics simulation, you would keep a scene graph around to perform rendering, but a list of physics objects is maintained separately by the physics engine, and it follows a very separate structure. Physics engines work best if objects that are physically near each other are also traversed in a local manner. Rendering works best if objects with similar rendering characteristics (made from the same textures) are traversed in a local manner.

Thus, a node on the scene graph would know how to look up the position of the model instance it represents, emit that to the renderer and then emit the drawing primitives for that object type.


with that out of the way, actually implementing such a thing probably means thinking about the kinds of interactions, at a global level, the root node of the scene graph must respond to. In the typical case, that probably means rendering.

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

The most obvious thing to do from there is to make a node that has children, so that we actually have a tree of nodes.

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();
    }
};


What about breaking down the viewing operation into a set of simple operations (move to (x,y) position, draw line of N length and so on) as part of a render class. Then each model node can have its own render operation in which it calls operations on a render object that has these simple operations in its interface.

The implementation of the render class can implement these simple operations in terms of Qt calls. The top-level View class then just calls the render method on the nodes (it could also pass the appropriate render object as an argument in case you don't want it to be a permanent attribute of the node class).


Inactive thread for a while but I’m wondering if you made progress since then and/or are still working in the same field.

I'm having a similar problem. I'm separating an existing codebase with everything lumped together: Model (SceneGraph), GUI (win32) and rendering (OpenGL) into a nice Model/View framework (no separate Controller). The Model/View separation for the GUI works and now I'm working on the OpenGL rendering. As a first "simple" demand for myself I started out restricting the system in the sense that no inclusion of an OpenGL header is allowed in the model layer. This immediately forces you to have a separate OpenGL "RenderGraph" on the view side in addition to a SceneGraph on the model side. All possible nodes in the SceneGraph get their own view representation (like you state). I kind of like that, because typical OpenGL rendering data (like vertex arrays) stay on the view side. One could for instance imagine a raytrace rendering that has no use for this data, so it’s good not to include it in the model (only things like “radius” or “position”).

The hierarchy of the SceneGraph and Rendergraph is simular at the moment, although I could imagine one would have a different structure based on state changes (as TokenMacGuy mentions). When the SceneGraph changes (as triggered by the GUI, and propagated by the model) you have to handle this change notification locally in the RenderGraph. This involves actions like adding/removing/moving objects. This is a bit cumbersome, but it is manageable.

My main problem at the moment is that the relation between the SceneGraph (Model) and the "ViewGraph" (View/GUI) is a bit different from the relation between the SceneGraph and the RenderGraph (View/OpenGL). While in the first case you can have "horizontal" connections between model nodes and view nodes, in the second case a change of an intermediate node often forces a re-render of the whole RenderGraph, from the root node up. I haven't found an elegant way to incorporate that in my framework.

As an example, say you have a model of a car in your SceneGraph. Somewhere in a leaf, you have "the diameter of the valve of the front left tire". This would be represented in a text control in the ViewGraph and when a user changes it, the corresponding leaf in the SceneGraph is adjusted. No problem, it is a local change. The model receives this change and sends a notification to the RenderGraph to update the OpenGL rendering. The node in the RenderGraph receiving this notification now not only has to re-render itself, but the whole RenderGraph as a whole has to be redrawn.

Kind Regards, Daniel Dekkers

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号