# 2D scene graph not transforming relative to parent

I am currently in the process of coding my own 2D Scene graph, which is basically a port of flash's render engine.

The problem I have right now is my rendering doesn't seem to be working properly. This code creates the localTransform property for each DisplayObject.

Matrix m_transform =
Matrix.CreateRotationZ(rotation) *
Matrix.CreateScale(scaleX, scaleY, 1) *
Matrix.CreateTranslation(new Vector3(x, y, z));


This is my render code.

float dRotation;
Vector2 dPosition, dScale;
Matrix transform;
transform = this.localTransform;
if (parent != null) transform = localTransform * parent.localTransform;
DecomposeMatrix(ref transform, out dPosition, out dRotation, out dScale);

spriteBatch.Draw(this.texture, dPosition, null, Color.White, dRotation,
new Vector2(originX, originY), dScale, SpriteEffects.None, 0.0f);


Here is the result when I try to add the Stage then to the stage a First DisplayObjectContainer and then a second one.

It may look fine but the problem lies in the fact that I add a first DisplayObjectContainer at (400,400) and the second one within it (that's the smallest one) at position (0,0). So he should be right over its parent but he gets render within the parent at the same position the parent has (400, 400) for some reason. It's just as if I double the parent's localMatrix and then render the second cat there.

This is the code i use to loop through every childs.

base.Draw(spriteBatch);
foreach (DisplayObject childs in _childs)
{
childs.Draw(spriteBatch);
}

• Alt+PrintScreen will capture just the active window. Just FYI. – MichaelHouse Sep 30 '12 at 19:22
• haha sweet didnt knew about that – Dr.Denis McCracleJizz Sep 30 '12 at 19:52
• Could you please upload the code and/or print and share the contents of localTransform and parent.localTransform during runtime. Also, please get another screenshot with the medium cat set to 100,200 so we can see that we are indeed looking at 2x the correct offset and not some other quirk. – wolfdawn Sep 30 '12 at 19:54
• Oh and please add some comments to the code. It would make life much easier to anyone who wants to help you solve the bug. - something suspicious about these lines here: transform = this.localTransform; if (parent != null) transform = localTransform * parent.localTransform; (wouldn't that be like typing) if (parent != null) transform = transForm * parent.localTransform; (which is not my point) My point being that you are changing This.localTransform, so if that stored the correct offset, next time your render it will store incorrect data. – wolfdawn Sep 30 '12 at 19:56
• @ArthurWulfWhite Looks like it, but localTransform is almost certainly a Matrix which is a value type, so it is not being written over, only its copy is. – David Gouveia Sep 30 '12 at 20:17

I could not figure out exactly where the code is failing, but I've noticed several things that you might want to change nonetheless.

1) The multiplication by the parent transform should be recursive all the way to the root

I recommend for instance using a recursive GlobalTransform property such as:

public Matrix GlobalTransform {
get { return Parent != null ? LocalTransform : LocalTransform * Parent.GlobalTransform;
}


Otherwise your scene graph will only work for children one level deep.

2) Don't translate the Z component

In your matrix you're doing Matrix.CreateTranslation(new Vector3(x, y, z)). I'm not sure but I think using a z different from 0 might cause problems because the SpriteBatch.Draw parameter called layerDepth is the one responsible for controlling the depth of the sprite, and this might mess that up.

3) You could also add the origin into the transform matrix

This one is optional ,but if you incorporate the origin into your matrix (by doing -origin * scale * rotation * translation) and leave it as Vector2.Zero on the SpriteBatch.Draw call, it can make other tasks easier to implement because you don't have to account for the origins separately.

For example, you could check if the mouse is intersecting the oriented bounding rectangle of the display object simply by multiplying it by the inverse GlobalTransform and then seeing if the result is within the (0,0) to (TextureWidth, TextureHeight) range.

• Thanks for the help, Adding GlobalTransformation did not solve the issue. Maybe if i had how i look through the childs it might help. – Dr.Denis McCracleJizz Sep 30 '12 at 21:16
• @Dr.DenisMcCracleJizz Here's one alternative that you can try: have the Draw method receive the parent transform as an optional parameter. Something like this. It's actually the way I'm doing it. This way you don't have to traverse up the hierarchy - the parent feeds the children with all the information it needs to draw. – David Gouveia Sep 30 '12 at 21:31