Jump to content
  • Advertisement
Sign in to follow this  
matt77hias

Obtaining specializations from a scene graph

Recommended Posts

How does or could one obtain specializations from a scene graph?

I currently use a TransformNode that looks something like this:  

 __declspec(align(16)) struct TransformNode final 
        : public AlignedData< TransformNode > {

    private:

        friend class Node;

        SharedPtr< Transform > m_transform;
        Node *m_parent;
        vector< SharedPtr< Node > > m_childs;

        mutable XMMATRIX m_object_to_world;
        mutable XMMATRIX m_world_to_object;
        mutable bool m_dirty_object_to_world;
        mutable bool m_dirty_world_to_object;
    };

The TransformNode encapsulates a local Transform (parent <> object) as well as its positioning in a scene graph (parent and child Nodes). A Node itself is some proxy on top of a TransformNode, allowing to do node->getTransform()->SetTranslation() via an indirection instead of directly calling and polluting the node itself (e.g. node->SetTranslation()). The Node class forms the root of a hierarchy containing abstract models, lights, sprites, cameras which all have their own specializations.

Given some Node, how does one normally convert it to its specialization?

  • Each node has a name, so I can search for a specific node and perform a dynamic_cast based on a template type provided by the user. Though this requires names to be globally unique or at least unique in every subtree of the scene graph.
  • If all the specializations are known in advance, then a static_cast can be used instead of a dynamic_cast if some enum member specifies the specialized type.
  • If all the specializations are known in advance, I can use specialized collections instead of one general collection in TransformNode.
  • The scene graph can support general visitors, but this requires an expensive double dispatch as well as lots of boilerplate code for a single implementation of the visitor.

For rendering purposes, I also have some flattened collections of the scene graph: models, specialized lights, cameras and sprites. But I do not have the need to have a collection for each specialization. For the lights, I explicitly want to know the most specialized types, but for cameras I do not really care for rendering and can just work with the abstract camera interface.

Share this post


Link to post
Share on other sites
Advertisement

If you're considering dynamic_casts or need to convert from base to specialization, then you most likely have a fundamental design problem on your hands and are trying to do something you shouldn't be.

Do you even need to build a linked hierarchy this way, or can you give it to a higher-level construct (scene graph itself)? What is the purpose of these specializations? Do they have anything in common, can they share an interface? Is this transform node actually necessary, or are you putting in extra effort for a non-existent problem?

If the goal is to keep transform separate from the node, then just use composition and have each node contain a transform that it can then plug into the scene graph. There's no reason to use inheritance here, IMO.

Edited by Styves

Share this post


Link to post
Share on other sites

The hierarchy looks like this:

https://matt77hias.github.io/MAGE-Doc/MAGE-Doc/html/classmage_1_1_node.html

1 hour ago, Styves said:

If the goal is to keep transform separate from the node, then just use composition and have each node contain a transform that it can then plug into the scene graph. There's no reason to use inheritance here, IMO.

But what if you have child nodes? Lets say you have a perspective camera node and add an omni light node as child (or alternatively one can specify this for a transform as well), how do you obtain the omni light node given that perspective camera node?

Share this post


Link to post
Share on other sites

You don't, because that's horrid design and asking for a spaghetti mess at the end.

 

Tell your nodes to process themselves, and they can handle any components/children as appropriate. Your main processing can be one line of code: tell the root node to process.

This "process" might be Tick(), or NetworkSync(), or Render(), or any number of other operations.

Share this post


Link to post
Share on other sites
8 minutes ago, ApochPiQ said:

tell the root node to process

But then I have a giant number of virtual method calls. Now I have 0 virtual method calls.

Furthermore, the issue remains for scripting. You cannot retrieve any specializations if you do not have a pointer or reference directly to those specializations.

Edited by matt77hias

Share this post


Link to post
Share on other sites
31 minutes ago, ApochPiQ said:

This "process" might be Tick(), or NetworkSync(), or Render()

My Update()/FixedUpdate() is down in some script instance which needs to store all the needed nodes.

The Render() is down outside the node itself. The node only provides an interface to access the data needed for rendering.

Share this post


Link to post
Share on other sites
37 minutes ago, Mike2343 said:

I liked this article when it first came out: http://lspiroengine.com/?p=566

I read the article, but it still puzzles me. :(

My scene graphs (multiple roots are possible) are not the primary scene data structure, neither do I operate on the scene graph for rendering or frustum culling. I have flattened collections (this works for now but has a linear complexity) of nodes in my scene itself which I iterate for these purposes.

The scene graph is only used for propagation and has some general methods for doing this as well as some specialized transform related methods with dirty flags. This is similar to Unity3D's hierarchies which always contain a transform and thus transform relationships at the very least. My scene graph doesn't do any processing.

So this looks not like violations against the design of a scene graph.

This however still does not specify how that you get some component of some child. The very least a scene graph does is specify the relationships between parents and childs.

 

Edited by matt77hias

Share this post


Link to post
Share on other sites

I hope L.Spiro reads this one. :)

Why do you need to get "some component of some child" if no processing is occurring?

What exactly is your goal? What problem are you trying to solve? It's really difficult to give you a straight answer without knowing what the problem domain is.

Also, if you want to avoid virtual calls but still process the hierarchy the way ApochPiQ mentioned then just break things up into lists of specialized components (light, camera, etc) and iterate over each list separately, keeping a simple link to the node/transform if necessry. Don't over-complicate it with OOP.

For example you can sort the nodes in order of the hierarchy with parents coming first and then process them in linear order, without even leaving the current function and without the need for any virtual inheritance. Any special behavior can just be linked to the nodes in some way.

Edited by Styves

Share this post


Link to post
Share on other sites
14 minutes ago, Styves said:

Also, if you want to avoid virtual calls but still process the hierarchy the way ApochPiQ mentioned then just break things up into lists of specialized components (light, camera, etc) and iterate over each list separately, keeping a simple link to the node/transform if necessry. Don't over-complicate it with OOP.

I have similar collections in my Scene. Furthermore, I still have composition for my scene graph (difference between Node and TransformNode). I know this seems way too complex, but so far it accomplishes the things I wanted it to support.

14 minutes ago, Styves said:

What exactly is your goal? What problem are you trying to solve? It's really difficult to give you a straight answer without knowing what the problem domain is.

If I load hierarchical models with submodels, I cannot use non-root nodes to their full potential, because I cannot access them (unless I use my previous proposals). If a plane has some propeller attached to some other part, I cannot get the propellor.

For the submodel<>model specifically, I don't want to have another hierarchy. The only thing that such submodels share is just a mesh, so special treatment is overkill.

 

16 minutes ago, Styves said:

Why do you need to get "some component of some child" if no processing is occurring?

Scripting.

Edited by matt77hias

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!