Understanding a (d3dx) model matrix's content

Started by
10 comments, last by Burnt_Fyr 9 years, 12 months ago

Hi,

I've been brushing up my matrix math because I ran into some issues. To be sure I get it right, I'd like to know if the following is correct:

- I create a World matrix for an object, by multiplying Scale, Rotation and Translation matrices

- this gives we for example:

[ 0.5 0.0 0.2 0.0 ]

[ 0.0 0.4 0.3 0.0 ]

[ 0.0 0.1 0.2 0.0 ]

[ 3.0 2.0 1.0 1.0 ]

When I try to 'read' this matrix I conclude:

- row 1/ 2 / 3 = X / Y / Z axis orientation = scaling + rotation combined (scaling first)

- row 4 = X/Y/Z/W translation

- if I want to extract a vector from the matrix, that gives my either X, Y or Z orientation (without translation), I could use the 1st three components of row 1, 2 or 3

- when I multiply a vector (position/point) with this matrix, for example:

[ 1.0 ]

[ 2.0 ]

[ 0.0 ]

[ 1.0 ]

=> the X component of the vector is only affected by the 1st row of the matrix

=> the Y component of the vector is only affected by the 2nd row of the matrix

=> the Z component of the vector is only affected by the 3rd row of the matrix

Are my assumptions correct or am I overseeing something?

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Advertisement

Your vector should be like [ 1.0 ] [ 2.0 ] [ 0.0 ] [ 1.0 ] since you are using row major and your vector should be on the left side of your matrix when you are multiplying. (V x M).

- if I want to extract a vector from the matrix, that gives my either X, Y or Z orientation (without translation), I could use the 1st three components of row 1, 2 or 3

Yes but you should take scaling into consideration so you need to normalize each axis.

=> the X component of the vector is only affected by the 1st row of the matrix

=> the Y component of the vector is only affected by the 2nd row of the matrix

=> the Z component of the vector is only affected by the 3rd row of the matrix

Your result vector's x component is effected by first column of the matrix, y is effected by second column and so on. And as a result you get another row vector. I suggest you to read some tutorials about matrices if you are having trouble with multiplication before starting to get deeper since you will need a good understanding for the basics.

Thanks, I dug into some more theory and get it now.
Basically the 1st 3 rows and columns save the rotation/ scaling. Where for example rotation on X axis, is affecting the matrix 'members' in the non X (i.e. 2nd/3rd) rows/ columns, because Y and Z are rotated around X.

I also did some more practice on matrix/ matrix and matrix/ vector multiplication. Where in matrix / vector multiplication the X component is only affected by the 1st column of the matrix, Y by the 2nd column etc.

What I assume is that this is correct because the X component will be affected by both the X, Y and Z orientation in the matrix, same for Y and Z component. Is this correct?

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

The real trick is that you need to understand how the type of vector, row or column, dictates how the multiplication happens, and that that affects the layout of your matrix. Then there is the issue of storing a 2d array in a linear buffer, and that's where majorness comes into play. ekba89 cleared the errors in your original post quite well, other then saying row major to describe the vector, when most use that term to describe the layout of a matrix in memory, where I would have said row vectors.

It would have been equally valid to take the other approach, IE that your vector is a column vector, and that multiplication should happen on the right, and that you were wrong in the middle section, but right in saying that the x coordinate is affected by the first row of the matrix. It really depends on the position you take. There are 2 halves to the coin.

In regards to your last question, yes, unless of course if you use an identity matrix, and that should be self explanatory..

Thanks. Here's an example/ one of my practice cases:

matrixtest.jpg

I multiply the X, Y, Z and W component with the first colum of the 4x4 matrix.

For Y I multiply the XYZW components with the 2nd colum of the matrix, etc.

So the resulting new X component, is determined by a multiplicaton of all 'original' vector components with the 1st column of the matrix.

I'm not 100% sure, but I believe directx/3d uses/ expects 'row major' matrices.

And to get for example the seperate axis's, I take the 1st three values of the 1st row for X, 2nd row for Y, 3rd row for Z (containing the rotations/scaling).

This example is a rotation matrix with X rotation is 90%:

matrixtest2.jpg

Where I believe the 1st 3 values of the 1st row, define a vector which I use as 'X axis' (my explanation in dummy: X and Z influence the result, because there's rotation around Y).

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

The first row is the object’s X vector, which points to the right of the object.
The second row is the object’s up vector. In a primitive FPS game this will always be [0,1,0] for a player as the player is always standing upright.
The third row is the object’s Z vector, which points forward in front of the object. It is the direction the object is facing.
The fourth row is the object’s position.

The first row is also scaled by the object’s X scale, and the second and third are scaled by the object’s Y and Z scales respectively.

Code to create a matrix from scratch (the easiest way to understand each component) is as follows:
    /** Creates a matrix from our data. */
    void COrientation::CreateMatrix( CMatrix4x4 &_mRet ) const {
        _mRet._11 = m_vRight.x * m_vScale.x;
        _mRet._12 = m_vRight.y * m_vScale.x;
        _mRet._13 = m_vRight.z * m_vScale.x;
        _mRet._14 = 0.0f;

        _mRet._21 = m_vUp.x * m_vScale.y;
        _mRet._22 = m_vUp.y * m_vScale.y;
        _mRet._23 = m_vUp.z * m_vScale.y;
        _mRet._24 = 0.0f;

        _mRet._31 = m_vForward.x * m_vScale.z;
        _mRet._32 = m_vForward.y * m_vScale.z;
        _mRet._33 = m_vForward.z * m_vScale.z;
        _mRet._34 = 0.0f;

        _mRet._41 = m_vPos.x;
        _mRet._42 = m_vPos.y;
        _mRet._43 = m_vPos.z;
        _mRet._44 = 1.0f;
    }
These are Direct3D matrices.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

The first row is the object’s X vector, which points to the right of the object.
The second row is the object’s up vector. In a primitive FPS game this will always be [0,1,0] for a player as the player is always standing upright.
The third row is the object’s Z vector, which points forward in front of the object. It is the direction the object is facing.
The fourth row is the object’s position.

The first row is also scaled by the object’s X scale, and the second and third are scaled by the object’s Y and Z scales respectively.

Code to create a matrix from scratch (the easiest way to understand each component) is as follows:


    /** Creates a matrix from our data. */
    void COrientation::CreateMatrix( CMatrix4x4 &_mRet ) const {
        _mRet._11 = m_vRight.x * m_vScale.x;
        _mRet._12 = m_vRight.y * m_vScale.x;
        _mRet._13 = m_vRight.z * m_vScale.x;
        _mRet._14 = 0.0f;

        _mRet._21 = m_vUp.x * m_vScale.y;
        _mRet._22 = m_vUp.y * m_vScale.y;
        _mRet._23 = m_vUp.z * m_vScale.y;
        _mRet._24 = 0.0f;

        _mRet._31 = m_vForward.x * m_vScale.z;
        _mRet._32 = m_vForward.y * m_vScale.z;
        _mRet._33 = m_vForward.z * m_vScale.z;
        _mRet._34 = 0.0f;

        _mRet._41 = m_vPos.x;
        _mRet._42 = m_vPos.y;
        _mRet._43 = m_vPos.z;
        _mRet._44 = 1.0f;
    }
These are Direct3D matrices.


L. Spiro

In a left handed system

Thanks, in my case it's a left handed system.

Here's my code of composing a model matrix:


D3DXMATRIX* ComposeD3DXWorldMatrix(D3DXMATRIX *pOut, const D3DXVECTOR3 &pScale, const float pXrot, const float pYrot, const float pZrot, const D3DXVECTOR3 pTranslation)
{
    pOut->m[0][0] = std::cos(pYrot) * std::cos(pZrot) * pScale.x;
    pOut->m[0][1] = std::cos(pYrot) * std::sin(pZrot) * pScale.x;
    pOut->m[0][2] = -std::sin(pYrot) * pScale.x;
    pOut->m[0][3] = 0.0f;

    pOut->m[1][0] = (((std::sin(pXrot) * std::sin(pYrot)) * std::cos(pZrot)) + (std::cos(pXrot) * -std::sin(pZrot))) * pScale.y;
    pOut->m[1][1] = (((std::sin(pXrot) * std::sin(pYrot)) * std::sin(pZrot)) + (std::cos(pXrot) * std::cos(pZrot))) * pScale.y;
    pOut->m[1][2] = std::sin(pXrot) * std::cos(pYrot) * pScale.y;
    pOut->m[1][3] = 0.0f;

    pOut->m[2][0] = (((std::cos(pXrot) * std::sin(pYrot)) * std::cos(pZrot)) + (-std::sin(pXrot) * -std::sin(pZrot))) * pScale.z;
    pOut->m[2][1] = (((std::cos(pXrot) * std::sin(pYrot)) * std::sin(pZrot)) + (-std::sin(pXrot) * std::cos(pZrot))) * pScale.z;
    pOut->m[2][2] = std::cos(pXrot) * std::cos(pYrot) * pScale.z;
    pOut->m[2][3] = 0.0f;

    pOut->m[3][0] = pTranslation.x;
    pOut->m[3][1] = pTranslation.y;
    pOut->m[3][2] = pTranslation.z;
    pOut->m[3][3] = 1.0f;

    return pOut;
}

I also draw it out for understanding:

modelmatrix.jpg

Math is slightly growing on me, luckily rolleyes.gif

For better clarity I could have named 'XYZW'/ XYZW, columns/ row 0 to 3.

I also found out that I can user either the 2 dimensional array for the d3dxmatrix data [ ][ ] or the '_11, _12 etc.' members (_12 would be 1st row, 2nd col).

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Thanks, in my case it's a left handed system.

The math is still the same, regardless, until we get to projection, but x+ to the right is how we visualize a left handed system. (thumb = x, index=y, middle = z), in a right handed system, x points to the left(or we use z- as the forward direction instead of z+), but the same rules apply. Mainly, that a positive rotation along the X axis rotates Y towards Z. and Y rotates z to x, and z rotates x to y.

In a left handed system

In Direct3D period, and indeed row-major matrices period.
Why is there suddenly all this confusion about handedness?
The difference between left-handed and right-handed doesn’t exist until you render something to the screen, in which case the projection matrix is different. Until then, nothing else changes.



Here's my code of composing a model matrix:

Just a note, sin() and cos() are more than expensive. Never call sin() and cos() with the same values repeatedly. Store them to locals and use the locals.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement