PDA

View Full Version : Deciphering OpenGL's ModelView Matrix



BradlyP
12-02-2000, 09:51 PM
Hello,
OK, we all know that OGL stores it's matricies in arrays like this



[0] [4] [8] [12]
[1] [5] [9] [13]
[2] [6] [10] [14]
[3] [7] [11] [15]

Where the numbers in brackets are the indicies into the array. The part I'm confused about is that I thought this was the standard arangement for a transformation matrix:



ix iy iz X
jx jy jz Y
kx ky kz Z
0 0 0 1

Where <ix, iy, iz> is the i vector (the local x axis), <jx, jy, jz> is the j vector (local y axis), <kx, ky, kz> is the k vector (can you guess?) and the point (X, Y, Z) is the location of the local coordinate system in the global coordinante system. So, using these two pieces of info, I'd expect OGL's modelview matrix to be constructed like this:



[0]ix [4]iy [8] iz [12]X
[1]jx [5]jy [9] jz [13]Y
[2]kx [6]ky [10]kz [14]Z
[3] 0 [7] 0 [11] 0 [15]1

But my first try at using my j <[1],[5],[9]> and k <[2],[6],[10]>vectors with gluLookAt() was unsuccessful. I couldn't figure it out, so I just tried something I didn't think would work, and it did! I used <[4],[5],[6]> for my j matrix and <[8],[9],[10]> for my k matrix. So it seems, from experimentation, that OGL stores the ModelView matrix like this:



[0]ix [4]jx [8] kx [12]X
[1]iy [5]jy [9] ky [13]Y
[2]iz [6]jz [10]kz [14]Z
[3] 0 [7] 0 [11] 0 [15]1

Is this correct? If so, I assume the other matricies are also stored like this... is that the case?

Thanks,
-BradlyP

[This message has been edited by BradlyP (edited 12-03-2000).]

Michael Steinberg
12-03-2000, 09:38 AM
From what I saw, it is wrong. If I take the 3rd line as a vector (only the first three elements of course) and rotate the "matrix" around it (so, only the axises), it looks like one would roll. So, the local z axis, what you call k, is for me in the 3rd row. For the other axes applies the same, respectively.
I'm not sure, but I think, the axises have to be normalized.

Michael Steinberg
12-03-2000, 09:40 AM
Reread your post. Seems funny to me. Could you mail me the code and I'll have a look at it.

Elixer
12-03-2000, 12:38 PM
Oops, took out wrong info. http://www.opengl.org/discussion_boards/ubb/redface.gif


the other info is ok though.




[This message has been edited by Elixer (edited 01-12-2001).]

Succinct
12-03-2000, 11:04 PM
You're right, Elixir. OGL's matrices are... i forget which is which. one is Row dominant, the other is column dominant (the other being the math books), but yes, ogl is the wrong one http://www.opengl.org/discussion_boards/ubb/wink.gif

like said, you have to use it as float[16], not [4][4], and enumerate them as he showed.

wierd stuff, huh?

http://www.opengl.org/discussion_boards/ubb/wink.gif
tt4n

Nutty
12-04-2000, 12:06 AM
Just as a side note, I use this for my openGL matrices.

typedef struct {

Vector3 right;
float pad_0;
Vector3 up;
float pad_1;
Vector3 at;
float pad_2;
Vector3 pos;
float pad_3;
}__struc_Matrix;

works fine for me to just load it directly into the modelview matrix.

cheers,
Nutty.

Punchey
12-04-2000, 07:33 AM
How in the world does loading this structure into the modelview matrix work? Doesn't it have to be float[16]?

Nutty
12-04-2000, 08:02 AM
That structure is the same size as a float[16]. Each Vector3 has 3 floats in it, and 4 pads, gives 16 floats.

It just allows me to extract information out of it really easy. eg. if I want an objects position, I just use the pos vector of the matrix. dead easy!

I also union it with a float[16] array so I can access it that way too.

Nutty http://www.opengl.org/discussion_boards/ubb/cool.gif

Elixer
12-04-2000, 11:17 AM
Hey Nutty, that is well... Nutty! http://www.opengl.org/discussion_boards/ubb/smile.gif I would have never thought of doing it that way.

Learn something new everyday I guess. http://www.opengl.org/discussion_boards/ubb/biggrin.gif

Now if only I can get my wavefront loader to work correctly, I'll be happy. http://www.opengl.org/discussion_boards/ubb/smile.gif

Punchey
12-04-2000, 11:23 AM
Well, Nutty, you're the _MAN_!!! This is a GREAT idea! I'm going to put it to use IMMEADIATELY! Did you come up with this idea yourself?

Michael Steinberg
12-04-2000, 11:29 AM
Remember to set the packing of structures' variables to bytewise. I had this problem one time when I had a structure that should have the size of x bytes (from the components), but between the components was a little space, wich made serious problems.

Punchey
12-04-2000, 11:53 AM
How would you go about setting that in MSVC++?

Michael Steinberg
12-04-2000, 12:10 PM
It was something with

#pragma( *PACK*, 1 )

I think. It's been a long time. Afterwards I sticked loading the array element per element out of the file, which looked cleaner to me than doing something possibly compiler-specific.

Michael Steinberg
12-04-2000, 12:12 PM
Oh, and because of that, I would prefer to still work in the matrix rows not in any vectors or elements that are "layed" over the actual matrix.

Kilam Malik
12-04-2000, 08:44 PM
If you use C++ classes for matrices, vectors etc. then write a constructor for your matrix which accepts a float array. Then you can convert the matrix in your own data format and work with it in the way you does with other matrices.

Nutty
12-04-2000, 11:59 PM
No Punchey, I found the idea in our last project we worked on. I think it might have been in a Renderware header file. I just adapted it to OpenGL's matrix format.

On the subject of packing, all the elements are 4 byte floats, so I wouldn't assume the compiler would insert any extra padding into it. However if you think it might you can always tell the compiler to not pad the structure.

Another great thing is that suppose you want to strafe your character. All you do is add or subtract a scaled amount of the right vector to the position! http://www.opengl.org/discussion_boards/ubb/cool.gif

Top stuff indeed!

I'm not sure about the 4th element in each row. Should this always be 0, in OpenGL's matrix, and 1 for element [3][3]. What happens if you chnage them. (They're the padding floats in my structure)

Nutty

Punchey
12-05-2000, 05:49 AM
First, I'm not all that familiar with compiler options, so how would you tell the compiler to not pad your structure? BTW, I don't see how (or why) it could be throwing stuff into your structure because that would totally mess you up with file I/O. I've relied for years on the fact that I can create something in C/C++ and then just dump it to disk and then just read that number of bytes back from disk to re-populate a structure. Unless there's something else going on that I'm not aware of, it looks to me like what you put in a structure is how many bytes the structure is. Period. After all, when you use malloc or memcpy or something like that, you're allocating the number of bytes it takes to make that structure and nothing more... AFAIK.

On another note, as Nutty mentioned, does anyone out there have a comprehensive definitions of all the elements of an OpenGL array? I am also wondering what [15] which is usually 1 and [3],[7], and [11] which are usually 0. Wait a minute, I don't know about the others, but I think I remember someone telling me that [15] is a scalar value? Would this represent the scale of the coordinate system being used? Or am I way out in left field here?

Deiussum
12-05-2000, 06:19 AM
Originally posted by Punchey:
nothing more... AFAIK.
On another note, as Nutty mentioned, does anyone out there have a comprehensive definitions of all the elements of an OpenGL array? I am also wondering what [15] which is usually 1 and [3],[7], and [11] which are usually 0. Wait a minute, I don't know about the others, but I think I remember someone telling me that [15] is a scalar value? Would this represent the scale of the coordinate system being used? Or am I way out in left field here?

First of all, let me say that my linear algebra knowledge is next to 0. What I know is basically limited to some things I picked up in a graphics class so my explanation below might not be completely accurate.

Those 0,0,0,1 elements are just to fill out a 4x4 matrix, I believe. In mathematical terms you could use a 4x3 matrix like so..

A11 A12 A13 A14
A21 A22 A23 A24
A31 A32 A33 A34

The above matrix would be perfectly valid for doing various transformations with. The last row is added as 0 0 0 1 in order to make the matrix multiplication nice and so that an identity matrix can be defined.

From your results, it appears that what is typically in the right colum of the matrix is actually on the bottom of an OpenGL matrix, so it seems reasonable that what is usually on the botton of a matrix would be the right colum of an OpenGL matrx.

Punchey
12-05-2000, 07:04 AM
Actually, it is impossible (AFAIK) to multiply two matrices without one matrix having the same number of columns as the other matrix has rows. Basically because you multiply the rows of one matrix with the columns of the other matrix. Which would cause me to think that, at some point, those bottom values are going to get multiplied with some other meaningful values (I can't say which because I don't know the order and direction OpenGL uses). But, then again, I don't really fully understand it myself.

12-05-2000, 08:04 AM
Hello all, I'm very new to the whole idea of OpenGL programming, but I do have some Linear Algebra experience, and will attempt to shed some light on your confusion. Please don't take anything I say here as final truth, I definitely do not have all of the answers to this problem!
Anyways, from what you all say about the modelview matrix tells me that if you wrote out a matrix in "standard" form i.e. like the math books:

a11 a12 a13 0
a21 a22 a23 0
a31 a32 a33 0
a41 a42 a43 1

where the rows are your vectors and the last column is there to flesh out the 4x4 so that you could indeed use it with an identity matrix or take it's determinant etc. If you took the transpose of this matrix you would get:

a11 a21 a31 a41
a12 a22 a32 a42
a13 a23 a33 a43
0 0 0 1

which, if i understand what you are all saying correctly, would be the proper form for the matrix in OGL, with each column being a vector.

Now with vectors that have only 3 fields in them (x, y, z) then you'd have to add on a zero to the end in order to be able to multiply it with the matrix described above. Some concern was expressed about the last row of zeros creating a problem, this shouldn't be the case. A quick little bit of info on matrix math, matrices can only be multiplied if the number of columns on the first matrix is equal to the number of rows on the second matrix, this was stated by someone earlier in this thread. i.e. our 4x4 matrix needs a 4x1 matrix to multiply with. If you have your vector (x,y,z) with a zero on the end so that it will multiply (x,y,z,0), and then transpose it as well, it will give you this 4x1 matrix and all will be well.

[a11 a21 a31 a41] [x] [x']
[a12 a22 a32 a42] X [y] = [y']
[a13 a23 a33 a43] [z] [z']
[0 0 0 1 ] [0] [0 ]

Thus your concern about the bottom row of zeros, while warranted, is unneccessary. That last row says: (0*x + 0*y + 0*z + 0*1) thus it all adds up to zero and gives you the fourth element in the resulting 4x1 matrix.

I hope this has helped with any confusion and that I haven't confused anyone more than they were before reading this.

-Spline

12-05-2000, 08:06 AM
Grr...sorry everyone about the messed up formatting in the above post, It looked nice before i sent it http://www.opengl.org/discussion_boards/ubb/wink.gif All of my spaces were yanked out, I hope you can still follow it...

-Spline

Punchey
12-05-2000, 08:31 AM
So, as I suspected but wasn't sure, you're saying that the 0,0,0,1 part of the matrix is just there so it'll multiply properly but doesn't hold useful information for anything as far as determining things such as an object's orientation in the universe etc.? So will this row of values always be 0,0,0,1? Will there EVER be a need to check these values or do we simply not care about them at all?

[This message has been edited by Punchey (edited 12-05-2000).]

Elixer
12-05-2000, 08:58 AM
If we got
1000
0100
0010
0001
That is the idenity matrix.
Now, the last coloum [0,0,0,1] is only used for operations that require shear, shrink, and stuff like that. So normally, that coloum is not used.
the first row is Xx,Xy,Xz, 2nd is Yx,Yy,Yz, and 3rd is Zx,Zy,Zz. the 4th row is the local coordinates that I said above.
So in effect, you have:
Xx Xy Xz 0
Yx Yy Yz 0
Zx Zy Zz 0
lx ly lz 1
and if you have scale/shrink/shear whatever, that is the last coloum.

I think that is correct anyway. http://www.opengl.org/discussion_boards/ubb/smile.gif

Punchey
12-05-2000, 10:12 AM
Okay, that sounds like what I've heard before about the 1 ([15]) being a scalar value. So for the purposes of selecting intuitive names for the members of a structure like Nutty created, does anyone know the actual functions of the elements in that last row? Or in other words, instead of just calling each element something like "pad1", what would be an appropriate and intuitive name to give them that would correspond to their meaning?

Elixer
12-05-2000, 03:46 PM
The last row is the local coords of the object.
so you can call it localX localY localZ or whatever. http://www.opengl.org/discussion_boards/ubb/smile.gif

(of course, I didn't really check all this out yet, I am going by memory. Someone do a qucik program that starts a object at 0,0,0, and translate it to 10,-4,3, then dump the matrix, and see what the values are. http://www.opengl.org/discussion_boards/ubb/smile.gif)

Deiussum
12-05-2000, 06:20 PM
I would think that pad1, pad2, etc. would be pretty appropriate names considering the last column is mostly just padding to make a 4x4 matrix. http://www.opengl.org/discussion_boards/ubb/smile.gif

Nutty
12-05-2000, 11:32 PM
If you took an identity matrix and did translate 10, 5, 2 on it. The last row would be 10, 5, 2, 1.

The first 3 elements being the new position.

Nutty

Punchey
12-06-2000, 06:15 AM
Originally posted by Nutty:
If you took an identity matrix and did translate 10, 5, 2 on it. The last row would be 10, 5, 2, 1.

The first 3 elements being the new position.

Nutty

So, you're saying that [3],[7],[11] and [15] would be 10, 5, 2 and 1 respectively? If so, then I'm guessing that [15] never changes? I thought that [12],[13] and [14] gave the "position" of the "center" of the matrix. Like if you were using the matrix to keep track of the location of the object, [12],[13] and [14] would give you the location of that object. Is this right? And if so, then what is [3],[7] and [11]? The change perhaps?

Nutty
12-06-2000, 06:34 AM
No, I said the last ROW would be 10, 5, 2, 1.
Which is elements 12, 13, and 14.

Elements 3, 7, 11, and 15 are the last COLUMN. 3, 7 and 11 are the scale of the object I think, and element 15 is always 1, and doesn't do anything I believe.

Elements 12, 13, and 14 do give you the position yes, they map into the X Y and Z of the position vector if you use the structure I mentioned.

hope that clears it up.

Nutty http://www.opengl.org/discussion_boards/ubb/cool.gif

Deiussum
12-06-2000, 06:48 AM
Originally posted by Nutty:

Elements 3, 7, 11, and 15 are the last COLUMN. 3, 7 and 11 are the scale of the object I think, and element 15 is always 1, and doesn't do anything I believe.




Actually, the scale is done in the middle of the matrix, not the last row. The resulting matrix from scaling everything in an identity matrix by 2 would be this..

2 0 0 0
0 2 0 0
0 0 2 0
0 0 0 1


3, 7, 11 should be 0 in most cases. I don't know offhand of anything that would cause the last column to be different, but I'm not really an expert either.

Nutty
12-06-2000, 07:02 AM
Ahh right..
so I guess if I wanted to scale the object in it's local X axis by 2, I could scale it's right vector (from the matrix) by 2.

Thats makes sense.

So the last column does nothing at all then?

Nutty

Elixer
12-06-2000, 09:11 AM
Ok, so the last coloum is not scale, but I know it has to do with shear, and the like... argh. Where did I put the .doc that had all this in it?