Jump to content

  • Log In with Google      Sign In   
  • Create Account

We need your feedback on a survey! Each completed response supports our community and gives you a chance to win a $25 Amazon gift card!


Understanding a (d3dx) model matrix's content


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 cozzie   Members   -  Reputation: 1778

Like
0Likes
Like

Posted 18 April 2014 - 08:33 AM

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?

 

 



Sponsor:

#2 ekba89   Members   -  Reputation: 480

Like
1Likes
Like

Posted 21 April 2014 - 05:55 PM

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.

 



#3 cozzie   Members   -  Reputation: 1778

Like
0Likes
Like

Posted 22 April 2014 - 02:42 PM

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?

#4 Burnt_Fyr   Members   -  Reputation: 1249

Like
0Likes
Like

Posted 22 April 2014 - 03:13 PM

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..



#5 cozzie   Members   -  Reputation: 1778

Like
0Likes
Like

Posted 22 April 2014 - 03:52 PM

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).


Edited by cozzie, 22 April 2014 - 03:54 PM.


#6 L. Spiro   Crossbones+   -  Reputation: 14447

Like
1Likes
Like

Posted 22 April 2014 - 05:45 PM

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

Edited by L. Spiro, 22 April 2014 - 05:46 PM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#7 Burnt_Fyr   Members   -  Reputation: 1249

Like
1Likes
Like

Posted 22 April 2014 - 06:19 PM

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



#8 cozzie   Members   -  Reputation: 1778

Like
0Likes
Like

Posted 23 April 2014 - 01:08 PM

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).


Edited by cozzie, 23 April 2014 - 01:08 PM.


#9 Burnt_Fyr   Members   -  Reputation: 1249

Like
0Likes
Like

Posted 23 April 2014 - 02:53 PM

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.



#10 L. Spiro   Crossbones+   -  Reputation: 14447

Like
0Likes
Like

Posted 23 April 2014 - 02:59 PM

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

Edited by L. Spiro, 23 April 2014 - 03:00 PM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#11 cozzie   Members   -  Reputation: 1778

Like
0Likes
Like

Posted 23 April 2014 - 03:56 PM

Thanks for the hint, I'll do that

#12 Burnt_Fyr   Members   -  Reputation: 1249

Like
0Likes
Like

Posted 25 April 2014 - 09:43 AM

 

The first row is the object’s X vector, which points to the right of the object.

 

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.

Sorry, I maybe should have been more selective in my quote, my previous post outlined my thoughts, but to reiterate, In a RH system,  +x would point to the left, if z+ was our forward vector.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS