25 Nov 2015, 15:34
(This post was last modified: 25 Nov 2015, 19:20 by Ketschak.
Edit Reason: fixed wrong matrix multiplication
)
I will try to give you a short summary about how the concept of transformation matrices is working. If you understand this concept, the answer to your question should be clear.
In computer graphics vertices are usually represented as a vector and transformations of vertices as matrices. In 3D a 3-vector and a 3x3-matrix can be used to transform a vector by a linear transformation.
Using this concept you can perform linear transformations like rotation or scale.
The problem is that you cannot perform an affine transformation like a translation with this concept. To be able to also represent affine transformations with a general matrix*vector operation, homogenous coordinates are used. This means representing a 3-vector (x, y, z) as a 4-vector (x, y, z, 1) instead.
Using homogenous coordinates, we can represent linear and affine transformations by simple 4x4 transformation matrices.
We can combine transformations by simply multiplying these transformation matrixes.
The order of transformations (order of matrix multiplications) is important! You cannot switch the order of the transformations and expect to end up with the same result. Use for example one Matrix T1 that translates in x direction and one matrix T2 that rotates around the z-axis.
With T'=T2*T1 you will get a completely different result as with T'=T1*T2
In the Murl Engine the Transform interface represents a transformation matrix with methods to directly set the rotation and translation components.
You can compose a combined transformation from individual transformations by nesting separate Transform nodes:
In this example the PlaneGeometry will first apply its own Transform then Transform t1 and then Transform t2.
You can also compose a transformation by calculating the transformation matrix in code:
If you directly set the rotation and translation components in one transformation matrix, you must be aware of the following restrictions:
What does this all mean for your example:
In your example you rotate the cube around X first and then rotate the cube around Y by HALF_PI. The result is a spinning cube which is spinning around the axis-Z. That is the expected behaviour.
If you want to rotate the cube first around Y and then around X, a second transformation matrix needs to be used. E.g.
I hope that helps to better understand transformation matrices.
Best regards, Ketschak
In computer graphics vertices are usually represented as a vector and transformations of vertices as matrices. In 3D a 3-vector and a 3x3-matrix can be used to transform a vector by a linear transformation.
Using this concept you can perform linear transformations like rotation or scale.
The problem is that you cannot perform an affine transformation like a translation with this concept. To be able to also represent affine transformations with a general matrix*vector operation, homogenous coordinates are used. This means representing a 3-vector (x, y, z) as a 4-vector (x, y, z, 1) instead.
Using homogenous coordinates, we can represent linear and affine transformations by simple 4x4 transformation matrices.
We can combine transformations by simply multiplying these transformation matrixes.
The order of transformations (order of matrix multiplications) is important! You cannot switch the order of the transformations and expect to end up with the same result. Use for example one Matrix T1 that translates in x direction and one matrix T2 that rotates around the z-axis.
With T'=T2*T1 you will get a completely different result as with T'=T1*T2
In the Murl Engine the Transform interface represents a transformation matrix with methods to directly set the rotation and translation components.
You can compose a combined transformation from individual transformations by nesting separate Transform nodes:
<Transform id="t2" …>
<Transform id="t1" …>
<PlaneGeometry ../>
</Transform>
</Transform>
In this example the PlaneGeometry will first apply its own Transform then Transform t1 and then Transform t2.
You can also compose a transformation by calculating the transformation matrix in code:
Graph::Matrix T1(Matrix::IDENTITY);
T1.SetTranslationComponentX(200);
Graph::Matrix T2(Matrix::IDENTITY);
T2.SetRotationComponentZ(45*Math::DEG_TO_RAD);
Graph::Matrix& m = mCubeTransform->GetTransform();
m = T2*T1;
If you directly set the rotation and translation components in one transformation matrix, you must be aware of the following restrictions:
- Rotation is applied before translation is applied.
- SetRotationComponentX or SetRotationX
SetRotationComponentY or SetRotationY
SetRotationComponentZ or SetRotationZ
overwrites the upper 3x3 matrix. Therefore you get a rotation around the specified axis. Existing values will be overwritten. Calling SetRotationComponentX first and SetRotationComponentY second has the same effect as if you would call SetRotationComponentY only.
- SetRotationComponent(angleX,angleY,angleZ) or SetRotation(angleX,angleY,angleZ)
overwrites the upper 3x3 matrix with the given rotations in a fixed rotation order. Currently only one rotation order is implemented: ROTATION_ORDER_ZYX. Unfortunately the name is badly chosen, because it reflects the nesting order of the hypothetical Transform nodes and not the actual order of the rotations. The actual order of rotations is rotate X first, then rotate Y, then rotate Z.
- The SetTranslationComponent/SetPosition methods overwrite the respective translation component value(s) in the transformation matrix and can be used independently.
What does this all mean for your example:
static Double angleX = 0;
static Double angleY = Math::HALF_PI;
static Double spinSpeed = 0.007;
angleX += spinSpeed;
angleX = Math::Fmod(angleX, Math::TWO_PI);
angleY = Math::Fmod(angleY, Math::TWO_PI);
mCubeTransform->SetRotation(angleX, angleY, 0);
In your example you rotate the cube around X first and then rotate the cube around Y by HALF_PI. The result is a spinning cube which is spinning around the axis-Z. That is the expected behaviour.
If you want to rotate the cube first around Y and then around X, a second transformation matrix needs to be used. E.g.
Graph::Matrix T1(Matrix::IDENTITY);
T1.SetRotationComponentY(Math::TWO_PI);
Matrix& m = mCubeTransform->GetTransform();
m.SetRotationComponentX(angleX);
m = m*T1;
I hope that helps to better understand transformation matrices.
Best regards, Ketschak