Translate - Rotate - Translate Back using XMMATRIX

2019-09-18 22:35发布

If all I know is an object's World matrix (because its x/y/z position is not tracked, which would be easier), how do I go about rotating it around it's center?

If I knew the location, it'd be about as simple as something like this:

        XMMATRIX world = pMissile->GetWorldMatrix(); 

        XMMATRIX matrixTranslation = XMMatrixTranslationFromVector(pMissile->GetPosition());
        XMMATRIX matrixInvTranslations = XMMatrixInverse(nullptr, matrixTranslation);

        float rotationAmount = (60 * XMConvertToRadians((float)fElapsedTime / 2.0f));

        XMMATRIX missileWorld = world * 
                    matrixInvTranslations 
                    * XMMatrixRotationX(rotationAmount) 
                    * XMMatrixRotationY(rotationAmount)
                    * XMMatrixRotationZ(rotationAmount)
                    * matrixTranslation;        
        pMissile->SetWorldMatrix(missileWorld);

Unfortunately, since I don't know the position, I'm not sure what to do. Basically I need to be able to get the "Translate back to the origin" from just the world matrix. Before I start pulling elements out of the matrix, there must be a DirectX or DirectXTK function to do this, no?

Currently I'm decomposing the matrix to get it:

        XMVECTOR vectorTranslation, vectorScale, rotationQuat;
        XMMatrixDecompose(&vectorScale, &rotationQuat, &vectorTranslation, world)

If that's the right/best way, let me know!

Somewhat tangentially, as you can see I use an inverse of the translation to "move it back" to where it was originally before I translated it to the origin for rotation. A lot of samples skip this - is there something I'm missing in that you don't -need- to translate back at the end?

1条回答
ゆ 、 Hurt°
2楼-- · 2019-09-18 22:59

XMMatrixDecompose is the correct, fully general way to get the elements of an arbitrary transformation matrix. The computation is expensive, so most folks make assumptions about what's in the matrix--because they control it at all points. For example, avoiding non-uniform scaling can really simplify things.

Many games exclusively use rotation and translation, and avoid scaling or at least avoid non-uniform scaling. You can quickly compute the inverse from such matrices by just transposing the upper 3x3 elements and then negating the x, y, and z elements of the last row.

If you know your matrix only contains a rotation and translation, and never contains scale, then the rotation matrix is just the upper 3x3 elements. As long as your matrix is homogenous (i.e. the last column is [0 0 0 1]), you can just read out the translation from the last row: world.r[3] should be (x, y, z, 1).

If you are new to DirectXMath, you should consider using the SimpleMath wrapper in the DirectX Tool Kit. It handles the alignment complexities a bit more automatically, and includes handy helpers like Matrix::Translation which just extracts the equivalent world.r[3] x, y, and z.

查看更多
登录 后发表回答