Sign in to follow this  

Problem getting the projection matrix right

This topic is 2662 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 guys,

I'm having a really hard time moving away from all OpenGL 3.x deprecated functions. Currently I'm trying to get my own projection-, model- and view-matrices to my shaders. While there were no problems implementing any of the (for me) all new rendering architecture, it seems like I can't get the projection matrix right, not even if I use the gluPerspective/glFrustum code. No matter which calculation I use (there are numerous on the web), I end up with my object being either too small, too wide (as if I used the wrong aspect ratio) or both.
Here is how I currently calculate the projection matrix:

void initPerspective(double zNear, double zFar, double aspect)
{
double fw, fh;
fh = Math.tan(fov / 360 * Math.PI) * zNear;
fw = fh * aspect;
initFrustum(-fw, fw, -fh, fh, zNear, zFar);
}

void initFrustum(double left, double right, double bottom, double top,
float zNear, float zFar)
{
projectionMatrix.m00 = (float) (2 * zNear / (right - left));
projectionMatrix.m02 = (float) ((right + left) / (right - left));

projectionMatrix.m11 = (float) (2 * zNear / (top - bottom));
projectionMatrix.m12 = (float) ((top + bottom) / (top - bottom));

projectionMatrix.m22 = (float) (-(zFar + zNear) / (zFar - zNear));
projectionMatrix.m23 = (float) (-2 * zFar * zNear / (zFar - zNear));

projectionMatrix.m32 = -1;

projectionMatrix.invert();
}


The above code produces (surprinsingly ;)) the exact same matrix as gluPerspective does (I've compared them). However, not only is my object only 1/10 of its size, it is also too wide, as if it was scaled by 1.5 in width.
One more thing noteworthy, before the matrix is actually used in my shader, I put it to column major order.

Thanks for reading.

Klaus

Edit:
Almost forgot the shader code:

// fragment shader
#version 150

in vec3 ex_Color;

out vec4 out_FragColor;

void main(void)
{
out_FragColor = vec4(ex_Color, 1.0);
}


// vertex shader
#version 150

uniform mat4 uni_ProjMat;
uniform mat4 uni_ViewMat;
uniform mat4 uni_ModelMat;

in vec3 in_Vertex;
in vec3 in_Color;

out vec3 ex_Color;

void main(void)
{
mat4 trans = uni_ProjMat * uni_ViewMat * uni_ModelMat;
//mat4 trans = uni_ViewMat * uni_ModelMat;
//mat4 trans = uni_ModelMat;
gl_Position = trans * vec4(in_Vertex, 1.0);
ex_Color = in_Color;
}

Share this post


Link to post
Share on other sites
Thanks for your reply, unfortunately the method call seems to be correct.


int width = 800;
int height = 600;
initProjectionMatrix(0.01f, 1000.0f, (float) width / height, 60.0f);

Share this post


Link to post
Share on other sites
I'm a little bit confused. You say your problem is "moving away from deprecated functions", so I'm assuming that at some point in the history of your project this was working correctly? You said that it looks wrong even if you use the gluPerspective code. Are you saying that if you just flat out use gluPerspective code it doesn't look right?

If gluPerspective did work for you at some point, and your matrix is giving you the exact same results as gluPerspective did, then logically there has to be something else wrong that isn't in your projection matrix.

Quote:

One more thing noteworthy, before the matrix is actually used in my shader, I put it to column major order.

This scares me slightly, you could be correct but I'm not aware of any reason why you'd have to change the order of the matrix to use it in the shader. Whatever you get from gluPerspective should be fine for the shader.

Share this post


Link to post
Share on other sites
Nevermind the part about the order of the matrix. All I did was calculate the matrix (with above code), invert it, and send it to my shader. I did not actually try to use the gluPerspective matrix in my shader, all I did was compare the two matrices. Are there any obvious errors in my matrix calculation? Is the order of the matrix operations in the shader correct? Thanks!

Share this post


Link to post
Share on other sites
I think I had a similar problem before and it was that I had a line similar to this: (float)width / height

It ended up being rounded to a whole number anyway. I cast both width and height to a float and like magic...

Share this post


Link to post
Share on other sites
Quote:
All I did was calculate the matrix (with above code), invert it, and send it to my shader.
Do you mean invert, or transpose? ('Cause if you're inverting the projection matrix, that could definitely cause problems.)

If you mean transpose, are you sure the transpose is necessary? Have you tried it without it?

Share this post


Link to post
Share on other sites
The aspect ratio is definately correct, since height is implicitely cast to float as well (I checked its value).
I did not transpose the matrix. I did however invert it, if I don't the object disappears completely. Heres the thing. I'vegot a projection matrix now which seems to be working (compared it with an object rendered in immediate mode, applying the same transformations). However, the matrix produces is not the same gluPerspective produces, and I have to invert it, otherwise the object appears to be way too close. I'm totally confused now, heres the code I'm using now:


projectionMatrix.setIdentity();
double yMax = zNear * Math.tan(fov * Math.PI / 360.0);
double yMin = -yMax;

double xMax = yMax / aspect;
double xMin = yMin / aspect;

projectionMatrix.m00 = (float) ((2.0 * zNear) / (xMax - xMin));
projectionMatrix.m11 = (float) ((2.0 * zNear) / (yMax - yMin));
projectionMatrix.m20 = (float) ((xMax + xMin) / (xMax - xMin));
projectionMatrix.m21 = (float) ((yMax + yMin) / (yMax - yMin));
projectionMatrix.m22 = (float) (-1.0 * (zFar + zNear) / (zFar - zNear));
projectionMatrix.m23 = (float) ((-2.0 * zFar * zNear) / (zFar - zNear));
projectionMatrix.m32 = (float) -1.0f;

projectionMatrix.invert();



The matrix object is then stored in column major order (just like OpenGL likes it) and sent to the shader. But as I said, the matrix is nothing like the one I get when using glGetFloatv to retrieve the projection matrix created by gluPerspective, the scene appears to be displayed correctly though :(.

Edit:
About transposing it. I did try to transpose it, which did not change anything, which confused me even more.

Share this post


Link to post
Share on other sites
You shouldn't be inverting the projection matrix. I would start by removing that line, and then working from there to solve your problem.

With the inversion removed, does your matrix match what's generated by the OpenGL utility functions?

Share this post


Link to post
Share on other sites
Without inverting my matrix, this is what I send to my shader:


[2.309401, 0.0, 0.0, 0.0, 0.0, 1.7320508, 0.0, 0.0, 0.0, 0.0, -1.00002, -1.0, 0.0, 0.0, -0.020000199, 1.0]



The gluPerspective matrix i get when using glGetFloatv is:


[1.299038, 0.0, 0.0, 0.0, 0.0, 1.7320508, 0.0, 0.0, 0.0, 0.0, -1.00002, -1.0, 0.0, 0.0, -0.0200002, 0.0]



However, when not inverting my own matrix my object appears way too large. When I additionally set the last element to 0.0 (just like the gluPerspective matrix) I see nothing. When I use the array I got from glGetFloatv using the gluPerspective function, I see nothing either. When I invert that matrix, my object is way too small.

Share this post


Link to post
Share on other sites
Randomly inverting things isn't going to help you :) Even if a random change of that sort appears to solve some problem or another or mitigate some undesirable behavior, if you're making changes of this sort without knowing why you're doing it, you're just going to make things harder for yourself down the road.

Inverting the matrix is a specific operation with a specific result, and when it's used it's used for a reason. Can you explain why inverting the projection matrix in this case would be an appropriate thing to do? What is it meant to accomplish exactly?

In any case, earlier you said that your projection matrix matched the one created by gluPerspective() exactly, but the arrays in your last post don't match. As such, it seems to me a good first step would be to figure out why your matrix isn't matching the one generated by gluPerspective().

Also, if using the matrix generated by gluPerspective() gives you the same results (that is, you can't see anything), then that would suggest there's something else wrong (in addition to the problems with the projection matrix).

Share this post


Link to post
Share on other sites
About inverting the matrix:
I really wasn't just throwing some random operations at my matrix (believe me ;)), I assumed that I have to invert the matrix in order to accomplish what I was trying to do. I guess I was wrong (its some time ago since I last did this theoretical math stuff at university), sorry for that.
About the matrices I posted not being equal:
The code I posted first did create the same matrix as gluPerspective. However, since it did result in a blank screen, I tried the code I last posted, which results in a different matrix but also correctly displayed objects.
I am now going to switch back to the code which produces the same matrix as gluPerspective does however, the question then is, what else could I have done wrong? I'm really stuck now since I really have no clue of what else could be wrong.

Share this post


Link to post
Share on other sites
Actually, here's a question: what does your 'invert' function do? Can you post the code for it?

(The reason I'm wondering is that you said the code you posted initially produces results that match those of gluPerspective(), but that code has a call to invert() it. Maybe I'm missing something, but it would seem odd to me if building the projection matrix and then inverting it produced results that matched those of gluPerspective().)

Share this post


Link to post
Share on other sites
The problem has been solved. Just so everyone who might check this thread out knows: The code I posted in my initial message works perfectly fine. Thanks everyone for helping me out.

Share this post


Link to post
Share on other sites

This topic is 2662 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this