В настоящее время у меня проблема с картами теней направленного света от движущегося (подобного солнцу) источника света.
Когда я изначально реализовал, матрица проекции света была рассчитана как 3D, и карта теней выглядела красиво. Затем я узнал, что для того, что я пытаюсь сделать, орфографическая проекция будет работать лучше, но мне трудно заменить правильную матрицу проекции.
Каждый тик, как и следовало ожидать, солнце перемещается на определенное расстояние по окружности. Я использую доморощенный метод «lookAt», чтобы определить правильную матрицу просмотра. Так, например, дневной свет бывает с 6 утра до 6 вечера. Когда солнце находится в положении 9:00 (45 градусов), оно должно смотреть на начало координат и отображать карту теней в буфер кадра. Что, по-видимому, происходит с орфографической проекцией, так это то, что она не «наклоняется вниз» к началу координат. Вместо этого он просто продолжает смотреть прямо вниз по оси Z. В 6:00 и 18:00 все выглядит нормально, но, например, в 12:00 абсолютно ничего не видно.
Вот как я настраиваю вещи:
Оригинальная 3D проекционная матрица:
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:
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;
}
Орфографическая проекция (с использованием ширины 100, высоты 75, около 1,0, далеко 100). Я пробовал это со многими разными значениями:
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;
Вершинный шейдер карты теней:
#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;
}
Шейдер фрагмента карты теней:
#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;
}
Я чувствую, что мне здесь не хватает чего-то очень простого. Как я уже сказал, это прекрасно работает с матрицей 3D-проекции, но я хочу, чтобы тени оставались постоянными, когда пользователь путешествует по миру, что имеет смысл для направленного освещения и, следовательно, ортогональной проекции.