glMultMatrixf(GLfloat *m );

Huh? What part is wrong? That is the output in my program… grumbles…and it is working, grumble… … …

Heck, I’ll just post this:

Matrices can be your Friends.Matrices can be your Friends.
By Steve Baker
What stops most people from getting friendly with matrices is that they look
like 16 utterly random numbers. However, a little mental picture that I have
seems to help most people to make sense of what’s going on. Most programmers are
visual thinkers and don’t take kindly to piles of abstract math.
Take an opengl matrix:

float m [ 16 ] ;

Consider this as a 4x4 array with it’s elements laid out like this:

0  1  2  3  
4  5  6  7         THE OPENGL WAY
8  9  10 11
12 13 14 15

Yes, I know mathmaticians like to lay the numbers out differently… They prefer
to number them like this:

0  4  8  12  
1  5  9  13         THE MATHEMATICIANS WAY
2  6  10 14
3  7  11 15

…but we are OpenGL programmers - not mathematicians - right?! The reason
OpenGL arrays are laid out in the opposite direction to mathematical convention
is somewhat lost in the mists of time. However, it turns out to be a happy
accident as we will see later.
If you are dealing with a matrix which only deals with rigid bodies (ie no
scale, shear, squash, etc) then the last column (array elements 3,7,11 and 15)
are always 0,0,0 and 1 respectively and so long as they always maintain those
values, we can safely forget about them for now.
The first three elements of the bottom row of the matrix is just the overall
translation. If you imagine some kind of neat little compact object (like a
teapot), then the bottom row tells you where it is in the world. It doesn’t
matter what combinations of rotations and translations it took to produce the
matrix, the bottom row tells you where the object basically is.
OK, so now we are down to only nine random-looking numbers. These are the first
three elements of each of the top three rows - and collectively they represent
the rotation of the object.
The easy way to decode those numbers is to imagine what happens to four points
near to the origin after they are transformed by the matrix:

(0,1,0)
| /(0,0,1)
| /
|/___(1,0,0)
(0,0,0)

These are four vertices on a 1x1x1 cube that has one corner at the origin.
After the matrix has transformed this cube, where does it end up?
Well, if we neglect the translation part (the bottom row), then the pure
rotation part simply describes the new location of the points on the cube:

(1,0,0)  --->  ( m[0], m[1], m[2] )
(0,1,0)  --->  ( m[4], m[5], m[6] )
(0,0,1)  --->  ( m[8], m[9], m[10])
(0,0,0)  --->  ( 0, 0, 0 )

After that, you just add the translation onto each point so that:

(1,0,0)  --->  ( m[0], m[1], m[2] ) + ( m[12], m[13], m[14] )
(0,1,0)  --->  ( m[4], m[5], m[6] ) + ( m[12], m[13], m[14] )
(0,0,1)  --->  ( m[8], m[9], m[10]) + ( m[12], m[13], m[14] )
(0,0,0)  --->  ( 0, 0, 0 ) + ( m[12], m[13], m[14] )

Once you know this, it becomes quite easy to use matrices to position objects
exactly where you need them without messing around with multiple calls to
glRotate.
Just imagine a little cube at the origin - pretend it’s firmly attached to your
model. Think about where the cube ends up as the model moves - write down where
it’s vertices would end up and there is your matrix.
So, if I gave you this matrix:

0.707, 0.707, 0, 0
-0.707, 0.707, 0, 0
0 , 0 , 1, 0
10 , 10 , 0, 1

…you could easily see that the X axis of that little cube is now pointing
somewhere between the X and Y axes, the Y axis is pointing somewhere between Y
and negative X and the Z axis is unchanged. The entire cube has been moved 10
units off in X and Y. This is a 45 degree rotation about Z and a 10,10,0
translation! You didn’t need any hard math - just a mental picture of what the
little cube did - and no concerns about the order of operations or anything hard
like that. What would have happened to something out at 100,100,0? Well, just
imagine it was glued to the cube (on the end of a long stick)…as the cube
rotated, the thing at 100,100 would have moved quite a bit too - in fact, you
can see that the rotation would put it onto the Y axis and the translation would
have moved it 10 units up and to the right.
With practice, you can figure out what that last column does to the little cube.

So, would you like to know how to use a matrix to squash, stretch, shear, etc?
Just think about where the axes of that little cube end up - write them down and
you are done. What does a cube of jello look like when there is a strong wind
blowing from X=-infinity?

1 , 0 , 0, 0
0.3, 0.9, 0, 0
0 , 0 , 1, 0
0 , 0 , 0, 1

Look - the Y axis is leaning a third of a unit to the right and the cube got a
bit shorter.
Suppose your cartoon character is going to jump vertically, and you want to do a
bit of pre-squash before the jump… and post-stretch during the jump. Just
gradually vary the matrix from:

1 , 0 , 0, 0 1 , 0 , 0, 0
0 , 0.8, 0, 0 0 , 1.2, 0, 0
0 , 0 , 1, 0 ===> 0 , 0 , 1, 0
0 , 0 , 0, 1 0 , 0 , 0, 1

Not bad - he got shorter then longer - how about getting a bit fatter too
(conservation of cartoon volume) ?

1.2, 0 , 0 , 0 0.9,0 , 0 , 0
0 , 0.8, 0 , 0 0 ,1.2, 0 , 0
0 , 0 , 1.2, 0 ===> 0 ,0 ,0.9, 0
0 , 0 , 0 , 1 0 ,0 , 0 , 1

Now the cube got smaller in Y and bigger in X and Z then got bigger in Y and
smaller in X/Z…easy!
Not only is it easier to think transforms out this way, but it’s invariably more
efficient too. By seeing the entire transformation as one whole operation on a
unit cube, you save a long sequence of glRotate/glTranslate/glScale commands -
which each imply a complicated set of multiply/add steps to concatenate the new
transform with whatever is on the top of the stack.
Finally, there is one matrix that we all need to know - the “Identity” matrix:

1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
0, 0, 0, 1

As you can see, this matrix leaves all the axes completely alone and performs no
translation. This is a “do nothing” matrix.
Matrices are really easy - it’s just a matter of looking at them pictorially.

From official opengl conventions, you’re outputting the thing incorrectly. Baker or however he is called is also wrong in that part.

You can see, that he is doing all these operations differently as normally done. He sais mathematians would do it like this:

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

And he sais opengl would have it like this:

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

But that is the other way around. He is not doing any mathematics WRONG. He just mixed the representations of the matrices. The mathematics are adapted carefully so they would perform correctly in this mixed up thing. Any opengl literatur that I read stated the matrix format to be the upper one.
This is more a question of how to write a matrix than how to work with it.

This is a big problem, since when there are any readers, they could use the wrong indices to calculate with. We should clear that up before telling anyone what to do, I think.

Hmm…the output is wrong?

Just using the idenity matrix, ie: glLoadIdentity();
glGetFloatv(GL_MODELVIEW_MATRIX, mat1);

the output is:
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
Or as the VC++ debugger has it:
0x0,0x5,0xa,0xf = 1.0
all the rest = 0.0, so in other words,
m0,m5,m10,m15 = 1.0 which is correct is it not?

My head hurts now.

So you got what I mean? Your ressource was wrong.

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

is correct.

Oh, ****, I think you didn’t get it.
We both have the same things being 1.0, since your misinterpretation of the matrix isn’t incorrect for the main diagonal (which is used in the identity matrix).
So, the identity matrix is no good example.

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

But from what I read from you, the indices for the axises are wrong.

matrix[2] is the x for z’
matrix[6] is the y for z’
matrix[10] is the z for z’

Play around with rotation matrices to see what I mean.
I am so sure, because my thing works for me. And I don’t think that we’re saying the same.

Slap…cough… bang… ok, that cleared it up… (I also that was a bad example, since the idenity matrix is the same in both cases ) hehe.

So, looking at the openGL FAQ (which lists 2 sites to check, that Steve Baker, and Hexapods (hexapod@netcom.com))
Hexapod says: (which Steve has backwards)

This Document OpenGL
| 0 1 2 3 | | 0 4 8 12 |
| 4 5 6 7 | | 1 5 9 13 |
| 8 9 10 11 | | 2 6 10 14 |
| 12 13 14 15 | | 3 7 11 15 |


That will show me for only relying on 1 source. I guess it would have shown up as soon as I started rotating the model and wonder why the element had the wrong value

So I stand corrected.
It should have been dummped as:
…%.2f %.2f %.2f %.2f",mat1[0],mat1[4],mat1[8],mat1[12]);
…%.2f %.2f %.2f %.2f",mat1[1],mat1[5],mat1[9],mat1[13]);
…%.2f %.2f %.2f %.2f",mat1[2],mat1[6],mat1[10],mat1[14]);
…%.2f %.2f %.2f %.2f",mat1[3],mat1[7],mat1[11],mat1[15]);

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

Can’t see anything inside that… Try

 statement.

Okay. I’m happe not to change my engine…
You must know, sometimes inbetween I wasn’t sure about my POV.

It is kinda funny though, Out of the 2 sites the FAQ lists, 1 had it backwards. So that is a 50/50 shot of getting it correct.

It is nice to get it straight though. I also e-mailed Steve, to see what he has to say.

Oh, forgot for anyone stumbling onto this long thread,
xX,xY,xZ = m0,m4,m8 (x axsis)
yX,yY,yZ = m1,m5,m9 (y axsis)
zX,zY,zZ = m2,m6,m10 (z axsis)
lX,lY,lZ = m12,m13,m14 (this is the translation)
[Hope I got that correct now. ]

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

According to Computer Graphics (Hearn & Baker, Prentice Hall publishing):

A transformation matrix for a translation (and they are doing the “mathematical” one) is:

1 0 0 tx
0 1 0 ty
0 0 1 tz
0 0 0 1

i.e. the translation goes to the right “mathematically”.

The issue here is that mathematics and openGL don’t really label the order of matrix elements differently; instead it is OpenGL that uses the transpose matrix of what a mathematician would use. OpenGL is “column major”, whereas mathematics, C and pretty much the rest of the world are “row major”. So you’re both right, kind of :slight_smile:
Michaels is right about the fact that ([2] [6] [8]] is (x y z) for the z axis (mathematically). however, it should be output as elixir does… Am I making any sense? :slight_smile:

An example, for the x translation:
Mathematic[3] = OpenGL[12]
which makes:
Mathematic[tx] = OpenGL[tx]

There’s even an OpenGL extension for dealing with this.
http://oss.sgi.com/projects/ogl-sample/registry/ARB/transpose_matrix.txt

So in OpenGLmemory, we would store the (mathematical) matrix
a b c d
e f g h
i j k l
m n o p
as:
[a e i m b f j n c g k n d h l p]

I think it’s easier to always number matrices:

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

since that’s the mathematical way, and then know that what I read from index 12 in OGL is the x translation. Same numbering for math and OGL that is.

[This message has been edited by Magnus W (edited 01-13-2001).]

Yeah.
Well, since you say that a transformation matrix looks like you stated, elixers output of it was incorrect. With these numbers, I mean the memory distances from the “start” of the array. I would advice anyone to use a [16] array to handle matrices.

I’m not even sure what’s right and wrong anymore : )

Let’s just say Elixir outputs it the way it’s stored in memory, given that C/C++ is row major. It -is- supposed to come out with translations at the bottom, i.e. as the transpose of the mathematical counterpart.

Next question tho’, is it more expensive (processing-wise) to use [4][4] in C than to use [16]?

Boy was that a fun discussion!!! I just would like to add by saying that mathematics has nothing do with that. The math and opengl Matrix is the same, they represent the same concept.

the only thing is that C/C++ is row major(look at the standard) and Opengl wants column major. That only means the representation in memory.

Magnus, the performance depends on your compiler and whether the number of elements is a power of 2.

If the number of elements is not a power of 2, the speed is the same.

If it is, then a clever compiler will use shift and instead of normal multi to map an [i][j] call to (in row major) [(j*num_elems + i)*sizeof(data) ]

the efficient version is [(j<<num_elems + i)*sizeof(data) ]

in column major the formula is
[(i<<num_elems + j)*sizeof(data) ]

[This message has been edited by Gorg (edited 01-13-2001).]

I wanted to state that only the “names” of the elements are flipped in opengl. The matrices always look equal. So gorg, I might have explained me bad, but I wasn’t discussing to calculate differently with opengl matrices. The problem was, that a mathemacian would store the first row in offsets 0, 1, 2, 3 but opengl has it in 0, 4, 8, 12 (all memory offsets). Elixer not only output the matrix incorrectly, he was actually calculating with the wrong offsets.

Originally posted by Magnus W:
[b]According to Computer Graphics (Hearn & Baker, Prentice Hall publishing):

A transformation matrix for a translation (and they are doing the “mathematical” one) is:

1 0 0 tx
0 1 0 ty
0 0 1 tz
0 0 0 1

i.e. the translation goes to the right “mathematically”.

The issue here is that mathematics and openGL don’t really label the order of matrix elements differently; instead it is OpenGL that uses the transpose matrix of what a mathematician would use. OpenGL is “column major”, whereas mathematics, C and pretty much the rest of the world are “row major”. So you’re both right, kind of :slight_smile:
[This message has been edited by Magnus W (edited 01-13-2001).][/b]

I thought I might clarify that OpenGL doesn’t use transposed matrices, they are exactly the same matrices as in your book. The difference is what index points to what cell (which you point out very well with the examples). In linear algebra the index increases along each row, so 3 is top right, OpenGL indices increase downwards along the column so 3 is bottom left. C 2d arrays (eg. float m[4][4]) are row-major whihch means the indices will be wrong. That’s why you should use float m[16] instead. If you have column major matrices you can write to the columns sequentially whihch might give a slight speed increase (since you often want to edit the axes or the position).

Michael wrote:
matrix[2] is the x for z’
matrix[6] is the y for z’
matrix[10] is the z for z’

Wait, is this correct or not then?:

/* Matrixes can be thought of as:

  • 0 4 8 12
  • 1 5 9 13
  • 2 6 10 14
  • 3 7 11 15
    */

/* alternately:
X’x Y’x Z’x Tx
X’y Y’y Z’y Ty
X’z Y’z Z’z Tz
0 0 0 1
*/

I was looking at another source, and they have the matrix as:
Xx Xy Xz Tx
Yx Yy Yz Ty
Zx Zy Zz Tz
0 0 0 1

It is 4AM now… so I can’t think straight now… there is lots of conflicting info. Argh.

Oh, ****.
My stomach sais that the second and my said stuff IS correct. However, I need to get far behind all that mathematic stuff.

Will cost lots of time. Stop. Don’t know where to get documention. Stop. Anybody knows. Stops. Waiting. Stop. Stop.

On the other side it may be that we all say the same stuff, but I can’t see it. (And I think that this is quite probable, since I didn’t see so many different answers to only one question yet.)