• Advertisement
Sign in to follow this  

I need help with matrices

This topic is 1376 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey guys,

I would greatly appreciate any help you can offer me. I'm writing a big Entity/Sprite/Model/Rendering system and I am having the hardest time understanding how to use matrices properly. I guess my main questions is: how can I use only a single matrix per object to define where it is located, how it is rotated, and how it is scaled? Since matrix multiplication is cumulative, I have come to the conclusion that I have no choice but to store a (Vector3D) position, (Quaternion) rotation, and (Vector3D) scale, and then re-calculate the matrix (for rendering) each frame from these values. This seems.... cumbersome and ugly. Is there some way to simply have a Matrix for each object and modify it directly when I call SetPosition(), RotateX(), etc.? I'm not that great with Matrix manipulation, so maybe this is no-brainer, but I can't seem to find any direct answer to this no matter where I search.

 

Side note: This isn't meant to sound rude at all, but please don't suggest that I use SDL or some matrix library. I get that a lot, but I want to make this myself. I just need some help in the right direction. Believe me, I've tried learning this myself, but I learn by example, so reading books explaining matrices just doesn't make it click for me.

 

Thanks in advance!

Share this post


Link to post
Share on other sites
Advertisement

Storing the model-to-world transform as (position, rotation, scale) has advantages (although I would argue that scale should be a single number, or not exist at all). But you can certainly use matrices instead.

 

I am not sure what you are having trouble with, though. To SetPosition, you just modify the "translation vector" part of the affine matrix. To RotateX, you multiply the 3x3 submatrix corresponding to the endomorphism of the vector space (ignore the big words: You probably know perfectly well what 3x3 submatrix I am talking about) by a 3x3 matrix that rotates around the x axis.

 

That probably doesn't help you, but I need to know what you know about how a 4x4 matrix of a special form can be used to encode the transformations you are interested in.

Share this post


Link to post
Share on other sites
Because your input had no meaning in the context of the conversation.
You said you use floats.
Vector3D uses floats.
Quaternion uses floats.
Matrix uses floats.

In other words, everyone uses floats.
Your reply is nonsensical at best, detrimental at worst to anyone who understands it to mean he or she should replace a Vector3D with 3 floats. That is absolutely 100% not the way it “seems to go”.

That is absolutely terrible advice.
What sane person would do that?
Vectors provide encapsulation, simplify the code, and make its intent clearer.

With 3 separate floats you have basically a pool of ungrouped floats rather than a clear separation between rotation values, position values, and scale values.

With 3 separate floats you have to do this:
object->addPos( off_x, off_y, off_z );
instead of this:
object->pos() += off;
Vector3D operators make manipulating code easier and faster.

What if one day you want to add SIMD optimizations to vector operations? Good luck if you just use raw floats everywhere.


That is why I down-voted you. And trust me, as rare as it is that I down-vote, you should take it as a serious hint.


L. Spiro Edited by L. Spiro

Share this post


Link to post
Share on other sites

I think the core question here is, how to directly modify a matrix, instead of storing an additional data for position, rotation, scale and then rebuilding the matrix

 

For this, i'll point you to what i guess is the canonical resource on matrices: http://www.cs.princeton.edu/~gewang/projects/darth/stuff/quat_faq.html

If you look at the breakdown of the matrix composition, M[3][0] M[3][1] M[3][2] holds the translation vector. So, a function to set the position would simply modify these three bits of the matrix.

 

I hope this addresses the question.

Good luck!

Edited by uglybdavis

Share this post


Link to post
Share on other sites

You don't have to recalculate the matrix every frame, only when the position, translation or scale changes.

 

I think that doing operations with only some indexes of the matrix will give you more troubles than solutions, as you say, the transformations are cumulative, so it's not the same to have a rotation of 90° and then a translation, or a rotation of 45° a translation and another rotation of 45°. If you change only some values of a precalculated matrix you'll get something more like the second case when it sounds you want the first case.

Share this post


Link to post
Share on other sites

For the most part you will have to build your matrix each frame unless the object is completely static. The order I build matrices is:

scaling

rotation

position

The scaling is not usually going to change. If your object doesn't change its scale, then you could store that matrix as the object's origin matrix.

The rotation (judging from you post) is done with a quaternion and then you build a matrix from that.... Multiply your scaling matrix by this one.

Position is simply:

matrix(3,0) is x

matrix(3,1) is y

and matrix(3,2) is z

It seems like a lot to do, but matrix math is fast.

 

Another note: If you are using a quaternion for rotation, have that quaternion as part of the structure of your object and make it cumulative.

Share this post


Link to post
Share on other sites


I guess my main questions is: how can I use only a single matrix per object to define where it is located, how it is rotated, and how it is scaled?

You really need to get a well-written book to teach you the basics of linear algebra, especially as it applies to games.  Perhaps "3D Math Primer for Graphics and Game Development", or the math section in "Physics for Game Developers", or many others.

 

All of those values are present in a transformation matrix.

 

A transformation matrix has three "basis vectors", that encode the rotation. It also has a vector showing where it is located. It has a value that can serve as a flag to indicate if something is a point or a vector. 

Share this post


Link to post
Share on other sites

Because your input had no meaning in the context of the conversation

Actually, I disagree. Float instead of vector is an odd (and perhaps uninformed) choice, but Smoker's right that people don't usually store this information in matrix form, and that building the matrix anew each frame is par for the course even if it seems inefficient.

Voting mean down means i,m waiting for an explaination.
So please tell me why vote me down ?

You got voted down here because you have a history of making uneducated or just plane wrong statements, and this particular post lacked sufficient detail and clarity for anyone to see it for anything but that. Post carelessly often enough and people will rightly stop giving you the benefit of the doubt.

Share this post


Link to post
Share on other sites

The others have hinted at this, but I think it needs to be made more clear. A 4x4 matrix can be interpreted as an array of 4 vectors: Right axis, Up axis, Forward axis, and Position. At least, if you use left handed coordinates and row-major matrices like DirectX. Normally we only use x/y/z of each vector, so the last component of each row is 0. Or you can write a 4x3 matrix class.

 

The Right, Up and Forward axes represent both the orientation and the scale, so it's not really practical to "set" those values if they're all mixed up with eachother.

 

Also, it's really only practical to "set" one rotation at a time... e.g. generating a standard Y rotation matrix. But you can apply rotations incrementally, which is the real reason to use a quaternion or matrix instead of euler angles in the first place.

 

So, you can't do exactly what you're wanting, but you can store your orientation and position as a matrix and use incremental rotations, and apply the scale separately. And depending on the game, you may only need a single float for the scale, rather than separate x/y/z scaling.

 

Another thing you can do is use a combination of matrix and one or two euler angles for the orientation. For example, a matrix plus a yaw angle, and by convention never do any yaw rotation in the matrix part. That could be useful in a game like mario kart, where you want the cars to tilt according to the terrain, and the player only has left/right controls (yaw angle), so you only need one that's convenient to read and modify. Set the matrix's up axis to the ground normal, cross product that with the natural forward (0,0,1) to get the right axis, and cross the up and right axes to get the new forward axis. Then generate a yaw matrix from your facing direction and multiply by that, and the car will rotate around the tilted up axis in a similar way to using incremental rotations, while keeping the convenient readability and set-ability of an euler angle for what the player controls apply to.

Share this post


Link to post
Share on other sites


You don't have to recalculate the matrix every frame, only when the position, translation or scale changes.
As a side note, I saw what the Ogre developers were doing a few months ago, they were tuning their codebase to be more cache friendly. They had some structure going to compute the matrices that were modified since the last frame.

 

IIRC, they found out that by disabling the "if(dirty) compute" paths and recomputing everything always, performance improved in quite a few cases by just plain hitting less branches even if the total matrix computations were more.

Share this post


Link to post
Share on other sites

I know you don't want to USE a library, but what is wrong about LEARNING from a library?

 

Grab a copy of GLM and have a look at the way they handle matrix math.

 

The guys who wrote it spent a lot of time and energy optimising their code for various architectures so you can learn a lot from how they approach the problem.

 

Have a look on their support forums and you can get a lot more information as well.

 

Personally I won't use it because of a couple of issues ( and a certain level of arrogance by the developers which annoyed the hell out of me) but I'm not too proud to admit that they did a lot of good stuff here.

 

In my experience the amount of time you spend on matrix math in a game frame on mobile devices is trivial compared to the amount of time pushing polygons.  

Edited by Stainless

Share this post


Link to post
Share on other sites

Not meaning to hijack the thread, but I suspect using matrices would help me too.

 

I have a camera class, it has this simple function to apply it.

//Some weird shit going on here
//Old comment but kept for lols
void Camera::ApplyICam()
{
  glRotatef(-m_rotation.m_xValue*180/PI, 1.0, 0.0, 0.0);
  glRotatef(-m_rotation.m_yValue*180/PI, 0.0, 1.0, 0.0);
  glRotatef(-m_rotation.m_zValue*180/PI, 0.0, 0.0, 1.0);

  glTranslatef(-m_position.m_xValue, 
               -m_position.m_yValue, 
               -m_position.m_zValue);
}

 

 

My object class also stores position and rotation as two 3 dimensional vectors. Using this system I can move my camera and view my objects just fine, the problem comes when I want to rotate the object.

 

Doing a simple initial rotation is easy, I simply set my m_rotate in object, my question is how to rotate my object after this initial rotation. Say we have an aircraft and I want the plane to bank left aka roll anticlockwise along it's central axis by say 15 degrees. I am unsure how to calculate this rotation given that the plane is no longer aligned along one of our axis, it has its own arbitrary axis. Simply put I cannot figure out how I need to alter my initial rotation.

 

Here is part of my code showing the order of transformations

  glLoadIdentity();
  cam->ApplyICam();
  obj->AddRotation(0.0, 0.025, 0.0);
  obj->ApplyTransformations();
  obj->GetMesh()->DrawMesh();
  cam->ApplyICam();

This code correctly draws my object in position, spinning around the y axis by 0.025 per frame. What I want to know is how to make my object bank as described above, no matter how it happens to be rotated at the time.

 

I am sorry for the poor description, I have always had a hard time visualizing these rotations 

Edited by foxcode

Share this post


Link to post
Share on other sites

Not meaning to hijack the thread, but I suspect using matrices would help me too.

 

I have a camera class, it has this simple function to apply it.

//Some weird shit going on here
//Old comment but kept for lols
void Camera::ApplyICam()
{
  glRotatef(-m_rotation.m_xValue*180/PI, 1.0, 0.0, 0.0);
  glRotatef(-m_rotation.m_yValue*180/PI, 0.0, 1.0, 0.0);
  glRotatef(-m_rotation.m_zValue*180/PI, 0.0, 0.0, 1.0);

  glTranslatef(-m_position.m_xValue, 
               -m_position.m_yValue, 
               -m_position.m_zValue);
}

 

 

My object class also stores position and rotation as two 3 dimensional vectors. Using this system I can move my camera and view my objects just fine, the problem comes when I want to rotate the object.

 

Doing a simple initial rotation is easy, I simply set my m_rotate in object, my question is how to rotate my object after this initial rotation. Say we have an aircraft and I want the plane to bank left aka roll anticlockwise along it's central axis by say 15 degrees. I am unsure how to calculate this rotation given that the plane is no longer aligned along one of our axis, it has its own arbitrary axis. Simply put I cannot figure out how I need to alter my initial rotation.

 

Here is part of my code showing the order of transformations

  glLoadIdentity();
  cam->ApplyICam();
  obj->AddRotation(0.0, 0.025, 0.0);
  obj->ApplyTransformations();
  obj->GetMesh()->DrawMesh();
  cam->ApplyICam();

This code correctly draws my object in position, spinning around the y axis by 0.025 per frame. What I want to know is how to make my object bank as described above, no matter how it happens to be rotated at the time.

 

I am sorry for the poor description, I have always had a hard time visualizing these rotations 

This is where you get into "incremental rotations". Store the aircraft's orientation as a matrix (or quaternion), and when the player wants to turn, generate a pitch, yaw or roll matrix with the small angle delta (your 0.025 value) and multiply the orientation by it. So for example a yaw rotation will rotate around the plane's current up axis, modifying the X and Z axes in the process. Then next time you want to do a pitch rotation, it will be around the modified X axis..It doesn't really matter what order you do them in if the player wants to rotate around multiple axes at the same time, since the change is so small each frame.

 

It can be more tricky at first, working with the orientation as a matrix/quaternion rather than angles, but it's actually easier once you get the hang of it. For example, if you want to move the plane forward, just multiply a vector (0,0,speed) by the orientation, and add it to the position.

 

And don't forget to re-normalize/orthogonalize the orientation periodically to correct any numerical accuracy problems that accumulate.

Share this post


Link to post
Share on other sites

The beautiful thing about matrices and quaternions is that the "rotation" is done the same way:

quat:

D3DXQuaternionRotationYawPitchRoll(&qt,y,p,r);

m_objQuat*=qt;//this is the new quaternion

D3DXMatrixQuaternion(&m_orientation,&m_objQuat);//this converts the object's quaternion into an orientation matrix that can be used with rendering

 

******OR********

 

matrix:

D3DXMatrixRotationYawPitchRoll(&mat,y,p,r);

m_orientation*=mat;//this is the new orientation matrix which can be used for rendering

 

 

Take note: the orientation matrix does NOT have translation. This means that it is at the origin, so to render the object using the orientation matrix, you will have to have a "complete" matrix with scaling, rotation, and location.

Share this post


Link to post
Share on other sites

You got voted down here because you have a history of making uneducated or just plane wrong statements,

In other words, "You got voted down because we're used to vote you down." lmao

Edited by TheChubu

Share this post


Link to post
Share on other sites

I know this isn't game specific, and may not be what you're looking for (if it's not, please cheerfully ignore it cool.png ).

 

If you want to really understand matrices, first you need to understand linear algebra (which emcompasses a lot more than matrices, contrary to what many introductory texts might have you believe). This is an absolutely awesome introduction to the subject. I have no idea why it isn't still in print, especially as it was a Dover publication. When I was an undergrad in Rutgers I convinced one of my professors to use it as the textbook for his course when he told me he was looking for one (I probably saved each of his students about $40). As he put it, the textbook they were using was 'bass ackwards', teaching matrix theory first and vector spaces second.

 

The nice things about the book: it doesn't start with matrices but it does get to them - so you don't confuse vector spaces with matrices. Answers to all the exercises and questions (even the true/false ones) are painstakingly detailed in the book so you understand why the answer is what it is. Yes, it's math, but if you're going to work with these things, you may as well understand what the hell you're doing. I can't imagine more knowledge hurting you blink.png

 

From Amazon it's all 3rd party sellers, so "new" is stupidly expensive. Used-Very Good though is about $12 shipped, which is a bit less than it cost originally, IIRC.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement