Directx - Matrix translation in local axis

泄露秘密 提交于 2019-12-11 23:29:01

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!