Jump to content
  • Advertisement
Sign in to follow this  
jujumbura

Is a matrix the all purpose object space data type?

This topic is 4813 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

Good evening folks, I've learned about a variety of data types that are used in 3D math thus far, and as I experiment, I use them in different places depending on what my task is. I use vectors, quaternions, angles, and matrices. But the more I think about it, for the basic orientation and location of an object in 3D space, is there anything that beats a matrix? Here's my thinking. I can extract any spacial data I want out of this thing: facing direction, position and scale. What else do I need? And, it accurately maintains a history of all rotations done to it in all three directions like a quaternion. The only thing I can think of that it DOESN'T do is interpolate well, but isn't SLERPing really only useful for bone structures in meshes and the like? I'm just talking about WHOLE OBJECT orientation. So I'm considering tossing out my variables that maintain coordinates, quaternions and vectors, and just using a matrix with get'ers and set'ers to handle interaction with the object. Is this foolish? Have many a young aspiring programmer made this same mistake? Please enlighten me if you know of some pitfalls. Thanks as always, jujumbura

Share this post


Link to post
Share on other sites
Advertisement
Storing cumulative operations in a matrix is problematic since rounding errors may creep in. This can introduce skewing, weird scaling or (in at least one instance in code I wrote) an object turning itself inside out.

Share this post


Link to post
Share on other sites
I don't know that there's any one right answer, except perhaps to use the best tool for the job at hand. Here are a few random things to consider, some or all of which you may already know:

1. Currently at least, graphics APIs work with 4x4 homogenous matrices, a possible argument for using that as your basic representation.

2. As sicrane noted, cumulative rotation introduces error. This is true whether you use matrices or quaternions. An advantage of quaternions is that it's a little cheaper to correct the error than with a matrix. But, matrix orthogonalization isn't that expensive to begin with.

3. Conversions between one representation and another probably won't be your bottleneck, so using quaternions or whatever internally and converting to a matrix when necessary is a reasonable option.

4. You can slerp rotation matrices; it's just considerably more expensive than the quaternion form.

5. You can probably squad matrices also, but I haven't worked through the derivation. Again, it'll be quite a bit more expensive than doing it with quaternions.

6. When it comes to networking, representation size becomes important. In this case you'll probably have to convert to a quaternion or some more compact representation. So, use a quat and convert to a matrix for rendering? Or use a matrix and convert to a quat for the network? As you can see, you may end up doing conversions no matter what.

7. Slerp can be useful for other things, such as orienting an object toward a target or over a surface over a certain number of frames. Whether you use quats or matrices, it's a handy thing to have available.

8. Euler angles are good for situations where you only need two angles, such as an FPS character or gun turret, sending orientation over the net, and intuitive user interface. They are bad for objects with arbitrary orientations, such as spaceships or 6dof cameras, or for objects in a physics simulation. IMO they shouldn't be a first choice by default.

9. Affine transformation matrices have one row or column always set to [0 0 0 1], so people often write 'transform' classes which omit these unused elements. They of course have to be re-introduced for interface with the API, so again there's some conversion involved.

Representation of object parameters, and especially orientation, is a big topic, and I only touched on a few things in this post. Feel free to ask any follow-up questions you may have, though.

Share this post


Link to post
Share on other sites
Thanks for the input guys.

Matrix orthonogolization? What exactly does that mean? I know that orthonormal vectors are vectors whose unit length is 1(and converting arbitrary vectors to orthonormal is pretty straightforward), is this similar to that? What are the rounding errors that creep in for matrix rotations, and how does this proccess correct them?

jujumbura

Share this post


Link to post
Share on other sites
Quote:
Matrix orthonogolization? What exactly does that mean? I know that orthonormal vectors are vectors whose unit length is 1(and converting arbitrary vectors to orthonormal is pretty straightforward), is this similar to that? What are the rounding errors that creep in for matrix rotations, and how does this proccess correct them?
The difference between the terms orthogonal and orthonormal, and how they are applied to bases and matrices, can be a little confusing. I don't have a background in math, so although I think I understand the difference, I won't try to explain it here for fear of messing something up. Suffice to say that the rows and column of an orthogonal matrix form an orthonormal basis. So, orthogonalizing a rotation matrix is equivalent to making the vectors of the basis that it represents orthonormal.

I don't know how much you know about floating-point math, but in short, it's pretty much always an approximation of the 'real thing'. That is, the result of any floating-point operation is an approximation of the actual answer. In a perfect world, any rotation that you applied to an orthonormal basis would result in another basis that was also orthonormal. In practice, after a rotation is applied, the basis is likely to be a little 'less' orthonormal than it used to be. This can build up over time resulting in noticable error or even complete failure of the system.

There are several techniques for making a basis orthonormal, but usually you don't need to deal with the fancier ones. It usually suffices to normalize one of the vectors, make another the normalized cross product of that one and the third, and then make the third the cross product of the first two. So, only two sqrts() required, and all in all really not that much more expensive than normalizing a quaternion.

Share this post


Link to post
Share on other sites
Whoa.

Ok, I'm a little confused. I'm using 4x4 Matrices, but in your orthogonal example, were you referring to 3x3 Matrices? I only counted 3 total "normalizations" of the basis vectors. Perhaps I don't understand what you mean by basis; I thought it meant the four vectors which make up the columns of your matrix?

If I'm right about the basis being the four vectors which make up the matrix columns, then how could I normalize them without losing data? Removing the magnitude would influence things like the scale factor and the translations, wouldn't it?

Or, are you suggesting that I keep two matrices: one that stays as-is to represent translation and scaling, and another to represent rotation that is safe to normalize after making changes?

Thanks much,
jujumbura

Share this post


Link to post
Share on other sites
Quote:
Ok, I'm a little confused. I'm using 4x4 Matrices, but in your orthogonal example, were you referring to 3x3 Matrices? I only counted 3 total "normalizations" of the basis vectors. Perhaps I don't understand what you mean by basis; I thought it meant the four vectors which make up the columns of your matrix?

If I'm right about the basis being the four vectors which make up the matrix columns, then how could I normalize them without losing data? Removing the magnitude would influence things like the scale factor and the translations, wouldn't it?

Or, are you suggesting that I keep two matrices: one that stays as-is to represent translation and scaling, and another to represent rotation that is safe to normalize after making changes?
Right, let me clarify. Orthonormality is only a desirable property for the 3x3 rotation matrix. So, if you were storing position and orientation as a vector and a 3x3 matrix, respectively, you would keep your basis orthonormal by orthogonalizing your matrix occasionally. If you're using a 4x4 homogenous matrix, then you would only apply the aforementioned orthogonalization algorithm to the upper-left 3x3 portion. If the matrix contains scale information as well, there might be ways to update the rotation incrementally without disturbing the scale information, but I don't know that it's typically done that way. In any case, you are correct that orthogonalization will overwrite any scaling or shear.

if you're using scale, shear, or other linear transformation in addition to rotation, you'll probably want to store things separately and compose them into a matrix when necessary. The rotation could be a quaternion, a 3x3 matrix, an Euler angle double or triple, or whatever else suits you. Scale and translation would obviously be 3d vectors, or a single scalar for scale if you're only concerned with uniform scale. If you're worried about the cost of assembling these into a 4x4 matrix, it can be done quite a bit more cheaply than the naive method due to the a priori knowledge of the matrix contents.

Don't consider the above to be the last word on the subject. I haven't given much thought to keeping all possible transformations in a single matrix and updating said matrix incrementally, so I can't say that it couldn't or shouldn't be done that way. But, I don't recall having ever seen it done that way.

Let me know if there's any further clarification I can offer.

Share this post


Link to post
Share on other sites
Ahh, thank you. I'd forgotten that the rotation portion is only the upper left 9 numbers. That all makes sense.

But now I'm kinda back where I started. Currently I store the various data representing scaling, translation, and rotation as different types, and then I make a composite matrix of all the different transformations at the end.

The reason I was interested in storing all this as a single matrix is motion. During each physics timestep, I move the object based on its velocity and its facing direction. To get the facing direction, I transform the quaternion into a matrix, and then I extract the _31, _32 and _33 components to get my facing direction. I normalize, multiply by my velocity, and then add that vector to my position. Once I'm done updating physics between Render()s, I use all my spacial data to compose another matrix which I use to transform my world coordinates.

So I guess I was thinking "gee, why am I pulling this quaternion out into a matrix and storing spacial coordinates for each timestep when I could just leave it all in a matrix that the Render() function will need eventually anyway?" Is converting a quaternion to a matrix for every object that needs to be moved along a facing direction per timestep really that cheap? Or is there just a TOTALLY better way to do this?

This is what I'm wrestling with anyhow.

Share this post


Link to post
Share on other sites
You bring up some interesting points. I don't have an 'authoratative' answer, but here are some thoughts based on my own experiences.

I noticed that in your last post you mentioned normalizing the direction vector after extracting it from the matrix. If your quaternion is unit-length, and your quat-to-matrix code is correct, this step shouldn't be necessary as the basis vectors should be unit-length to begin with. A small thing, but perhaps significant since you're concerned about performance.

The next thing I'll mention is that if you only need one of the basis vectors (say, forward), there's no need to extract all three from the quaternion; you can get whichever one you need directly from the quaternion simply by isolating the appropriate part of the quat-to-matrix code. However, if you're going to need all three basis vectors on a regular basis, such as for strafing, moving up and down, or rendering, you might as well convert the quat to a matrix whenever the quat is updated.

It sounds like you're using scaling at the rendering stage, presumably for resizing your models. If this is the case, I don't know that it's particularly practical to try to keep everything together and update it incrementally. As I mentioned in an earlier post, there may be ways to do this, but I think it'd be kind of a pain.

This may not be the answer you're looking for, and this is IMHO, but it may matter less than you think which representation you choose. There are many pros and cons for just about any choice you could make, so it really just depends on your priorities. How important to you is networking? Interpolation of rotation? Interoperability with a physics engine or numerical integrator? Compatibility with a specific API? Ease of implementation? Performance and efficiency? Clarity to other programmers? And so on. Given the answers to all these questions one might be able to make a more or less 'objective' recommendation, but even then I think there'd be at least a little 'IMO' involved ;-)

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!