Jump to content

  • Log In with Google      Sign In   
  • Create Account


I need help with matrices


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
20 replies to this topic

#1 Chaosenemy   Members   -  Reputation: 152

Like
1Likes
Like

Posted 09 April 2014 - 08:03 AM

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!



Sponsor:

#2 Álvaro   Crossbones+   -  Reputation: 11891

Like
0Likes
Like

Posted 09 April 2014 - 08:17 AM

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.



#3 the incredible smoker   Members   -  Reputation: 257

Like
0Likes
Like

Posted 09 April 2014 - 09:11 AM

I also use floats for everything, and in the render function build a matrix from it and render,

maybe you find it ugly, but it seems the way to go.


S T O P   C R I M E !

Visual Pro 2005 C++ DX9 Cubase VST 3.70  Working on : LevelContainer class & LevelEditor


#4 the incredible smoker   Members   -  Reputation: 257

Like
-1Likes
Like

Posted 09 April 2014 - 09:36 AM

Voting mean down means i,m waiting for an explaination.

So please tell me why vote me down ?


Edited by the incredible smoker, 09 April 2014 - 09:37 AM.

S T O P   C R I M E !

Visual Pro 2005 C++ DX9 Cubase VST 3.70  Working on : LevelContainer class & LevelEditor


#5 L. Spiro   Crossbones+   -  Reputation: 12270

Like
2Likes
Like

Posted 09 April 2014 - 09:46 AM

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, 09 April 2014 - 10:52 AM.

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

#6 the incredible smoker   Members   -  Reputation: 257

Like
0Likes
Like

Posted 09 April 2014 - 10:02 AM

floats or vector, i personally have floats, but its about the idea.

I did not tell him he should use floats instead of vector.

 

btw : i am sane.


Edited by the incredible smoker, 09 April 2014 - 10:04 AM.

S T O P   C R I M E !

Visual Pro 2005 C++ DX9 Cubase VST 3.70  Working on : LevelContainer class & LevelEditor


#7 uglybdavis   Members   -  Reputation: 895

Like
1Likes
Like

Posted 09 April 2014 - 10:18 AM

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, 09 April 2014 - 10:20 AM.


#8 DiegoSLTS   Members   -  Reputation: 815

Like
0Likes
Like

Posted 09 April 2014 - 10:48 AM

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.



#9 Hawkblood   Members   -  Reputation: 721

Like
0Likes
Like

Posted 09 April 2014 - 04:53 PM

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.



#10 frob   Moderators   -  Reputation: 18883

Like
3Likes
Like

Posted 09 April 2014 - 05:46 PM


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. 


Check out my personal indie blog at bryanwagstaff.com.

#11 Ravyne   Crossbones+   -  Reputation: 6769

Like
2Likes
Like

Posted 10 April 2014 - 12:26 AM

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.

#12 DekuTree64   Members   -  Reputation: 953

Like
0Likes
Like

Posted 10 April 2014 - 06:21 AM

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.



#13 Alpha_ProgDes   Crossbones+   -  Reputation: 4680

Like
0Likes
Like

Posted 10 April 2014 - 10:11 AM

I'll just drop the article about Matrices here. This author has also made other articles on matrices and quaterions as well.


Beginner in Game Development? Read here.
 
Super Mario Bros clone tutorial written in XNA 4.0 [MonoGame, ANX, and MonoXNA] by Scott Haley
 
If you have found any of the posts helpful, please show your appreciation by clicking the up arrow on those posts Posted Image
 
Spoiler

#14 TheChubu   Crossbones+   -  Reputation: 3710

Like
0Likes
Like

Posted 10 April 2014 - 07:16 PM


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.


"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

 

My journals: dustArtemis ECS framework and Making a Terrain Generator


#15 Stainless   Members   -  Reputation: 670

Like
1Likes
Like

Posted 14 April 2014 - 02:34 AM

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, 14 April 2014 - 02:34 AM.


#16 foxcode   Members   -  Reputation: 232

Like
0Likes
Like

Posted 14 April 2014 - 06:18 AM

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, 14 April 2014 - 06:19 AM.


#17 DekuTree64   Members   -  Reputation: 953

Like
1Likes
Like

Posted 14 April 2014 - 09:20 AM

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.



#18 Hawkblood   Members   -  Reputation: 721

Like
0Likes
Like

Posted 14 April 2014 - 09:36 AM

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.



#19 TheChubu   Crossbones+   -  Reputation: 3710

Like
0Likes
Like

Posted 14 April 2014 - 10:27 AM


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, 14 April 2014 - 10:28 AM.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

 

My journals: dustArtemis ECS framework and Making a Terrain Generator


#20 Hawkblood   Members   -  Reputation: 721

Like
0Likes
Like

Posted 14 April 2014 - 12:55 PM

I've made stupid comments before. It was usually because I wasn't thinking straight or I misread the OP.....






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