Scene Graph Questions

Recommended Posts

jdub    459
I am in the process of completing a scene graph-like structure for a 2D game engine. I am also really new to matrix math. So here are my questions: I store a matrix for each scene node describing their orientation relative to their parent node. When rendering I concatenate all of these matrices together to put them into game world space. I store the world orientation of each node in a matrix. Finally, I translate each node's world orientation to its position on screen and render it. If I want to transform a scene node in world space before it is rendered, how do I do this? If I just set the matrix directly, it will get overwritten when the scene graph stores all of the node's parents concatenations. The only way I can think of is to see what the world space transformation is for that node's parent and emulate a transformation in world space while actually doing the transformation in parent space. How would I emulate this? I am sorry if I am very confusing as I am new to this and might not be using the correct terminology.

Share on other sites
VizOne    598
Hi,

I don't think I understood your description completely, but here's what I do: a node has two transformation matrices, one that stores the local transformation relative to the node's parent, the other is the global transformation of the node, ie. the world transform for that specific node. I can translate(), rotate() etc a node by modifying the local transformation node. When I update the scene graph, each node's global transformation is set like:

node.GlobalTransform = node.LocalTransform * node.Parent.GlobalTransform

The matrix that is used as the world matrix for rendering is node.GlobalsTransform.

The localtransform matrix can be updated in several ways, here are two:
a) Maintain a rotation vector R (or quaternion), a translation vector T and a scale vector S separately. When you need the local transform matrix, build it by concatenating:
Matrix.Scale(S)*Matrix.Rotation(R)*Matrix.Translation(T)
Such an SRT matrix is a nice way to describe scaling, rotation and translation absolutely in the node's local frame. The methods to change the location go like this:
void translate(float x, float y, float z){ node.translationVector += Vector(x,y,z);}void rotationYawPitchRoll(float yYaw, float xPitch, float zRoll){ node.rotationQuaternion = Quaternion.YawPitchRoll(yYaw, xPitch, zRoll) * node.rotationQuaternion;}...Matrix getWorldMatrix(){  return Matrix.Scale(scaleVector) * Matrix.RotationYawPitchRoll(rotationQuaternion) * Matrix.Translation(translationVector);}

b) If you want a way to control the matrix more "first-person-like", ie. you want to apply an additional transformation to the current transformation, you'd modify the local matrix directly:
void translate(float x, float y, float z){ node.LocalTransform = Matrix.Translation(x,y,z) * node.LocalTransform;}void rotationYawPitchRoll(float yYaw, float xPitch, float zRoll){ node.LocalTransform = Matrix.YawPitchRoll(yYaw, xPitch, zRoll) * node.LocalTransform;}

The difference is, that with the second approach you modify the local matrix consecutively and the different transformation types can appear in any order; while with the first approach your local transformation matrix will always be built by applying scaling, rotation and translation in a fixed order. You should play with both approaches to see what say do. Personally I even use both methods. Method 1) to create a local frame for the node relative to its parent and method 2) to move a node through its local frame.

Regards,
Andre

Share on other sites
jdub    459
Thankyou for replying. You provided me with some interesting information.

My question however is How can I set the global transform matrix of a node and have it affect rendering considering that I have a big hierarchy of nodes.

You:

When I update the scene graph, each node's global transformation is set like:

node.GlobalTransform = node.LocalTransform * node.Parent.GlobalTransform

However it seems that the global transform will be set when you update no matter what. This means that if I set the global transform before I update the scene and render. The Global transform matrix will be over written by the scene graph. I was wondering how I would solve this problem?

Share on other sites
VizOne    598
Add a boolean flag to a node like "OverrideGlobalTransform", "IsDetached", "AbsoluteTransform" or so and when you update the graph check for this flag

if(!node.OverrideGlobalTransform){  // a normal node that is related to its parent via the LocalTransform  node.GlobalTransform = node.LocalTransform * node.Parent.GlobalTransform} else{  // two choices, depending on where the node stores the overriding  // global transform  // a) do nothing, because the node directly provides  //    a GlobalTransform that must not be changed  // b) node.GlobalTransform = node.LocalTransform  //    if the node stores its personal GlobalTransform in LocalTransform}

But out of curiosity, do you have a specific case where you'd want to do that? You could instead make the node a child of the root with a similar effect. It seems to break up the principle of a logical hierarchy if you'd had a car node with four wheel nodes, but one of the wheel nodes would refuse to move with the car :-) Yes, you can change a tire, but in that case I wouldn't consider it a child of the car anymore.

Share on other sites
haegarr    7372
Look e.g. this thread on how such a thing can be handled.