Monday, September 4, 2017

xna - Transformation order when dealing with Meshes


I have created a player model out of primitive types. To do this I have created a Model class and Component (mesh) class. Each model consists of one or more components my problems start when you have to rotate the model as a whole. When you manually create a mesh, you have to also specify it's origin, my problem is that the player is not rotating, before it worked somewhat (it turned each mesh indivialy) but then I changed the order of the Matrices and now it doesn't rotate at all, I think it is my matrix order:


effect.Parameters["World"].SetValue(Matrix.Identity *  Matrix.CreateTranslation(component.RelativePosition) * Matrix.CreateRotationY(player.Rotation.Y) * Matrix.CreateTranslation(player.Position)  * Matrix.CreateTranslation(player.Model.Origin));

How can I fix this?


Edit:


The update code is (I added the "0, 0, -1" so I can actually see it) but it is rotating each component idividally rather then as a whole model:


effect.Parameters["World"].SetValue(Matrix.CreateTranslation(-player.Model.Origin)  * Matrix.CreateRotationY(player.Rotation.Y) * Matrix.CreateTranslation(component.RelativePosition) * Matrix.CreateTranslation(player.Position) * Matrix.CreateTranslation(0, 0, -1));

enter image description here




Answer



I don't really know exactly what your RelativePosition and Model.Origin stand for, so it's hard to say for certain, but usually the origin part should come at the beggining of the world matrix and be negated (i.e. Matrix.CreateTranslation(-player.Model.Origin)).


Scaling, rotation and translation usually come in SRT order, which you did right.


As for the RelativePosition I'm not sure what it is. But if that's like the transform of the parent object, then I think it needs to go at the end (at least that's how it worked for me here).


Anyway, for future reference, here's a rundown of what is usually the order for each situation:


Simple Transformations


The order of multiplication for a world matrix is typically:


// World Matrix
Scale * Rotation * Translation


And the order of multiplication for a view matrix is typically:


// View Matrix
-Translation * -Rotation * Zoom

Transformations with Origin


However, especially in 2D games, you frequently need to add an origin displacement to your transformation. That's usually added to the beggining, and must be negated too, so:


// World Matrix with Origin
-OriginTranslation * Scale * Rotation * PositionTranslation

The same thing can also be done with a view matrix, but you add it to the end and this time you don't negate it:



// View Matrix with Origin
-PositionTranslation * -Rotation * Zoom * OriginTranslation

Transformations with Selective Origin


There are also some cases where you want to have an origin displacement, but you want it to affect only your scale and rotation, but not your translation. The way to handle that is to undo the origin transformation before reaching the translation component. For example, with the world matrix:


// World Matrix with Origin for Scale and Rotation
-OriginTranslation * Scale * Rotation * OriginTranslation * PositionTranslation

And the view matrix:


// View Matrix with Origin

-PositionTranslation * -OriginTranslation * -Rotation * Zoom * OriginTranslation

Orbiting around Target


Finally, there's the special case where you want something that orbits around another point. In that situation, you simply switch rotation and translation and it becomes:


// Orbit matrix
Scale * Translation * Rotation



Edit


From your picture I now understand you're trying to create a sort of bone hierarchy where the character is composed by several pieces each with their own transformations, which in turn are grouped together and work as a whole.



In this situation it's easier to understand if you divide the process into two separate matrices, one for the character as a whole, and one for the piece, and then combine them into one as:


Piece Absolute World Matrix = Piece Relative World Matrix * Character World Matrix

So for full flexibility let's say your character has its own Position, Rotation, Scale and Origin in the world, and each piece has its own Position, Rotation, Scale and Origin relative to the origin of the character. You would then calculate the actual world matrix as:


Matrix characterMatrix = Matrix.CreateTranslation(-character.Origin) *
Matrix.CreateScale(character.Scale) *
Matrix.CreateRotationY(character.Rotation) *
Matrix.CreateTranslation(character.Position);

foreach(Piece piece in character.Pieces)

{
Matrix pieceMatrix = Matrix.CreateTranslation(-piece.Origin) *
Matrix.CreateScale(piece.Scale) *
Matrix.CreateRotationY(piece.Rotation) *
Matrix.CreateTranslation(piece.Position);

Matrix finalMatrix = pieceMatrix * characterMatrix;
}

Since you only seem to use a small subset of this values, you can remove everything that isn't being used, and if you want you can also inline everything into a single expression (the problem is that you will be recalculating the character's world matrix over and over and again for each piece, which is wasteful).



I think the result would then be, using the values you provided:


effect.Parameters["World"].SetValue(
Matrix.CreateTranslation(component.RelativePosition) * // Piece Matrix
Matrix.CreateTranslation(-player.Model.Origin) * // Character Matrix
Matrix.CreateRotationY(player.Rotation.Y) *
Matrix.CreateTranslation(player.Position) *
Matrix.CreateTranslation(0, 0, -1)
);

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...