问题
I have difficulty for using matrices
I can move an object, rotate, and move in word coordinate like these:
matScale* matRotate * matTranslate
But I don't know how to move an object in his local axis i.e: after rotate, move(0,0,10) i local Z of the object
EDIT: Sorry but I'm lost :(
I have tried this:
D3DXMatrixRotationX(&matRotateX, modell->getPitch());
D3DXMatrixRotationY(&matRotateY, modell->getYaw());
D3DXMatrixRotationZ(&matRotateZ, modell->getRoll());
matRotate = matRotateX * matRotateY * matRotateZ;
D3DXMatrixScaling(&matScale, modell->getScale().x, modell->getScale().y, modell->getScale().z);
Matrix WVP;
WVP = matScale* matTranslate * matRotate * matView * matProjection;
Matrix translation;
D3DXMatrixTranslation(&translation, 10, 10, 0); // just for test
cBuffer.Final = translation * WVP;
...but the rotation is around WORLD axis, not local :(
EDIT 2:
OK, I begin to understand… we can now:
-Translate my object in local axis with:
translation * matRotate * matScale * matTranslate * matView * matProjection
“or” we can:
-Rotate this object on local axis with:
matRotate * translation * matScale * matTranslate * matView * matProjection
But, I want to do the two transformation in same time ^^, I want to translate in <local> AND I want to rotate in <local> with the same operation
How it’s possible? :-)
EDIT 3
Okay, I think we can simplify that...
I want to move on Z axis of the object, I can do that:
if (input.keyPressed(VK_UP))
{
ship->translate(0, 0, -0.01, ASF3D::LOCAL);
}
Then, I update positions of my objects in their class: (fuction: translate)
position.x += z * sin(yaw);
position.y += z * sin(pitch);
position.z += z * -cos(yaw);
After this, I make my matPosition (Instead of managing a location matrix and a matrix tranlation)
Then, I do my: cBuffer.Final = matScale* matRotate * matTranslate* matView * matProjection;
I can't test atm, but I'm sure it's working and it easier
I'm just not sure about the calculations of trigonometry :P
回答1:
Note:
This answer is not specific to DirectX, its about general matrix multiplication. But since you didn`t provide any code or any more information about how you tried to solve the problem, it's the best i can come up with. And it should get you on the right track how transformations with matrices are done.
First some general relations of matrices:
M*N != N*M //non-commutative
M*(N*O) = (M*N)*O //associative
inverse(M*N) = inverse(N)*inverse(N)
Let S be the scaling matrix, Rthe rotation and T the translation. Further x are the coordinates in local, untransformed coordinates while w are the coordinates in world coordinates.
If you multiply coordinates as column-vector from the right, you get something like:
w = S*R*T * x <-> w = S*(R*(T*x))
which first translates in the local coordinates of x, then rotates in the translated coordinates, then scales in the translated and rotated coordinates. A transformation L in the local coordinate-system can be easily achieved by multiplying 'L' from the right to your current transformation matrix:
w = S*R*T * L * x <-> w = S*(R*(T*(L*x)))
if you are fixed to multiply it to the left, you need to transform it first with some matrix M and its inverse I=inverse(M) like this:
w = M*L*I * S*R*T * x
one can easily see, that with M=(S*R*T) this becomes:
w = (S*R*T) * L * inverse(S*R*T) * (S*R*T) * x
w = S*R*T * L * x
which is the same as above.
If you multiply your coordinates x as a row-vector from the left, the above formulas become:
w = x * S*R*T <-> w = ((x*S)*R)*T
which first scales in the local coordinates of x, then rotates in the scaled coordinates, then translates in the scaled and rotated coordinates.
(...)
w = x * L * S*R*T <-> w = (((x*L)*S)*R)*T
(...)
w = x * S*R*T * I*L*M
w = x * (S*R*T) * inverse(S*R*T) * L * (S*R*T)
w = x * L * S*R*T
Edit after you provided some code:
Your cBuffer.Final is computed as:
cBuffer.Final = translation * WVP;
or
cBuffer.Final = translation * matScale* matTranslate * matRotate * matView * matProjection;
Since DirectX uses row-vectors, this takes your coordinates x and then first applies translation, moving the object out of the center. Then it applies matScale scaling the Object around the center of your coordinate-system (and therefore moving it even further). Then it applies matTranslate moving it again. Then it applies matRotate, rotating it around the center of your coordinate system (this will move the object in a wide arc, since your object is not centered anymore). Then it applies the matView and finally matProjection to get the screen-coordinates of your object.
If you want to rotate the object around its local coordinate system, try this:
cBuffer.Final = matRotate * translation * matScale * matTranslate * matView * matProjection;
This will first rotate the object (while it is still in the center of your coordinate system) and then apply (in order) the translation, matScale, matTranslate, matView and matProjection.
If you (as stated in the part of your question before the edit) want to move your object in local coordinates along the vector (0,0,10), try this:
D3DXMatrixTranslation(&translation, 0, 0, 10);
cBuffer.Final = translation * matRotate * matScale * matTranslate * matView * matProjection;
The importan part to note is: The order of your matrix-multiplications determines the order in which transformations are applied. I.e. A*B != B*A
Edit2:
To take the example with the spaceship from comment:
Let's say your spaceship has a position and a rotation given by 2 matrices matPosition and matRotate. Then the final transformation matrix is given by:
cBuffer.Final = matScale * matRotate * matPosition * matView * matProjection
(See again this image why we first rotate and then translate.)
Then if you want to update your matPosition by moving the position 5 steps in z-direction you would write:
D3DXMatrixTranslation(&translation, 0, 0, 5);
matPosition *= translation;
But you want to move it in the local z-direction. So what you want to do is to have this transformation:
cBuffer.Final = matScale * translation * matRotate * matPosition * matView * matProjection
Which (look at the picture again) will first translate, then rotate (giving a translation in local axis) and then move the object to its position. However we anyhow need to "move" this translation into the position-matrix or in the next step it will use the new rotation matrix, which we dont want. But we can rewrite the line as (without scale, view and project):
cBuffer.Final = translation * matRotate * matPosition
/ This is the unity-matrix \
cBuffer.Final = matRotate * inverse(matRotate) * translation * matRotate * matPosition
\ - - store this in a new position-matrix - - - - - - - /
cBuffer.Final = matRotate * matNewPosition
This leads us to:
D3DXMatrixTranslation(&translation, 0, 0, 5);
matPosition = inverse(matRotate) * translation * matRotate * matPosition;
cBuffer.Final = matScale * matRotate * matPosition * matView * matProjection;
来源:https://stackoverflow.com/questions/35393594/directx-matrix-translation-in-local-axis