Jump to content
  • Advertisement
Sign in to follow this  
bryanedds

OpenGL Having trouble with OpenGL matrices...

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

Hello all, I just started learning some OpenGL coming from XNA. I'm trying to get my Matrix struct to be aligned how glLoadMatrixf expects. Here's the relevant parts -
	struct Matrix
	{
		float
			M11, M12, M13, M14,
			M21, M22, M23, M24,
			M31, M32, M33, M34,
			M41, M42, M43, M44;

		operator float*();
	};
I know that the fields are supposed to be in column-major order, but I'm not sure if this particular order is column-major or not. I think it's not, but when I transpose them, my rendering no longer works. Additionally, I'm not sure if I'm pushing the model, view, and projection matrices in the proper order while rendering. It works when I use glTranslatef, but not when I push my own world matrix instead. Here's my current attempt -
	glPushMatrix();
	{
		glLoadMatrixf(camera.GetView());
		glPushMatrix();
		{
			glLoadMatrixf(camera.GetProjection());
			glPushMatrix();
			{
				glTranslatef(0, 0, -10);
				// render sphere - works, but probably shouldn't!

				glLoadMatrix(sphere.GetWorld());
				// render sphere - doesn't work...
			}
			glPopMatrix();
		}
		glPopMatrix();
	}
	glPopMatrix();
This seems to work, but like I said, when I try transposing the Matrix so that it's seemingly in column-major order, everything breaks down. Anyone have any clues as to what all is going wrong here? Thanks!

Share this post


Link to post
Share on other sites
Advertisement
I suspect you want to use glMultMatrix instead of glLoadMatrix.
You also don't need to use glPushMatrix unless you want to "rewind" the stack to a previous state.

Share this post


Link to post
Share on other sites
Ok, I have things reformed to what I believe was the suggestion.

Here is a snipped of my current Matrix code -


struct Matrix
{
operator float*();

float
M11, M21, M31, M41,
M12, M22, M32, M42,
M13, M23, M33, M43,
M14, M24, M34, M44;
};


And here is a snippet of my drawing code -


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(Matrix::Transpose(camera.GetProjection()));
glMultMatrixf(Matrix::Transpose(camera.GetView()));
glPushMatrix();
{
glMultMatrixf(Matrix::Transpose(sphereView.GetTransform().GetWorldTransform()));
sphereView.Draw(timeElapsed);
}
glPopMatrix();


My question is: why do I have to transpose each matrix while drawing? My struct now has the fields in column-major order. Any ideas?

[Edited by - bryanedds on November 23, 2008 1:05:39 AM]

Share this post


Link to post
Share on other sites
In the second post, you simply changed the matrix element names, opengl doesnt refer to these. Transpose, GetProjection() and friends are still probably copying row1 in the first 4, row2 into the next 4, etc. What opengl understands is 16 elements with col1 in the first 4, etc.

float gl[16];
gl[0] = m.r1c1; gl[4] = m.r1c2; gl[8] = m.r1c3; gl[12] = m.r1c4;
gl[1] = m.r2c1; gl[5] = m.r2c2; gl[9] = m.r2c3; gl[13] = m.r2c4;
gl[2] = m.r3c1; gl[6] = m.r3c2; gl[10] = m.r3c3; gl[14] = m.r3c4;
gl[3] = m.r4c1; gl[7] = m.r4c2; gl[11] = m.r4c3; gl[15] = m.r4c4;

thats why the transpose is still needed, opengl doesnt care what you call you matrix class elements. Best to leave them named correctly like the first post, then do the above;

Share this post


Link to post
Share on other sites
Consider this part of the implementation -


Matrix::operator float*()
{
return reinterpret_cast<float*>(this);
}


Consider that I'm passing the result of this reinterpret_cast to the gl function directly. From my eye, I didn't change the names of the fields inasmuch as I changed their order inside the struct. To my thinking, therefore, the order in which the fields are declared in the struct do matter. That is, if I do m[1][2] on this reinterpret_casted pointer, it should come out in the expected column-major alignment.

Please let me know if this is not the case :)

Share this post


Link to post
Share on other sites
Quote:
This seems to work, but like I said, when I try transposing the Matrix so that it's seemingly in column-major order, everything breaks down.


Column-major vs. row-major is simply semantics. Te important part is that you are consistent in all operations. If your code works with opengl without transposing that means that internally you use column-major matrices and operations (withhout realizing it), and simply have mis-named the values.

Share this post


Link to post
Share on other sites
1) Supplying OpenGL with matrices is usually done in 2 steps. The projection is set-up usually like here:
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(camera->projection());
It is often done once, since most application need not change the projection afterwards. The model-view matrix is composed from the view matrix and the model matrices, and often varies from frame to frame, so it is set-up each time at the beginning of the rendering loop:
glMatrixMode(GL_MODELVIEW);
glLoadMatrix(camera->view());
glPushMatrix();
glMultMatrix(someModel->worldFrame());
glPopMatrix();
where the latter 3 lines are repeated for each model that is rendred (it may be more complex, e.g. if deeper frame nesting is used).

2) Mathematically OpenGL uses column vectors with the homogeneous component at the 4th place. A matrix looks like:

[ Rxx Ryx Rzx Tx ]
[ Rxy Ryy Rzy Ty ]
[ Rxz Ryz Rzz Ty ]
[ 0 0 0 1 ]
what can be interpreted as [Rxx Rxy Rxz]t denoting the x direction vector, [Ryx Ryy Ryz]t denoting the y direction vector, [Rzx Rzy Rzz]t denoting the z direction vector, and [Tx Ty Tz]t denoting the position. (Here the super-posed t denotes the transpose operator, since I wrote the column vectors as rows; its just for a convenient writing.)

Such a 2D construct has to be mapped to the 1D (linear) computer memory. OpenGL uses the column major order, what means that it walks down a column before it goes to the next one. In summary that means a layout like
Rxx Rxy Rxz 0 Ryx Ryy Ryz 0 Rzx Rzy Rzz 0 Tx Ty Tz 1

Now, if you remember back, D3D uses row vectors as well as row-major order. Notice please that both kinds of handling are changed! That means that the same matrix as above has to be transposed to yield in the mathematical representation:

[ Rxx Rxy Rxz 0 ]
[ Rxy Ryy Ryz 0 ]
[ Rzx Rzy Rzz 0 ]
[ Tx Ty Tz 1 ]

When mapping this in row major order to a linear memory, you'll get
Rxx Rxy Rxz 0 Ryx Ryy Ryz 0 Rzx Rzy Rzz 0 Tx Ty Tz 1
what is unsurprisingly the same as with OpenGL. I write "unsurprisingly" because both the vector kind as well as the order kind are changed so that both changes annul each other.

Hence, it is senseful to use the above layout. Notice please that this is nevertheless not the only possible layout. E.g. Collada uses an incompatible layout.


I hope that has cleared the issue.

EDIT: 2 syntax errors corrected.

[Edited by - haegarr on November 24, 2008 6:07:56 AM]

Share this post


Link to post
Share on other sites
haegar,

Wonderful post! Thank you so much for the time you put it into it! I have things working perfectly now. Thank you as well snoutmate and yngvedh!

Here's my final Matrix snippet -

struct Matrix
{
float
M11, M12, M13, M14,
M21, M22, M23, M24,
M31, M32, M33, M34,
M41, M42, M43, M44;

operator float*();
};

Here's my final rendering code -

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(camera.GetProjection());

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(camera.GetView());

glPushMatrix();
{
glMultMatrixf(sphereView.GetTransform().GetWorldTransform());
sphereView.Draw(timeElapsed);
}
glPopMatrix();

Thank you again to everyone!

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!