PDA

View Full Version : 2 MATRIX, OR NOT 2 MATRIX? That is the question...



dragonworx
07-15-2002, 03:38 PM
Hi - here are my Facts / Assumtions / and finally a Conclusion (which is actually more like a question):

Fact 1) When manipluating the modelview matrix, any verticies subsequently drawn will be transformed to their appropriate world / view / screen destination. Fine.

Assumtion 1) Although it transforms the vertexs, OpenGL does not provide any direct way of returning the world location of any given local vertex after transforming it (for the purpose of collision detection, or other needs) - True?

Assumtion 2) Given that Assumtion 1) is correct, this means that all systems using OpenGL for rendering must still maintian their own Matrix classes for handling their Scene Graph calculations, which would involve knowing the world coord of a local mesh vertex (after model transformations). Ok.

Conclusion 1) I just use OpenGL's perspective transformations alone, and instead of using glRotate() and other model transformations, use my own Matrix class to transform a meshes local vertex coord to it's world space location, then draw it with OpenGL? This way, since I need to have a multiplied matrix ready for the model (to handle collision etc), I might as well compute it per-frame just before passing OpenGL the world coord. Doesn't this save 2 different set's of matrixes doing part of the same stuff?

In Other words) Is is good practice to just use OpenGL's perspective transformations (just to transform world verticies to view space), and use your own matrix to transform your meshes to their world space coords (then draw those world space coords directly), thus eliminating the need to use any subsequent OpenGL model transformations?

- Thanks, it sounds good to me. But what do you guys do?

Junkstyle
07-15-2002, 04:40 PM
The game engine I'm building I have each 3d game object hold its location and orientation along with other things such as velocity. Every frame rendered I go through the typical transformations:

local space -> world space -> viewing space

dragonworx
07-15-2002, 06:20 PM
Cheers <junkstyle>,

but do you mean that:

a) you transform your local verticies using OpenGL's matricies?

or

b) do you transform the local coords with your own matricies, and then draw those transformed world coords with OpenGL?

For example -

- Say that the camera is positioned to be at 15,15,15, looking at 0,0,0.
- We define a cube with -1 -> +1 values.
- We want the cube to be scaled by 5, then rotated around xyz by 45`, then translated up to around 10,10,10.

we could do something like this:

- take the modelview matrix in OpenGL
- scale it
- rotate it
- translate it
- draw the local verticies of the cube (-1 -> +1)

This will draw the cube up in space, rotated, and scaled. That's using OpenGL's matricies.

The other way would be (which is what i feel works just as well):

- take our custom matrix of our model
- scale it
- rotate it
- translate it
- draw the transformed verticies of the cube in world space

This way makes sense to me, since we will retain the matrix that transformed the model for later use, and we are still drawing the vertices transformed to world space.

It's just that the books don't mention this method, they use the modelview matrix to transform the points around, but don't address the fact that you will need to know the actual world coords of those points later in your engine.

Does anyone else use the second method?

- Thanks heaps

ioquan
07-15-2002, 07:05 PM
Use something like the second method, but dont actually calculate the transformed vertices yourself before sending them to OpenGL. Just calculate the matrix, and use glMultMatrix.

The verts I send to OGL are local model verts, but I am not using glRotate, glScale, or glTranslate. Instead, I calculate my own transformation matrix for the model when I do my updates, and I store it. I can use that matrix to transform my verts from local to world at any time. When I am ready to draw, I use one call to glMultMatrixd for each of my objects, using the stored transformation matrix.

[This message has been edited by ioquan (edited 07-15-2002).]

dragonworx
07-15-2002, 09:03 PM
thanks ioquan,

That sounds good. I assume you are using glMultMatrix*() since it may be implemented in hardware, and this would be faster than your own compiled matrix mutiplication? That sounds fair, although the OpenGL1.2 Programming Guide mentions sticking to commands like glRotate*(), instead of using your own matrix manipulation. Personally, I don't see why they have not implemented a local to world function.

Many Matrix implentations I have seen store 16 floats (a11, a12...) to hold their elements. I assume that your matrix is a straight C array of floats? Not multi-dimensional? Do you have an example of your matrix class?

Thanks.

ironhelix
07-15-2002, 09:11 PM
personally, I use GL to do the static stuff, stored in vertex buffers...and objects and such I do the rotations and such myself (you kind of have to with skeletal animation and such)

ioquan
07-15-2002, 11:38 PM
dragon, GL is going to multiply all of your verts by the modelview matrix before it draws them anyway, so there's no point in transforming them yourself first. And dont listen to the stuff about glRotate being faster. glMultMatrix is certainly faster than glRotate, and the creation of your own rotation matrix should not be that expensive. In my case, I HAVE to do rotations independently of gl in the first place, so using glMultMatrix when ready to draw is definitely the fastest way.

My engine is at http://home.earthlink.net/~ioquan

Mezz
07-16-2002, 01:35 AM
Ioquan, I just looked at your engine page, it looks pretty good (like the screenshots).

Also, I don't know if you remember this... but I used to be a mapper for Terratorial Advantage before it was canned. Hehe, I'd forgotton about that until I read it on your 'other projects' page.

-Mezz

ioquan
07-16-2002, 10:58 AM
Cool mezz. What have you been up to lately?

Jambolo
07-16-2002, 12:34 PM
You still need to do the transformation from world space to view space, so you won't save anything by sending world coorinates instead of model coordinates.

In addition, applications generally don't need to know the world coordinates of every vertex.

Junkstyle
07-16-2002, 02:12 PM
Dragon, you sound like you have written a software only engine and are now writing an OpenGL engine. I was in that boat too. You have to figure out where you should stop coding and where OGL picks up the slack.

Here is generally what you do:

1) decide what world location you want the center of your model to be, either a static location or a dynamic one
i.e. calculating your model's location via user input or physics or whatever

2) calculate your model's orientation (rotation). this can be done many ways:
rotation matrices, yaw pitch roll, quaternions, axis and angle

3) send the information you figured out in steps 1 and 2 to OpenGL modelview matrix.
this also can be done in more than one way:

a.) if you have the rotationalMatrix:

glTranslatef(modelLocation.x, modelLocation.y, modelLocation.z);
glMultMatrixf(yourModelsRotationalMatrix);

b.) if you are using 3 axis rotations(x-axis, y-axis, z-axis):

glTranslatef(modelLocation.x, modelLocation.y, modelLocation.z);
glRotate(angleX, 1, 0, 0);
glRotate(angleY, 0, 1, 0);
glRotate(angleZ, 0, 0, 1);

c.) if you have an axis and angle:

glTranslatef(modelLocation.x, modelLocation.y, modelLocation.z);
glRotatef(angle, axis.x, axis.y, axis.z);


I favor method a) myself. Note: in method a) you can work the translation into the 4x4 rotational matrix by using the last column for modelLocation.x, modelLocation.y, modelLocation.z, so you can drop the glTranslate call.

Junkstyle
07-16-2002, 02:19 PM
Dragon, your question about matrices: it doesn't have to be anything fancy. This is what I use:

typedef float matrix4[16];
// 0 4 8 12
// 1 5 9 13
// 2 6 10 14
// 3 7 11 15

This is the way OGL lays out their matrices in memory.

[This message has been edited by Junkstyle (edited 07-16-2002).]

ioquan
07-16-2002, 02:25 PM
Junkstyle, you are failing to recognize that you can put your translation information in with your other transformation data. Why use glTranslate at all? If you calulate a transformation matrix for your object ahead of time, you can put scaling, translation, and rotation information into one matrix, and just use a single call to glMultMatrix.

dragonworx
07-16-2002, 05:00 PM
Thanks guys, much appreciatted...

Your responses have helped me to gain some insight into different experiences.

<Junkstyle>, you are right, I have only written software engines, and I am just begining my OpenGL days. I would just like to get started with simple rendering, and then move into the vertex arrays later (when I define my "real" model and mesh classes properly).

But to get started, I think I will use this method:

- Define my Matrix class as a straight array of [16] elements (thanks <Junkstyle> for the example).
- Define the Translation, Scaling, Rotation sub-matricies and their inverses, which will also store the straight values to the Matrix type as well (eg. An XRotation Matrix will have the "x" degree stored with the prepared Matrix, when you change the "x" rotation of the model, the XRotation Matrix re-calculates it's sin / cos values).
- Create a Transformation class, which is like a collection of Matricies, and their multiplied product.
- Have each Model instance hold a Transformation instance.
- The Transformation class has the following order of Matrix multiplication (uses 6 Matricies):
- Local Pivot (translation), XYZScale, XRotation, YRotation, ZRotation, WorldPosition (translation)
- The Transformation class has an interface to change the raw component values of each of it's 6 Matricies (eg. myModel.transform.xRotation(45) http://www.opengl.org/discussion_boards/ubb/wink.gif
- After setting the OpenGL viewing transformation by using glPerspecitve() & glLookAt(), I would do the following:
1) Set the <>model.transform...> values
2) Tell the model.transform to multiply() (which will multipy the 6 different matricies together into one combined transformation)
3) use glMultiply(model.transform.combinedMatrix) to move the models coords into their world space place (thus multiplying their combined matrix with OpenGL's viewing matrix -> saving the glRotate() & glTranslate() calls)
4) draw the local vertexes (producing the transformed render)

This way, if a model doesn't move (which I'm not saying it wouldn't) then I have a matrix stored within it (via the model.transform.combinedMatrix) which I can multiply local coords (like a local bounding sphere or box) to obtain where those coords would be in world space.

Since glRotate() and glTranslate() etc just multiply a new matrix onto the current, I might as do that in my own engine (so that I can keep the transformation for later), and then use glMultiply() to make sure OpenGL has the right transformation too.

Thanks for your help, it was very useful.

p.s. <ioquan>, I had a look at your site, the engine looks really cool. Good luck with your future projects too.

ioquan
07-16-2002, 06:34 PM
dragon, why have a transformation class? A matrix itself IS a transformation class. You can put ALL of your transformations into a single matrix, including translation, scaling, rotation, and anything else. Once you have the single matrix calculated, you can use it to get absolute coordinates for your models, and you can pass it to glMultMatrix to do the full transformation.
And if you want to be able to have a hierarchy of objects (like one object attached to another) you can just concatenate the child's matrix with the parent's.

Btw, gluLookAt is EVIL. Just make a view class and give it a position and orientation which can act just like the objects in your scene. Then just make your own view transform matrix from the position and orientation. You will be glad you did when you want to start doing interesting things with your camera (and when you want to get rid of those nasty glu libs and dlls).


P.S. I started out doing software engines like you guys. In April I started my first OpenGL engine, which is the one you saw on my page.

[This message has been edited by ioquan (edited 07-16-2002).]

[This message has been edited by ioquan (edited 07-16-2002).]

Junkstyle
07-16-2002, 07:47 PM
ioquan, yes you are correct you can put the translate in that modelview matrix as well so you can drop the gltranslate() call. But I listed that way to be more clear. You didn't read my full post:

"Note: in method a) you can work the translation into the 4x4 rotational matrix by using the last column for modelLocation.x, modelLocation.y, modelLocation.z, so you can drop the glTranslate call."

Junkstyle
07-16-2002, 08:00 PM
Dragon, ioquan speaks the truth--don't make that transformation class. And you don't need to do all those nasty matrix multiplies to make your transformation matrix. I know this is how they explain it in every single graphics book written, but but in practice there are ways around multiplying 6 matrices or whatever you said. If you are actually thinking doing 6 matrices you might as well use the GL functions instead:

glTranslate()
glSscale()
glRotate()

What these GL functions do is actually work on the modelview matrix. Its one big stack of matrices that get all multiplied together. I would actually do it the typical way you see in an opengl book until you get an understanding of the flow of the gl program. Then I'd try to do what ioquan is doing because that is really what you are probably going to end up wanting to do. Also, I'd suggest checking out ioquan's engine.

dragonworx
07-16-2002, 09:36 PM
<Junkstyle>, <ioquan>, I see what you mean, but there IS logic to implementing a transformation class - here's why:

Sure, a single matrix is a collection of transformations, which you can transform points with later - but how do you retain the individual components of those transformations? If you want a model to be rotated the same z-angle as the z-rotation of another model, then you'll need to store some individual rotation values in the model -> like (model.yRotation) or something.

If you're going to do that, then why not define something like this:
--------------------------------------------------------------------------------------------------------------
typedef float matrix4[16];
// 0 4 8 12
// 1 5 9 13
// 2 6 10 14
// 3 7 11 15
// <junkstyles> matrix example...

class Transformation {
// variables
float xLocal, yLocal, zLocal; // models local translation (pivot)
float xScale, yScale, zScale; // models scale
float xRotation, yRotation, zRotation; // models rotation
float xWorldPos, yWorldPos, zWorldPos; // models world position
matrix4 transformation; // 6 combined transformations
// functions
matrix4 multiply(); // produce the 6 combined transformations
};

...
matrix4 Transformation::multiply()
{
// create a translation matrix called (localTranslation)
// create a scaling matrix called (scale)
// create a xrotation matrix called (xrotation)
// create a yrotation matrix called (yrotation)
// create a zrotation matrix called (zrotation)
// create a translation matrix called (worldTranslation)
// return (localTranslation * scale * xrotation * yrotation * zrotation * worldTranslation)
}
...
------------------------------------------------------------------------------------------------------------------------
...Then, instead of using OpenGL's transformations <pseudo snippet>:

// ...set the viewing transformation earlier...
glPushMatrix();
glTranslate(xLocal, yLocal, zLocal);
glScale(xScale, yScale, zScale);
glRotate(xRotation, 1, 0, 0);
glRotate(yRotation, 0, 1, 0);
glRotate(zRotation, 0, 0, 1);
glTranslate(xWorldPos, yWorldPos, zWorldPos);
// ...draw the verticies...
glPopMatrix();

...you could do <pseudo snippet>:

// ...set the viewing transformation earlier...
glPushMatrix();
model.transform.localPosition(xLocal, yLocal, zLocal); // these calls are just simple /
model.transform.scale(xScale, yScale, zScale); // component updates, /
model.transform.rotation(xRotation, yRotation, zRotation); // there is no matrix /
model.transform.worldPosition(xWorldPos, yWorldPos, zWorldPos); // multiplication yet...
model.transform.multiply(); // THIS actually creates a
// composite matrix, of 6
// transformations...
glMultMatrix(model.transform.transformation); // add these transformations to
// the modelview transformation
// ...draw the verticies...
glPopMatrix();

...Basically, a Transformation class is just a wrapper for the individual component values, plus the combined transformation matrix. Each model has a Transformation instance, which allows you to keep track of the model's transformation matrix, plus the actual values which transformed it.

Do you dig it?

BTW. ioquan: how did you load the homer model? What format did you load it from? It looks funky too.

ioquan
07-16-2002, 09:51 PM
If you really need all those individual components of the transformation, then using the transformation class would be a way to do that. However, I think you will find in time that it is not that useful.

Eventually you will run into the gimbal lock problem, and if you've based a lot of your movements on your transformation class, you will have a heck of a time converting to some other orientation system. http://www.opengl.org/discussion_boards/ubb/wink.gif

My models are in the md2 (quake 2) format.

[This message has been edited by ioquan (edited 07-17-2002).]

Mezz
07-17-2002, 02:13 AM
Gimbal lock is highly annoying.

Ioquan, I haven't really been up to alot. I just write some code here and there, do some experiments etc.

I actually wrote an MD2 loader the other day, it's all fine apart from the texturing which for some reason I had to invert the t coordinate on (well, do 1 minus the t coordinate) to get it mapping correctly. I think that was something to do with me loading the skin as a TGA.

-Mezz