I'm currently having an issue with directional light shadow maps from a moving (sun-like) light source.
When I initially implemented, the light projection matrix was computed as 3D, and the shadow map appears beautifully. I then learned that for what I'm trying to do, an orthographic projection would work better, but I'm having a hard time substituting the proper projection matrix.
Each tick, the sun moves a certain amount along a circle, as one would expect. I use a homegrown "lookAt" method to determine the proper viewing matrix. So, for instance, daylight occurs from 6AM to 6PM. When the sun is at the 9AM position (45 degrees) it should look at the origin and render the shadow map to the framebuffer. What appears to be happening with the orthographic projection is that it doesn't "tilt down" toward the origin. It simply keeps looking straight down the Z axis instead. Things look fine at 6AM and 6PM, but 12 noon, for instance, show absolutely nothing.
Here's how I'm setting things up:
Original 3D projection matrix:
Matrix4f projectionMatrix = new Matrix4f();
float aspectRatio = (float) width / (float) height;
float y_scale = (float) (1 / cos(toRadians(fov / 2f)));
float x_scale = y_scale / aspectRatio;
float frustum_length = far_z - near_z;
projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = (far_z + near_z) / (near_z - far_z);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * near_z * far_z) / frustum_length);
LookAt method:
public Matrix4f lookAt( float x, float y, float z,
float center_x, float center_y, float center_z ) {
Vector3f forward = new Vector3f( center_x - x, center_y - y, center_z - z );
Vector3f up = new Vector3f( 0, 1, 0 );
if ( center_x == x && center_z == z && center_y != y ) {
up.y = 0;
up.z = 1;
}
Vector3f side = new Vector3f();
forward.normalise();
Vector3f.cross(forward, up, side );
side.normalise();
Vector3f.cross(side, forward, up);
up.normalise();
Matrix4f multMatrix = new Matrix4f();
multMatrix.m00 = side.x;
multMatrix.m10 = side.y;
multMatrix.m20 = side.z;
multMatrix.m01 = up.x;
multMatrix.m11 = up.y;
multMatrix.m21 = up.z;
multMatrix.m02 = -forward.x;
multMatrix.m12 = -forward.y;
multMatrix.m22 = -forward.z;
Matrix4f translation = new Matrix4f();
translation.m30 = -x;
translation.m31 = -y;
translation.m32 = -z;
Matrix4f result = new Matrix4f();
Matrix4f.mul( multMatrix, translation, result );
return result;
}
Orthographic projection (using width 100, height 75, near 1.0, far 100 ) I've tried this with many many different values:
Matrix4f projectionMatrix = new Matrix4f();
float r = width * 1.0f;
float l = -width;
float t = height * 1.0f;
float b = -height;
projectionMatrix.m00 = 2.0f / ( r - l );
projectionMatrix.m11 = 2.0f / ( t - b );
projectionMatrix.m22 = 2.0f / (far_z - near_z);
projectionMatrix.m30 = - ( r + l ) / ( r - l );
projectionMatrix.m31 = - ( t + b ) / ( t - b );
projectionMatrix.m32 = -(far_z + near_z) / (far_z - near_z);
projectionMatrix.m33 = 1;
Shadow map vertex shader:
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec4 in_Position;
out float pass_Position;
void main(void) {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_Position;
pass_Position = gl_Position.z;
}
Shadow map fragment shader:
#version 150 core
in vec4 pass_Color;
in float pass_Position;
layout(location=0) out float fragmentdepth;
out vec4 out_Color;
void main(void) {
fragmentdepth = gl_FragCoord.z;
}
I feel that I'm missing something very simple here. As I said, this works fine with a 3D projection matrix, but I want the shadows constant as the user travels across the world, which makes sense for directional lighting, and thus orthographic projection.