Hi guys,could you give me a hand ,now I trapped in the XNA transform problem,I write a simply demo about a helicopter fly with a propeller and rotor,now the problem is I'm going to change the Y value of the helicopter also change the propeller and rotor,after I done it,the strage thing appear rotor and propeller didn't fowllow the direction

of helicoper,even the rotor is far away from helicopter!How could I do?

**1**

# Transform

Started by granberg, Sep 09 2011 01:01 AM

11 replies to this topic

Sponsor:

###
#2
Members - Reputation: **1118**

Posted 09 September 2011 - 01:29 AM

Try this (pseudo code, trick works for OpenGL and DX8 as i remember it, probably does for XNA too)

DrawHelicopter() { DrawHull DrawPropeller Transform(Rotate) PushMatrix DrawRotator PopMatrix } Render() { Transform(Translate) PushMatrix DrawHelicopter() PopMatrix }

###
#3
Members - Reputation: **56**

Posted 09 September 2011 - 05:36 AM

I can't understand popMatrix and pushMatrix,but now I can show my code,could you check the error for me

private void DrawRotor()

{

Vector3 RotorPosition = new Vector3(airplanePosition.X +0.7f - 0.2f + 0.25f, airplanePosition.Y - 0.3f , airplanePosition.Z + 0.4f); ;

Matrix RotorTranslation, world, scale, rotationZ, OrbitTranslation, OrbitRotateY;

scale = Matrix.CreateScale(0.3f, 0.7f, 0.0f);

OrbitRotateY = Matrix.CreateRotationY(RotationAngle() - 0.04f);

rotationZ = Matrix.CreateRotationZ(propellerSpin);

OrbitTranslation = Matrix.CreateTranslation(1.04f , 0.0f, 0.2f);

RotorTranslation = Matrix.CreateTranslation(RotorPosition);

world = scale * rotationZ * OrbitTranslation * OrbitRotateY * RotorTranslation;

// world = scale * rotationZ * RotorTranslation;

// 4: set shader parameters

positionColorEffectWVP.SetValue(world * cam.viewMatrix

* cam.projectionMatrix);

// 5: draw object - primitive type, vertices, # of primitives

PositionColorShader(PrimitiveType.TriangleStrip, propellerVertices, 2);

RotorPosition = new Vector3(airplanePosition.X + 0.7f - 0.2f + 0.22f, airplanePosition.Y + 0.3f, airplanePosition.Z);

RotorTranslation = Matrix.CreateTranslation(RotorPosition);

OrbitTranslation = Matrix.CreateTranslation(1.17f, 0.0f, 0.0f);

OrbitRotateY = Matrix.CreateRotationY(RotationAngle() + 0.04f);

world = scale * rotationZ * OrbitTranslation * OrbitRotateY * RotorTranslation;

// world = scale * rotationZ * OrbitRotateY * RotorTranslation;

// 4: set shader parameters

positionColorEffectWVP.SetValue(world * cam.viewMatrix

* cam.projectionMatrix);

// 5: draw object - primitive type, vertices, # of primitives

PositionColorShader(PrimitiveType.TriangleStrip, propellerVertices, 2);

}

rotor sometime sideways from airplane.

private void DrawRotor()

{

Vector3 RotorPosition = new Vector3(airplanePosition.X +0.7f - 0.2f + 0.25f, airplanePosition.Y - 0.3f , airplanePosition.Z + 0.4f); ;

Matrix RotorTranslation, world, scale, rotationZ, OrbitTranslation, OrbitRotateY;

scale = Matrix.CreateScale(0.3f, 0.7f, 0.0f);

OrbitRotateY = Matrix.CreateRotationY(RotationAngle() - 0.04f);

rotationZ = Matrix.CreateRotationZ(propellerSpin);

OrbitTranslation = Matrix.CreateTranslation(1.04f , 0.0f, 0.2f);

RotorTranslation = Matrix.CreateTranslation(RotorPosition);

world = scale * rotationZ * OrbitTranslation * OrbitRotateY * RotorTranslation;

// world = scale * rotationZ * RotorTranslation;

// 4: set shader parameters

positionColorEffectWVP.SetValue(world * cam.viewMatrix

* cam.projectionMatrix);

// 5: draw object - primitive type, vertices, # of primitives

PositionColorShader(PrimitiveType.TriangleStrip, propellerVertices, 2);

RotorPosition = new Vector3(airplanePosition.X + 0.7f - 0.2f + 0.22f, airplanePosition.Y + 0.3f, airplanePosition.Z);

RotorTranslation = Matrix.CreateTranslation(RotorPosition);

OrbitTranslation = Matrix.CreateTranslation(1.17f, 0.0f, 0.0f);

OrbitRotateY = Matrix.CreateRotationY(RotationAngle() + 0.04f);

world = scale * rotationZ * OrbitTranslation * OrbitRotateY * RotorTranslation;

// world = scale * rotationZ * OrbitRotateY * RotorTranslation;

// 4: set shader parameters

positionColorEffectWVP.SetValue(world * cam.viewMatrix

* cam.projectionMatrix);

// 5: draw object - primitive type, vertices, # of primitives

PositionColorShader(PrimitiveType.TriangleStrip, propellerVertices, 2);

}

rotor sometime sideways from airplane.

###
#4
Members - Reputation: **1118**

Posted 09 September 2011 - 06:45 AM

PushMatrix pushes the transformation stack, telling that all the following transformations will happen together, and not affect the previously transformed vertices.

PopMatrix pops the stack. Back to the level above. Or below, depending on how you see it. Towards the root level.

PopMatrix pops the stack. Back to the level above. Or below, depending on how you see it. Towards the root level.

###
#8
Members - Reputation: **56**

Posted 09 September 2011 - 10:45 AM

positionColorEffectWVP.SetValue(world * cam.viewMatrix

* cam.projectionMatrix);

// 5: draw object - primitive type, vertices, # of primitives

PositionColorShader(PrimitiveType.TriangleStrip, propellerVertices, 2);

two calls darw the primitive

###
#9
Members - Reputation: **109**

Posted 22 September 2011 - 10:17 PM

So one of your problems is that rotor position is a direct offset from the plane.

Imagine your helicopter has three transform matrices: Scale, Rotate (for what direction it's facing), Translate (from the origin)

Imagine your rotor has two transform matrices: Scale, Rotate (for the degrees it's spun), Translate (to translate it from the helicopter body)

So your final transform matrix for the helicopter is: Helicopter.Transform = Helicopter.Scale * Helicopter.Rotate * Helicopter.Translate

But for the rotor, you have to apply the helicopter's matrices as well so that its offset from the helicopter properly: Rotor.Transform = Rotor.Scale * Rotor.Rotate * Rotor.Translate * Helicopter.Rotate + Matrix.CreateTranslation(Vector3.Transform(Vector3.Zero, Helicopter.Transform))

You multiply the rotor's transform matrix by Helicopter.Rotate so that the rotor will be angled properly against the fin rather than, say, be perpendicular to the fin since the user rotated the helicopter 90 degrees to the right. You then basically add the helicopter's position to the rotor's position so that the rotor isn't floating at (0,0) when the helicopter is at (30, 5) and rotated 10 degrees in the yaw.

Maybe this will fix your code? It's just off the top of my head.

Imagine your helicopter has three transform matrices: Scale, Rotate (for what direction it's facing), Translate (from the origin)

Imagine your rotor has two transform matrices: Scale, Rotate (for the degrees it's spun), Translate (to translate it from the helicopter body)

So your final transform matrix for the helicopter is: Helicopter.Transform = Helicopter.Scale * Helicopter.Rotate * Helicopter.Translate

But for the rotor, you have to apply the helicopter's matrices as well so that its offset from the helicopter properly: Rotor.Transform = Rotor.Scale * Rotor.Rotate * Rotor.Translate * Helicopter.Rotate + Matrix.CreateTranslation(Vector3.Transform(Vector3.Zero, Helicopter.Transform))

You multiply the rotor's transform matrix by Helicopter.Rotate so that the rotor will be angled properly against the fin rather than, say, be perpendicular to the fin since the user rotated the helicopter 90 degrees to the right. You then basically add the helicopter's position to the rotor's position so that the rotor isn't floating at (0,0) when the helicopter is at (30, 5) and rotated 10 degrees in the yaw.

Maybe this will fix your code? It's just off the top of my head.

###
#10
Members - Reputation: **1206**

Posted 23 September 2011 - 03:04 AM

In addition to GGulati's explanation, you can represent (logically, or in your code) the helicopter cockpit and its rotor(s) as a transform hierarchy of the transforms he describes. Your rotors will be spinning in a certain direction, and at a certain speed that should not affect the helicopter cockpit at all. However, the rotor positions in world space have to be rigid to the cockpit, e.g. the helicopter goes up, the rotors spin but are translated up accordingly. Each piece, therefore, maintains its own "local" transform - the cockpit probably is centered at the origin, but the main rotor is translated some units up the y-axis and so on. Then when you're updating the scene, you combine these local transforms into a final world transform for each piece of geometry.

For example, from my own code organization:

1. Each geometry has a local/world Transform, where a Transform is comprised of a Vector3 for Scale, a Quaternion for Rotation, and a Vector3 for Translation. You can of course use a rotation matrix rather than a quaternion, or keep three matrices for each component - but I tend to shy away from matrices.

2. The scene is organized with parent-child relationships. So the cockpit would be a parent, and the two rotors would be children (they have a reference to their parent and vice versa).

3. Every Update() call on the scene, each child combines their local transform with their parent's world transform:

Cockpit - No parent, simply uses its local Transform as its world transform.

Rotors - Parent is the cockpit, so their locals are combined with the cockpit's world transform.

The actual combination code looks something like this:

The (world) transform class I use has a matrix property which would then be used in with your view/projection matrices when setting the world-view-projection to the effect you're using. I cache that matrix too, so it's only computed once unless if any of the individual components change. Likewise, my scene management only updates world transforms if a scene object's transform has changed to reduce redundant computations. For example, the cockpit's transform may not change, but the rotor's rotation will, so only the world matrix is recomputed for the rotor and not for the cockpit. If the cockpit's transform changed, both would need to be updated. (Basically update any scene object, and any other objects it would influence - so children).

I mention this because your DrawRotor() could be made a lot simpler where each geometry has its own transforms, that get compiled to a world matrix in some general function like I posted above, making it easy to add new objects to Render, since you may only need to change a few transform properties without having to re-write the same sort of code. Also, you can reduce computations for parts of your models that don't actually move in a frame.

For example, from my own code organization:

1. Each geometry has a local/world Transform, where a Transform is comprised of a Vector3 for Scale, a Quaternion for Rotation, and a Vector3 for Translation. You can of course use a rotation matrix rather than a quaternion, or keep three matrices for each component - but I tend to shy away from matrices.

2. The scene is organized with parent-child relationships. So the cockpit would be a parent, and the two rotors would be children (they have a reference to their parent and vice versa).

3. Every Update() call on the scene, each child combines their local transform with their parent's world transform:

Cockpit - No parent, simply uses its local Transform as its world transform.

Rotors - Parent is the cockpit, so their locals are combined with the cockpit's world transform.

The actual combination code looks something like this:

private Vector3 _scale; private Quaterion _rotation; private Vector3 _translation; private bool _cacheRefresh; private Matrix _cachedMatrix; ... //Combines the components into a matrix public Matrix Matrix { get { if(_cacheRefresh) { Matrix scaleM; Matrix rotationM; Matrix translationM; Matrix.FromScale(ref _scale, out scaleM); Matrix.FromQuaternion(ref _rotation, out rotationM); Matrix.FromTranslation(ref _translation, out translationM); _cachedMatrix = scaleM * rotationM * translationM; _cacheRefresh = false; } return _cachedMatrix; } } public void CombineWithParent(Transform parent) { //Multiply scaling Vector3.Multiply(ref parent._scale, ref _scale, out _scale); //Multiply rotation Quaternion.Multiply(ref parent._rotation, ref _rotation, out _rotation); //Combine translation Vector3.Multiply(ref _translation, ref parent._scale, out _translation); Vector3.Transform(ref _translation, ref parent._rotation, out _translation); Vector3.Add(ref _translation, ref parent._translation, out _translation); _cacheRefresh = true; }

The (world) transform class I use has a matrix property which would then be used in with your view/projection matrices when setting the world-view-projection to the effect you're using. I cache that matrix too, so it's only computed once unless if any of the individual components change. Likewise, my scene management only updates world transforms if a scene object's transform has changed to reduce redundant computations. For example, the cockpit's transform may not change, but the rotor's rotation will, so only the world matrix is recomputed for the rotor and not for the cockpit. If the cockpit's transform changed, both would need to be updated. (Basically update any scene object, and any other objects it would influence - so children).

I mention this because your DrawRotor() could be made a lot simpler where each geometry has its own transforms, that get compiled to a world matrix in some general function like I posted above, making it easy to add new objects to Render, since you may only need to change a few transform properties without having to re-write the same sort of code. Also, you can reduce computations for parts of your models that don't actually move in a frame.

**Starnick **

Tesla Graphics Engine | AssimpNet | DevILNet |

###
#12
Members - Reputation: **458**

Posted 21 June 2012 - 07:34 AM

Granberg, look up NESTED TRANSFORMATION.

This is what you need.

The concept being, you have a world, with its coordinate space (positions relative to a zero point and arbitrary orientations of Up, Right and Forward), when you send stuff to be rendered, the graphics system uses your models transformations as well as the point of view (or camera transformation) to take that world to the coordinate space of the screen,

When the position of one model is relative to another, in this case the rotor is relative to the chopper, for this to be represented the rotor must not be in the world's coordinate space, but in that of the chopper, so the transformation of the rotor needs to first be applied that of the chopper before you send it to the graphics system.

Seriously look up nested transformations, once you understand it, it will make your life easy.

This is what you need.

The concept being, you have a world, with its coordinate space (positions relative to a zero point and arbitrary orientations of Up, Right and Forward), when you send stuff to be rendered, the graphics system uses your models transformations as well as the point of view (or camera transformation) to take that world to the coordinate space of the screen,

When the position of one model is relative to another, in this case the rotor is relative to the chopper, for this to be represented the rotor must not be in the world's coordinate space, but in that of the chopper, so the transformation of the rotor needs to first be applied that of the chopper before you send it to the graphics system.

Seriously look up nested transformations, once you understand it, it will make your life easy.

Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272