Calculating the parameters for orthographic matrix from perspective matrix - opengl

The following two methods are taken from the ios GLKit framework:
GLK_INLINE GLKMatrix4 GLKMatrix4MakeOrtho(float left, float right,
float bottom, float top,
float nearZ, float farZ)
{
float ral = right + left;
float rsl = right - left;
float tab = top + bottom;
float tsb = top - bottom;
float fan = farZ + nearZ;
float fsn = farZ - nearZ;
GLKMatrix4 m = { 2.0f / rsl, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f / tsb, 0.0f, 0.0f,
0.0f, 0.0f, -2.0f / fsn, 0.0f,
-ral / rsl, -tab / tsb, -fan / fsn, 1.0f };
return m;
}
GLK_INLINE GLKMatrix4 GLKMatrix4MakePerspective(float fovyRadians, float aspect, float nearZ, float farZ)
{
float cotan = 1.0f / tanf(fovyRadians / 2.0f);
GLKMatrix4 m = { cotan / aspect, 0.0f, 0.0f, 0.0f,
0.0f, cotan, 0.0f, 0.0f,
0.0f, 0.0f, (farZ + nearZ) / (nearZ - farZ), -1.0f,
0.0f, 0.0f, (2.0f * farZ * nearZ) / (nearZ - farZ), 0.0f };
return m;
}
I would like to smoothly move from perspective view to ortho view and vice-versa. How should i calculate the correct parameters for ortho matrix, given the perspective matrix and parameters?

Related

opengl get window space to world space cursor position

i am trying to get the mouse cursor in world space pos from window space(-1,1 window width and height) using the viewprojectionmatrix.
This is how i calculate my projection matrix:
static mat4 Perspective4x4(float FOV, float AspectRatio, float FarC, float NearC)
{
// Positive x is right
// Positive y is up
// Positive z is forward into the screen
float Cotangent = 1.0f / tanf((FOV)*0.5f);
float Depth = NearC - FarC;
float A = (-FarC - NearC) / Depth;
float B = 2.0f * FarC * NearC / Depth;
return
{
Cotangent/AspectRatio, 0.0f, 0.0f, 0.0f,
0.0f, Cotangent, 0.0f, 0.0f,
0.0f, 0.0f, -A, -B,
0.0f, 0.0f, 1.0f, 0.0f,
};
}
...
float WidthOverHeight = ...;
mat4 ProjectionMatrix = Perspective4x4(DegreesToRadians(90.0f), WidthOverHeight, 50.0f, 0.1f);
This is how i calculate my view matrix:
static mat4 Translate4x4(vec3 V)
{
return
{
1.0f, 0.0f, 0.0f, V.X,
0.0f, 1.0f, 0.0f, V.Y,
0.0f, 0.0f, 1.0f, V.Z,
0.0f, 0.0f, 0.0f, 1.0f
};
}
...
mat4 ViewMatrix = Translate4x4(-CameraPosition);
This is how i calculate the cursor position in worldspace:
mat4 ProjectionMatrix = ...;
mat4 ViewMatrix = ...;
vec2 CursorP = GetBilateralCursorPos(Input); // Values between -1 and 1
v4_f32 WorldSpacePNear = Inverse(ProjectionMatrix) * V4F32(CursorP, -1.0f, 1.0f);
WorldSpacePNear /= WorldSpacePNear.W;
WorldSpacePNear = Inverse(ViewMatrix) * WorldSpacePNear;
v4_f32 WorldSpacePFar = Inverse(ProjectionMatrix) * V4F32(CursorP, 1.0f, 1.0f);
WorldSpacePFar /= WorldSpacePFar.W;
WorldSpacePFar = Inverse(ViewMatrix) * WorldSpacePFar;
WorldSpacePFar.Z *= -1.0f;
WorldSpacePNear.Z *= -1.0f;
EDIT: I also tried dividing by W at the end but it doesnt work properly either.
This is how i send the matrices to OpenGL (legacy):
// I send them transposed because my matrices are row-major
mat4 ProjectionMatrix = Transpose(...);
mat4 ViewMatrix = Transpose(...);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(ProjectionMatrix.E);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(ViewMatrix.E);
The resulting positions do not seem to take in account the view projection because a change in the camera position will offset them making them not accurate.
NOTES:
vec4, vec2, mat4 are custom float-based math types. (they are what you would expect)
I know legacy OpenGL is deprecated, in fact im going to switch to modern opengl very soon, i just want to get this working.
i fixed the issue calculating the cursor pos like this:
mat4 ProjectionMatrix = ...;
mat4 ViewMatrix = ...;
// Z Distance from camera pos
float WorldDistanceFromCameraZ = 1.0f;
vec2 CursorP = GetBilateralCursorPos(Input); // Values between -1 and 1
vec4 ProbeZ = V4F32(World->Camera.P - WorldDistanceFromCameraZ*World->Camera.P.Z, 1.0f);
ProbeZ = (ProjectionMatrix*ViewMatrix) * ProbeZ;
vec4 ClipP = V4F32(CursorP.X*ProbeZ.W, CursorP.Y*ProbeZ.W, ProbeZ.Z, ProbeZ.W);
vec4 WorldP = Inverse(ProjectionMatrix*ViewMatrix) * ClipP;

What is wrong with my matrix stack implementation (OpenGL ES 2.0)?

I am porting my OpenGL 1.1 application to OpenGL ES 2.0 and am writing a wrapper to implement the OpenGL 1.1 functions. My code seems to work fine until I start calling glPushMatrix() and glPopMatrix(). I think my understanding of how these should be implemented is incorrect.
Do I compute the final rotate/translate/scale before pushing it back on the stack? Should I keep only one modelview matrix (instead of separating it into three)? Are the transforms applied in the correct order?
Here is the code for my tranformation matrices
static std::vector<GLfloat> vertices;
static std::vector<std::vector<GLfloat>> rotationMatrixStack;
static std::vector<std::vector<GLfloat>> scalingMatrixStack;
static std::vector<GLfloat> rotationMatrix =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
static std::vector<GLfloat> scalingMatrix =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
static std::vector<GLfloat> translationMatrix =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
static std::vector<GLfloat> orthographicMatrix =
{
.0025f, 0.0f, 0.0f, -1.0f,
0.0f, .0025f, 0.0f, -1.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
void glTranslatef (GLfloat x, GLfloat y, GLfloat z)
{
float translation[] =
{
1.0f, 0.0f, 0.0f, x,
0.0f, 1.0f, 0.0f, y,
0.0f, 0.0f, 1.0f, z,
0.0f, 0.0f, 0.0f, 1.0f
};
multiplyMatrix(translation , &translationMatrix[0], &translationMatrix[0]);
}
void glScalef (GLfloat x, GLfloat y, GLfloat z)
{
float scaling[] =
{
x, 0.0f, 0.0f, 0.0f,
0.0f, y, 0.0f, 0.0f,
0.0f, 0.0f, z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
multiplyMatrix(scaling , &scalingMatrix[0], &scalingMatrix[0]);
}
void glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
{
glTranslatef(-x, -y, -z);
GLfloat radians = angle * M_PI/180;
float zRotation[] =
{
cos(radians), -sin(radians), 0.0f, 0.0f,
sin(radians), cos(radians), 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
multiplyMatrix(zRotation , &rotationMatrix[0], &rotationMatrix[0]);
glTranslatef(x,y,z);
}
void glLoadIdentity (void)
{
rotationMatrix, scalingMatrix, translationMatrix =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
}
void multiplyMatrix(float* a, float* b, float* product)
{
int a_heigth = 4;
int a_width = 4;
int b_heigth = 4;
int b_width = 4;
int product_heigth = a_heigth;
int product_width = b_width;
float intermediateMatrix[product_heigth * product_width] = {0};
for (int product_row = 0; product_row < product_heigth; product_row++)
{
for (int product_column = 0; product_column < product_width; product_column++)
{
float value = 0;
//std::cout << "r[" << (product_row*product_width) + product_column << "] = ";
for (int multiplication_index = 0; multiplication_index < a_width ; multiplication_index++)
{
value += a[(product_row * a_width) + multiplication_index] * b[product_column + (b_heigth * multiplication_index)];
//std::cout << "( a[" << (product_row * a_width) + multiplication_index << "] * b[" << product_column + (b_heigth * multiplication_index) << "] ) + ";
}
//std::cout << std::endl;
intermediateMatrix[(product_row*product_width) + product_column] = value;
}
}
for (int i = 0; i < product_heigth * product_width; i++)
{
product[i] = intermediateMatrix[i];
}
}
Here is the code for the matrix stack
static std::vector<std::vector<GLfloat>> translationMatrixStack;
void glPushMatrix()
{
rotationMatrixStack.push_back(rotationMatrix);
scalingMatrixStack.push_back(scalingMatrix);
translationMatrixStack.push_back(translationMatrix);
}
void glPopMatrix()
{
rotationMatrix = rotationMatrixStack.back();
scalingMatrix = scalingMatrixStack.back();
translationMatrix = translationMatrixStack.back();
rotationMatrixStack.pop_back();
scalingMatrixStack.pop_back();
translationMatrix.pop_back();
}
And here is the vertex shader code
attribute highp vec4 myVertex;
uniform mediump mat4 orthographicMatrix;
uniform mediump mat4 translationMatrix;
uniform mediump mat4 scalingMatrix;
uniform mediump mat4 rotationMatrix;
void main(void)
{
gl_Position = orthographicMatrix * translationMatrix * scalingMatrix * rotationMatrix * ( myVertex) ;
}";
You do not have a separate matrix stack for rotation, translation and scaling. In OpenGL there is one matrix stack for each matrix mode (See glMatrixMode). The matrix modes are GL_MODELVIEW, GL_PROJECTION, and GL_TEXTURE.
See the documentation of glTranslate:
glTranslate produces a translation by x y z . The current matrix (see glMatrixMode) is multiplied by this translation matrix, with the product replacing the current matrix.
the documentation of glRotate:
glRotate produces a rotation of angle degrees around the vector x y z . The current matrix (see glMatrixMode) is multiplied by a rotation matrix with the product replacing the current matrix.
and the documentation of glScale:
glScaleproduces a nonuniform scaling along the x, y, and z axes. The three parameters indicate the desired scale factor along each of the three axes.
The current matrix (see glMatrixMode) is multiplied by this scale matrix.
This means you need one matrix stack, and all operations operate on the same matrix stack.
Note, a matrix multiplication C = A * B works like this:
Matrix4x4 A, B, C;
// C = A * B
for ( int k = 0; k < 4; ++ k )
for ( int j = 0; j < 4; ++ j )
C[k][j] = A[0][l] * B[k][0] + A[1][j] * B[k][1] + A[2][j] * B[k][2] + A[3][j] * B[k][3];
A 4*4 matrix looks like this:
c0 c1 c2 c3 c0 c1 c2 c3
[ Xx Yx Zx Tx ] [ 0 4 8 12 ]
[ Xy Yy Zy Ty ] [ 1 5 9 13 ]
[ Xz Yz Zz Tz ] [ 2 6 10 14 ]
[ 0 0 0 1 ] [ 3 7 11 15 ]
And the memory image of a 4*4 matrix looks like this:
[ Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1 ]
This means you have to adapt your matrix operations:
static std::vector<std::vector<GLfloat>> modelViewMatrixStack;
static std::vector<GLfloat> modelViewMatrix{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
void multiplyMatrix( float A[], float B[], float P[] )
{
float C[16];
for ( int k = 0; k < 4; ++ k ) {
for ( int l = 0; l < 4; ++ l ) {
C[k*4+j] =
A[0*4+j] * B[k*4+0] +
A[1*4+j] * B[k*4+1] +
A[2*4+j] * B[k*4+2] +
A[3*4+j] * B[k*4+3];
}
}
std::copy(C, C+16, P);
}
void glTranslatef( GLfloat x, GLfloat y, GLfloat z )
{
float translation[]{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
x, y, z, 1.0f };
multiplyMatrix(&modelViewMatrix[0], translation, &modelViewMatrix[0]);
}
void glScalef( GLfloat x, GLfloat y, GLfloat z )
{
float scaling[]{
x, 0.0f, 0.0f, 0.0f,
0.0f, y, 0.0f, 0.0f,
0.0f, 0.0f, z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
multiplyMatrix(&modelViewMatrix[0], scaling, &modelViewMatrix[0]);
}
void glRotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
float radians = angle * M_PI/180;
float c = cos(radians);
float s = sin(radians);
float rotation[16]{
x*x*(1.0f-c)+c, x*y*(1.0f-c)-z*s, x*z*(1.0f-c)+y*s, 0.0f,
y*x*(1.0f-c)+z*s, y*y*(1.0f-c)+c, y*z*(1.0f-c)-x*s, 0.0f,
z*x*(1.0f-c)-y*s z*y*(1.0f-c)+x*s, z*z*(1.0f-c)+c, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
multiplyMatrix(&rotationMatrix[0], rotation, &rotationMatrix[0]);
}
See further:
GLSL 4×4 Matrix Fields
GLSL Programming/Vector and Matrix Operations
Data Type (GLSL)

Perspective Matrix seems wrong

This is how the result looks like:
and the same result using an Orthogonal matrix:
Any idea why using the projection matrix makes everything look weird?
My Perspective:
inline static Matrix<T> ProjectionPerspectiveOffCenterLH(const T left, const T right, const T bottom, const T top, const T zNear, const T zFar)
{
return Matrix<T>(
(2.0f * zNear) / (right-left), 0.0f, 0.0f, 0.0f,
0.0f, (2.0f * zNear) / (top-bottom), 0.0f, 0.0f,
(left+right)/(left-right), (top+bottom)/(bottom-top), zFar / (zFar - zNear), 1.0f,
0.0f, 0.0f, (zNear * zFar) / (zNear - zFar), 0.0f);
}
My Orthogonal:
inline static Matrix<T> ProjectionOrthogonalOffCenterLH(const T left, const T right, const T bottom, const T top, const T zNear, const T zFar)
{
T farNear = zFar - zNear;
return Matrix<T>(
2.0f / (right-left), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f / (top-bottom), 0.0f, 0.0f,
0.0f, 0.0f, 1.0f / farNear, 0.0f,
(left + right) / (left - right), (top + bottom) / (bottom - top), -zNear / farNear, 1.0f);
}
Just found out why this happens:
In my Perspective Matrix the FOV is 0°. That's why it looks like that.
So better use a Perspective FOV Matrix.

Projection matrix still not working... [OpenGL]

Recently I've been struggling just to set up a good perspective projection matrix and to apply it to a simple triangle. Before I show any code, I have a small question about matrix order: Do I have to multiply my view matrix with my projection matrix or multiply my projection matrix with my view matrix?
Ok now the code. I have tried many different ways to do a perspective matrix without any good result.
1
static Matrix4x4<T> Perspective_S(const T &fovy, const T &aspectRatio, const T &zNear, const T &zFar)
{
T range = tanf(fovy / 2.0f) * zNear;
return Matrix4x4<T>((2.0f * zNear) / (range * aspectRatio + range * aspectRatio), 0.0f, 0.0f, 0.0f,
0.0f, zNear / range, 0.0f, 0.0f,
0.0f, 0.0f, -(zFar + zNear) / (zFar - zNear), -1.0f,
0.0f, 0.0f, (-(2.0f * zFar * zNear) / (zFar - zNear)), 0.0f);
}
2
static Matrix4x4<T> Perspective_S(const T &fovy, const T &aspectRatio, const T &zNear, const T &zFar)
{
T f = 1.0f / tan(fovy / 2.0f);
return Matrix4x4<T>(f / aspectRatio, 0.0f, 0.0f, 0.0f,
0.0f, f, 0.0f, 0.0f,
0.0f, 0.0f, (zFar + zNear) / (zNear - zFar), (2.0f * zFar * zNear) / (zNear - zFar),
0.0f, 0.0f, -1.0f, 0.0f);;
}
3
static Matrix4x4<T> Frustum_S(const T &left, const T &right, const T &bottom, const T &top,
const T &zNear, const T &zFar)
{
return Matrix4x4<T>(2.0f * zNear / (right - left), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f * zNear / (top - bottom), 0.0f, 0.0f,
(right + left) / (right - left), (top + bottom) / (top - bottom), -(zFar + zNear) / (zFar - zNear), -1.0f,
0.0f, 0.0f, -2.0f * zFar * zNear / (zFar - zNear), 0.0f);
}
static Matrix4x4<T> Perspective_S(const T &fovy, const T &aspectRation, const T &zNear, const T &zFar)
{
T scale = tan(fovy) * zNear;
T r = aspectRation * scale, l = -r;
T t = scale, b = -t;
return Frustum_S(l, r, b, t, zNear, zFar);
}
4
static void Perspective_S(Matrix4x4<T> &matrix, T fovyInDegrees, T aspectRatio, T znear, T zfar)
{
T ymax = znear * tanf(fovyInDegrees * 3.14159265358979323846 / 360.0); //c'est pas 180?
//ymin = -ymax;
//xmin = -ymax * aspectRatio;
T xmax = ymax * aspectRatio;
Frustum(matrix, -xmax, xmax, -ymax, ymax, znear, zfar);
}
static void Frustum_S(Matrix4x4<T> &matrix, T left, T right, T bottom, T top,
T znear, T zfar)
{
T temp = 2.0f * znear;
T temp2 = right - left;
T temp3 = top - bottom;
T temp4 = zfar - znear;
matrix = Matrix4x4<T>(temp / temp2, 0.0f, 0.0f, 0.0f,
0.0f, temp / temp3, 0.0f, 0.0f,
(right + left) / temp2, (top + bottom) / temp3, (-zfar - znear) / temp4, -1.0f,
0.0f, 0.0f, (-temp * zfar) / temp4, 0.0f);
}
Some of the functions look like the transposed resulting matrix of some of my other trys. All of those functions were taken from tutorials. One even came from my previous post and it's still not working...
Just in case you might think it's my LookAt code, here it is:
What I do in main.cpp
matptr = (Matrix4x4f::LookAt_S(eye, center, up) *
Matrix4x4f::Perspective_S(M_PI / 3.0f, (float)window->getSize().x / (float)window->getSize().y, 0.001f, 1000.0f)).ToArray();
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "myMatrix"), 1, GL_FALSE, &matptr[0]);
My LookAt code:
static Matrix4x4<T> LookAt_S(Vector3<T> &eye, Vector3<T> &center, Vector3<T> &up)
{
Vector3<T> forward(center - eye);
forward.Normalize();
Vector3<T> side(forward.CrossProduct(up));
side.Normalize();
up = side.CrossProduct(forward);
return Matrix4x4<T> (side.x, up.x, -forward.x, 0.0f,
side.y, up.y, -forward.y, 0.0f,
side.z, up.z, -forward.z, 0.0f);
}

Strange shadow map behaviour, do I compute my coordinates correctly?

I wrote a shadow map shader for my graphics engine. I followed these tutorials:
Part 1 and the following part.
Unfortunately, the results I get are quite a bit off. Here are some screenshots. They show what my scene normally looks like, the scene with enabled shadows and the content of the shadow map (please ignore the white stuff in the center, thats just the ducks's geometry).
This is how I compute the coordinates to sample the shadow map with in my fragment shader:
float calcShadowFactor(vec4 lightSpacePosition) {
vec3 projCoords = lightSpacePosition.xyz / lightSpacePosition.w;
vec2 uvCoords;
uvCoords.x = 0.5 * projCoords.x + 0.5;
uvCoords.y = 0.5 * projCoords.y + 0.5;
float z = 0.5 * projCoords.z + 0.5;
float depth = texture2D(shadowMapSampler, uvCoords).x;
if (depth < (z + 0.00001f))
return 0.0f;
else
return 1.0f;
}
The lightSpacePosition vector is computed by:
projectionMatrix * inverseLightTransformationMatrix
* modelTransformationMatrix * vertexPosition
The projection matrix is:
[1.0f / (tan(fieldOfView / 2) * (width / height)), 0.0f, 0.0f, 0.0f]
[0.0f, 1.0f / (tan(fieldOfView / 2), 0.0f, 0.0f]
[0.0f, 0.0f, (-zNear - zFar) / (zNear - zFar), 2.0f * zFar * zNear / (zNear - zFar)]
[0.0f, 0.0f, 1.0f, 0.0f]
My shadow map seems to be okay and I made sure the rendering pass uses the same lightSpacePosition vector as my shadow map pass. But I can't figure out what is wrong.
Although I do not understand this entirely, I think I found the bug:
I needed to transform the coordinates to NDC space and THEN multiply the matrices. My shadow coordinate computation now looks like this:
mat4 biasMatrix = mat4(
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f
);
vec4 shadowCoord0 = biasMatrix * light * vec4(vertexPosition, 1.0f);
shadowCoord = shadowCoord0.xyz / shadowCoord0.w;
where
light = projectionMatrix * inverseLightTransformationMatrix
* modelTransformationMatrix
Now the fragment shader's shadow factor computation is rather simple:
float shadowFactor = 1.0f;
if (texture(shadowMapSampler, shadowCoord.xy).z < shadowCoord.z - 0.0001f)
shadowFactor = 0.0f;