Thread: working with rotation matrices

  1. #1
    Registered User
    Join Date
    Feb 2005
    Posts
    61

    working with rotation matrices

    I have a rotation matrices, and I have to do a few things with it.
    If the matrix represents the rotations around three axis,

    1) how do you apply the rotation around 1 axis to another matrix ?
    for example : I want one matrix to have only the y-rotation of the other matrix. For example, when I want a 3rd person camera.

    2) how do you set the rotation around a specific axis to a value. But without touching the rotations around the other axis ?
    For example, when I want a camera to look at a specific height.

    Thanks in advance.

  2. #2
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Basically, the problem is to separate the different rotations of a matrix into rotation around the X-, Y- and Z-axis.

    Here's one way, perhaps not the most efficient there is.

    Take a vector v = (v1,v2,v3) (= (1,1,1) for example), and apply the rotation matrix to it:
    u = (u1,u2,u3) = A*v

    To calculate the X-rotation of A, calculate the angle between the projections of v and u to the YZ-plane.

    v' = (0,v2,v3)
    u' = (0,u2,u3)

    Use v'*u' = |v'||u'|cos a to calculate the angle a, which is the rotation around the X-axis. You'll need to determine if the rotation is negative or positive too.


    1) Use the above method to extract the Y-rotation and create a new matrix.

    2) Extract the rotations and create a new matrix with one rotation changed.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  3. #3
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Construct the X, Y, and Z rotation matrices. Multiply them together (concatenate them). This is your final rotation matrix. Multiply this by the translation matrix. Multiply this by the scaling matrix. This is your world matrix.

    Multiply every vertex by the world matrix. Multiply this by the clip matrix. Multiply this by the view matrix. Multiply this by the projection matrix. Divide all vertices by their w component. Render.

    Yet again I will post the matrices here. These are for Direct3D, left- handed matrices. You will have to change them somewhat for OpenGL. But I should mention some of this is available in our tutorials section.

    Do a search. Read the tutorial on matrices for OpenGL. And you can also go to www.gamedev.net or www.gamasutra.com for very thorough explanations of these matrices, how they work, how to derive them, and why they work.

    X rotation matrix
    1,0,0,0
    0,cos,sin,0
    0,-sin,cos,0
    0,0,0,1

    Y rotaton matrix
    cos,0,-sin,0
    0,1,0,0
    sin,0,cos,0
    0,0,0,1

    Z rotation matrix
    cos,sin,0,0
    -sin,cos,0,0
    0,0,1,0
    0,0,0,1

    Translation matrix
    1,0,0,0
    0,1,0,0
    0,0,1,0
    dx,dy,dz,1

    Scaling matrix
    sx,0,0,0
    0,sy,0,0
    0,0,sz,0
    0,0,0,1

    Identity matrix
    1,0,0,0
    0,1,0,0
    0,0,1,0
    0,0,0,1

    Projection matrix

    Prepares for division by W - does not actually divide by W.

    1,0,0,0
    0,1,0,0
    0,0,1,1/d
    0,0,0,0

    Projection divide - actually divides by W
    [x,y,z,w]=[x/w,y/w,z/w]

    Scale in arbitrary direction

    Scale by factor of k in direction of unit vector n

    S(n,k)=

    1+(k-1)*(n.x*n.x),(k-1)*n.x*n.y,(k-1)*(n.x*n.z)
    (k-1)*n.x*n.y,1+(k-1)*n.y,(k-1)*n.y*n.z
    (k-1)*n.x*n.z,(k-1)*n.y*n.z,1+(k-1)*(n.z*n.z)

    Axis-angle rotation matrix

    Rotate theta radians around unit vector n.

    R(n,theta)=

    (n.x*n.x)*(1-cos)+cos,n.x*n.y*(1-cos)+n.z*sin,n.x*n.z*(1-cos)-n.y*sin
    n.x*n.y*(1-cos)-n.z*sin,(n.y*n.y)*(1-cos)+cos,n.y*n.z*(1-cos)+n.x*sin
    n.x*n.z*(1-cos)+n.y*sin,n.y*n.z*(1-cos)-n.x*sin,(n.z*n.z)*(1-cos)+cos

    Projection onto cardinal axis or plane

    XY plane
    1,0,0
    0,1,0
    0,0,0

    XZ plane
    1,0,0
    0,0,0
    0,0,1

    YZ plane
    0,0,0
    0,1,0
    0,0,1

    Projection onto arbitrary line or plane
    P(n)=S(n,0)

    1-(n.x*n.x),-n.x*n.y,-n.x*n.z
    -n.x*n.y,1-(n.y*n.y),-n.y*n.z
    -n.x*n.z,-n.y*n.z,1-(n.z*n.z)

    Shearing matrices

    Shear by factor of s and t respectively

    XY shear
    1,0,0
    0,1,0
    s,t,1

    XZ shear
    1,0,0
    s,1,t
    0,0,1

    YZ shear
    1,s,t
    0,1,0
    0,0,1

    Reflection

    Reflect about a plane through the origin perpendicular to unit vector n

    1-2*(n.x*n.x),-2*n.x*n.y,-2*n.x*n.z
    -2*n.x*n.y,1-2*(n.y*n.y),-2*n.y*n.z
    -2*n.x*n.z,-2*n.y*n.z,1-2*(n.z*n.z)

    Clip

    winPhysX=winResX*pixPhysX*devResX
    winPhysY=winResY*pixPhysY*devResY

    zoomx=winPhysX
    zoomy=winPhysY

    zoom=1/(tan(fov/2))
    fov=2*atn(1/zoom)

    Projection divide:
    [x,y,z,w]=[x/w,y/w,z/w]

    Direct3D
    zoomx,0,0,0
    0,zoomy,0,0
    0,0,(far/far-near),1
    0,0,(far*near)/(near-far),0

    OpenGL
    zoomx,0,0,0
    0,zoomy,0,0
    0,0,(far+near)/(far-near),1
    0,0,(2*near*far)/(near-far),0

    Transform to screen space

    ScreenX=((ClipX*winResX)/2*ClipW))+winCenterX
    ScreenY=((ClipY*winResY)/2*ClipW))+winCenterY

    Standard lighting

    X - denotes component wise multiply

    Light=Specular+Diffuse+Ambient

    Specular

    V - vector that points towards viewer
    N - surface normal
    L - points towards light source
    R - reflection vector - reflecting l about n
    H - halfway vector between V and L (for Blinn only)

    theta - angle between r and v

    All vectors are unit vectors.

    PhongSpecular=((V dot R)^mGloss)*SourceSpecular X MaterialSpecular

    BlinnSpecular=((N dot H)^mGloss)*SourceSpecular X MaterialSpecular

    Diffuse lighting
    Diffuse=(N dot L)*SourceDiffuse XMaterialDiffuse

    Light attenuation

    (i1/i2)=(d2*d2)/(d1*d1)

    (dmax-d)/(dmax-dmin)

    Final equation:

    Light=i(max(N dot H,0)^mGloss*SourceSpecular XMaterialSpecular+max(N dot L,0)*SourceDiffuse X MaterialDiffuse)+GlobalAmbient X MaterialAmbient

    Fog
    Light=final color of pixel after lighting computation (from above)
    f = fog density
    FogColor=color of fog
    FinalColor=final result of fog computation

    FinalColor=Light+f*(FogColor-Light)


    That should give you enough info to write a small rendering engine with any API and/or use vertex/pixel shaders to do the lighting.

    If you don't want Y rotation included in your rotations, either zero it's members out in the world matrix (set them to identity 0,1,0,0) or don't include the Y rotation in your concatentation. Matrix multiplication or concatenation is cumulative.

    I would highly recommend the book 3D Math Primer for Graphics and Game Development by Fletcher Dunn and Ian Parberry. It is published by WordWare in their Game Math library series and is available at www.amazon.com. All of this information and more is available in that book.

    Please rate this thread or bring it to a mod's attention so they can either sticky it or put it in an easy to find place. I don't want to re-type all that.
    Last edited by VirtualAce; 03-22-2005 at 09:13 AM.

  4. #4
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    Nice work Bubba, just a couple things differ from the way i learned them...

    Y rotaton matrix
    cos,0,sin,0
    0,1,0,0
    -sin,0,cos,0
    0,0,0,1

    Translation matrix
    1,0,0,dx
    0,1,0,dy
    0,0,1,dz
    0,0,0,1

    Projection matrix
    1,0,0,0
    0,1,0,0
    0,0,1,0
    0,0,1/d,0

  5. #5
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    If I understood his question right, he already had a given rotation matrix and he needed to extract the Y-rotation from that matrix. His second problem was that he needed to change the rotation around one axis without changing the other two.
    Quote Originally Posted by Bubba
    That should give you enough info to write a small rendering engine with any API and/or use vertex/pixel shaders to do the lighting.
    What? Just posting matrices and formulas won't help anyone learning anything. Good reference though.
    Last edited by Sang-drax; 03-22-2005 at 10:36 AM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  6. #6
    Registered User
    Join Date
    Mar 2003
    Posts
    580
    I'm just completely confused...he only asked for help with rotation matrices.

    Please rate this thread or bring it to a mod's attention so they can either sticky it or put it in an easy to find place. I don't want to re-type all that.
    *WHY* didn't you type it for a sticky in the first place? 90% of what you posted doesn't belong here dude, no offense.
    Last edited by Darkness; 03-22-2005 at 12:01 PM.
    See you in 13

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I posted it all here even though it's not completely relevant because I'm sick of these types of questions when this information is all over the game programming board, all over www.gamedev.net, www.gamasutra.com, www.google.com, and even in our tutorials section which can be linked to from the main page.

    Anything to do with rotation matrices or any matrices for that matter is somewhere on this board already which means no board search has been done on the topic and also means that google has not been used.

    That's why.

    I'll remove it if need be or perhaps put it in a completely different post so it can be stickied.
    Do a search. This type of matrix question has been asked 10,000 times over.

    1) how do you apply the rotation around 1 axis to another matrix ?
    for example : I want one matrix to have only the y-rotation of the other matrix. For example, when I want a 3rd person camera.

    2) how do you set the rotation around a specific axis to a value. But without touching the rotations around the other axis ?
    For example, when I want a camera to look at a specific height.
    Both of these question lend credence to the fact that the OP does not understand anything about matrix math or concatenation and that being true the OP has no business attempting to rotate anything anywhere. Learn the matrix math first, then you will understand how to use them and how they can be combined and used for transformations. No offense intended at all but you must learn matrix math before you just start plugging and chugging numbers into them.

    Because you stated these questions the way you did, I know you do not understand how they work.

    So to answer the questions:
    1) how do you apply the rotation around 1 axis to another matrix ?
    for example : I want one matrix to have only the y-rotation of the other matrix. For example, when I want a 3rd person camera.
    A 3rd person camera has nothing to do with the Y rotation or whatever it is you are talking about. It has to do with 3 basis vectors - up,look, and right. You rotate using the axis angle rotation matrix to arrive at your final matrix. You use the camera view matrix that we just computed as your view transformation matrix for the entire scene.

    I want one matrix to have only the y-rotation of the other matrix.
    I have no idea what you mean. Matrix math is cumulative. Each result can then be used in a chain of other matrices to produce new results and a new matrix.

    2) how do you set the rotation around a specific axis to a value. But without touching the rotations around the other axis ?
    For example, when I want a camera to look at a specific height.
    Set your rotations by using three variables to represent x,y and z rotations. If you don't want to rotate around the other axes, then set their values to 0.0f and they won't rotate. You are building one rotation matrix from all this, not 3 different ones. When you multiply the three together you are creating one. But most of the time you don't want to multiply the three together - you can also derive an xyz rotation matrix from the information I gave you so that one matrix multiplication will rotate around x,y, z correctly and with no gimbal lock. Height has nothing to do with rotation. Height has to do with the Y value of the camera. The only time that height comes into play is if you are translating the camera away from the origin. The height of the camera then during an X rotation or rotation about the vertical is equal to the sine of the distance you translated from the origin.

    There is also a class for a 3rd person camera on this board. I would recommend buying a book that explains this much better than I can in this small post.
    Last edited by VirtualAce; 03-22-2005 at 01:07 PM.

  8. #8
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    I have to agree with Bubba here, I dont think his post was out of line at all in this case. This is the third question ive seen about the same(ish) thing in about a week. We need full explanations like this to point to so we don't end up answering the same question over and over.

  9. #9
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    One of the things the original poster tried to do was, given a rotation matrix A, extract the rotations around the X- Y- and Z-axis. Perhaps it has no practical use, but it could be seen as a mathematical exercise.

    Here's how to do it (I typed it in MATLAB beause I didn't have a matrix library for C++ available)

    A is a rotation matrix created by matrix multiplication of the X,Y and Z (in that order) rotation matrices.

    Code:
    % 3x3 Rotation matrix A
    %
    % A is created by the rotation matrices
    % A = Ax * Ay * Az
    function [rx,ry,rz] = getRotationXYZ(A)
    
    %Get the X-axis rotation
    v  = [0; 0; 1];
    u  = A * v;
    rx = atan2(u(2),u(3))
    %Remove the X-axis rotation from the matrix
    Ax = [1 0 0;0 cos(rx) sin(rx); 0 -sin(rx) cos(rx)];
    A = Ax' * A;
    %Get the Y-axis rotation
    v  = [1; 0; 0];
    u  = A * v;
    ry = atan2(u(3),u(1))
    %Remove the Y-axis rotation from the matrix
    Ay = [cos(ry) 0 -sin(ry); 0 1 0; sin(ry) 0 cos(ry)];
    A = Ay' * A;
    %Get the Z-axis rotation
    v  = [0; 1; 0];
    u  = A * v;
    rz = atan2(u(1),u(2))
    The atan2 exists in C++ as well. This is perhaps not the most efficient way to do it, but it seems to work very well for the matrices I tried.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  10. #10
    Registered User
    Join Date
    Feb 2005
    Posts
    61
    I posted it all here even though it's not completely relevant because I'm sick of these types of questions when this information is all over the game programming board, all over www.gamedev.net, www.gamasutra.com, www.google.com, and even in our tutorials section which can be linked to from the main page.

    Anything to do with rotation matrices or any matrices for that matter is somewhere on this board already which means no board search has been done on the topic and also means that google has not been used.

    That's why.
    First of all you're wrong here. Before I asked this question here, I've spent more that a day searching for an answer. Maybe I didn't use the right keywords, or something like that, but anyway I didn't find an answer to the two questions I posted. Don't say I didn't try. I did try google, gamedev and this board.

    Secondly, in the two posts you made, you didn't give me an answer to any of my two questions. And no, I don't want to use an already existing camera class. I'm trying to learn everything the hard way by doing it my way.

    Sang-drax :
    Thanks for your answer, that was what I was looking for.

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    First of all you're wrong here. Before I asked this question here, I've spent more that a day searching for an answer. Maybe I didn't use the right keywords, or something like that, but anyway I didn't find an answer to the two questions I posted. Don't say I didn't try. I did try google, gamedev and this board.

    Secondly, in the two posts you made, you didn't give me an answer to any of my two questions. And no, I don't want to use an already existing camera class. I'm trying to learn everything the hard way by doing it my way.
    Extracting rotations from a matrix can be found in any matrix math discussion and the book I mentioned also shows how to do it. If you use atan, acos, or asin it will be deathly slow.
    Search: extracting x,y,z rotations from a matrix
    http://www.google.com/search?sourcei...+from+a+matrix

    6th one down leads you here.

    http://www.idevgames.com/forum/archi...hp/t-5085.html

    Search:matrix math
    http://www.google.com/search?sourcei...&q=matrix+math

    As I said gamedev pops up almost immediately in that search.
    http://www.gamedev.net/reference/art...article877.asp

    A whole day eh?



    The well known tutorial available on this board:
    http://www.cprogramming.com/tutorial/3d/theBasics.html

    Board search: matrix math
    http://cboard.cprogramming.com/searc...earchid=149951

    Board search: rotation matrices
    http://cboard.cprogramming.com/searc...earchid=149951

    I clicked on one of the posts and they led me to about ten other links related to math, 3D rotations, etc.

    Took about 5 min.

  12. #12
    Registered User
    Join Date
    Feb 2005
    Posts
    61
    After reading all those links, and looking at the google searches you provided, I still didn't come up with a useful answer.

    Sang-drax :
    The algorithm you provided works in a few cases, but in many cases it doesn't. I already noticed that the algoritm gives wrong results when y or z is between - (Pi / 2) and (Pi / 2).

    I could solve this if I knew if the angles lie either
    between 0 and Pi / 2 or
    between Pi / 2 and PI or
    between - (Pi / 2) and 0 or
    between Pi and - (Pi / 2)

    I tried for more than an hour on paper, but I didn't find how to do it.

  13. #13
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    The original questions you asked are not difficult and can be accomplished with simple matrix mathematics. Perhaps you ought to explain in more detail what it is exactly you need to do.

    I have first person camera classes up and running without gimbal lock issues and that adjust for ground objects and flying objects. I can also point the camera at any spot in 3D space, hence I can do flyby views, etc. The camera can rotate and move around/on any axis you choose.

  14. #14
    Registered User
    Join Date
    Feb 2005
    Posts
    61
    I'll try to explain clear what exactly I want to do.

    I want to be able to break up a rotation matrix into 3 matrices.
    So, if R is given, I want to get RX, RY, and RZ.

    I need to do this because I want my camera to follow the object that I move. To position the camera well, I use the following code :
    cam->posx = object->posx - object->rot[2] * 5.0f;
    cam->posz = object->posz + object->rot[10] * 5.0f;

    So what I do is position the camera 5 units behind the object.

    For giving the camera the correct rotation, I want to give it the same rotation around the y-axis. So if I rotate my object around the x-axis, I don't want my camera to rotate around the x-axis too. Same for z.

    Another thing I want to do is to look at my object from preset views. I want to let the 'player' be able to choose from these presets. What I need to do for that is adjust the height of the camera, and its rotation arount the x-axis. So what I want to do is to let the camera keep its rotation around the y( and z )-axis, but set its x-rotation value to for example 40 degrees.

    I hope I explained it clearly now.

    edit : btw, the algoritm that sang-drax gave to split the rotation matrix into 3 matrices works well, except that I need to know for each angle if it lies :
    between 0 and Pi / 2 or
    between Pi / 2 and PI or
    between - (Pi / 2) and 0 or
    between Pi and - (Pi / 2)
    Last edited by hannibar; 03-23-2005 at 04:45 PM.

  15. #15
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well if you start with a rotation matrix with all the values in it, I'm almost positive that rotation can be inverted. Take the inverse of the matrices you want to 'remove' from the final matrix and multiply the final matrix by these matrices. This will get you back to the original matrices.

    Also you could use a matrix stack. Put each rotation in a separate matrix, like X,Y and Z. When you multiply one matrix by another, push the resulting matrix onto a stack. To effectively undo the previous concatentation you only need to pop the stack to arrive at your original matrix or the previous matrix in the chain.

    But your real problem is that you are approaching the problem the wrong way. You don't need to orient your camera using 3 separate distinct rotations. At best this will result in huge gimbal lock, and at worst it will completely fall apart. I will show you some code from my camera class to illustrate.

    Code:
    void Camera::pitch(float angle)
    {
    	
    	D3DXMATRIX T;
    	D3DXMatrixRotationAxis(&T, &_right,	angle);
    
    	// rotate _up and _look around _right vector
    	D3DXVec3TransformCoord(&_up,&_up, &T);
    	D3DXVec3TransformCoord(&_look,&_look, &T);
    }
    
    void Camera::yaw(float angle)
    {
    	D3DXMATRIX T;
    
    	// rotate around world y (0, 1, 0) always for land object
    	if( _cameraType == LANDOBJECT )
    		D3DXMatrixRotationY(&T, angle);
    
    	// rotate around own up vector for aircraft
    	if( _cameraType == AIRCRAFT )
    		D3DXMatrixRotationAxis(&T, &_up, angle);
    
    	// rotate _right and _look around _up or y-axis
    	D3DXVec3TransformCoord(&_right,&_right, &T);
    	D3DXVec3TransformCoord(&_look,&_look, &T);
    }
    
    void Camera::roll(float angle)
    {
    	// only roll for aircraft type
    	if( _cameraType == AIRCRAFT )
    	{
    		D3DXMATRIX T;
    		D3DXMatrixRotationAxis(&T, &_look,	angle);
    
    		// rotate _up and _right around _look vector
    		D3DXVec3TransformCoord(&_right,&_right, &T);
    		D3DXVec3TransformCoord(&_up,&_up, &T);
    	}
    }
    
    void Camera::getViewMatrix(D3DXMATRIX* V)
    {
    	// Keep camera's axes orthogonal to eachother
    	D3DXVec3Normalize(&_look, &_look);
    
    	D3DXVec3Cross(&_up, &_look, &_right);
    	D3DXVec3Normalize(&_up, &_up);
    
    	D3DXVec3Cross(&_right, &_up, &_look);
    	D3DXVec3Normalize(&_right, &_right);
    
    	// Build the view matrix:
    	float x = -D3DXVec3Dot(&_right, &_pos);
    	float y = -D3DXVec3Dot(&_up, &_pos);
    	float z = -D3DXVec3Dot(&_look, &_pos);
    
    	(*V)(0,0) = _right.x; (*V)(0, 1) = _up.x; (*V)(0, 2) = _look.x; (*V)(0, 3) = 0.0f;
    	(*V)(1,0) = _right.y; (*V)(1, 1) = _up.y; (*V)(1, 2) = _look.y; (*V)(1, 3) = 0.0f;
    	(*V)(2,0) = _right.z; (*V)(2, 1) = _up.z; (*V)(2, 2) = _look.z; (*V)(2, 3) = 0.0f;
    	(*V)(3,0) = x;        (*V)(3, 1) = y;     (*V)(3, 2) = z;       (*V)(3, 3) = 1.0f;
    }
    I took most of this from a camera class sample in one of my books, Introduction to 3D Game Programming with DirectX9 by Frank Luna.

    This camera class works very well and I saw no reason to change it so I learned the how and why of the class and then changed some names to suit my needs. It's a very good class and I think the yaw, pitch, and roll functions will help you a lot.

    D3DXVec3TransformCoord simply multiplies a vector by a matrix or transforms a vector using a matrix. D3DXMatrixRotationAxis simply constructs an axis-angle rotation matrix, which already has been supplied to you in this thread.

    Even though this class does not suffer from gimbal lock, it would be much better if it used quaternions...which might be what you are looking for. Euler angles are great except that they cannot be easily interpolated. Quaternions solve this and allow for smooth interpolation from one 3D orientation to another.

    Here are my 3 basis vectors:

    1,0,0 - right vector
    0,1,0 - up vector
    0,0,1 - look vector
    Last edited by VirtualAce; 03-24-2005 at 08:06 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. camera rotation matrix
    By Vick jr in forum Game Programming
    Replies: 5
    Last Post: 05-26-2009, 08:16 AM
  2. Replies: 8
    Last Post: 05-07-2009, 11:31 AM
  3. one final problem with rotation
    By DavidP in forum Game Programming
    Replies: 3
    Last Post: 11-19-2003, 03:50 AM
  4. 90 Degree Rotation Blt
    By Unregistered in forum Windows Programming
    Replies: 1
    Last Post: 04-08-2002, 07:05 PM
  5. saving contents of a function
    By speve in forum C Programming
    Replies: 5
    Last Post: 01-05-2002, 08:38 PM