Я пытаюсь обновить рендеринг карты теней в моей игре OpenGL до метода Cascaded Shadow Map, описанного в этого руководства OGLdev .Все работает отлично, за исключением определенных углов камеры, карта теней не покрывает весь усеченный вид.
Здесь есть быстрое видео о проблеме , где я переключаюсь между финальной визуализированной сценой исредняя тень среза текстуры.Вы можете видеть, что тени игрока обрезаются слишком рано в текстуре теней (белый вид).
Каждая карта теней визуализируется в свой собственный FBO и сэмплируется позже при выполнении постобработки (простой fragDepth>textureDepth).Код выглядит следующим образом:
const int SLICE_AMOUNT = 3;
Matrix4[] lightViewSpaces = new Matrix4[SLICE_AMOUNT];
Matrix4[] shadowProjections = new Matrix4[SLICE_AMOUNT];
OrthoInfo[] orthoInfo = new OrthoInfo[SLICE_AMOUNT];
const float zNear = 1;
const float zFar = 256;
Vector3 up = new Vector3(0, 1, 0);
Vector3 LightDirection = new Vector3(-1, 1, 1).Normalized();
float[] cascadeEnds = new float[SLICE_AMOUNT + 1]
{
zNear,
32f,
64f,
zFar,
};
Vector3[] frustumCenters = new Vector3[SLICE_AMOUNT];
public void RenderShadowShader()
{
CalculateOrthographicFrustums();
// Create shadows maps at each view frustum slice
for (int i = 0; i < SLICE_AMOUNT; i++)
{
// Bind the shadow map FBO for this slice
Gl.BindFramebuffer(FramebufferTarget.DrawFramebuffer, CurrentCollection.shadowFBO[i]);
var o = orthoInfo[i];
// Combine the light view projection and orthographic projection -200 for leniency
shadowProjections[i] = lightViewSpaces[i] * Matrix4.CreateOrthoProjection(o.l, o.t, o.r, o.b, o.n - 200, o.f - o.n);
Gl.Viewport(0, 0, (int)screenWidth, (int)screenHeight);
Gl.Clear(ClearBufferMask.DepthBufferBit);
Gl.Enable(EnableCap.DepthTest);
Gl.Disable(EnableCap.CullFace);
// Render scene objects to the shadowFBO depth buffer
RenderShadowMeshes(shadowProjections[i]);
}
}
// Convert each view frustum slice to light space
void CalculateOrthographicFrustums()
{
// Get the world view projection from player camera
Matrix4 Cam = Matrix4.CreateLookAt(player.headPosition, player.headPosition - player.LookAtVector(), up);
Matrix4 worldViewProj = Cam.Inverse();
var aspectRatio = screenHeight / screenWidth;
var tanHalfHFOV = (float)Math.Tan(Math.PI * (parent.FieldOfView / 180.0) / 2.0);
var tanHalfVFOV = (float)Math.Tan(Math.PI * (parent.FieldOfView / 180.0) * aspectRatio / 2.0);
for (int i = 0; i < SLICE_AMOUNT; i++)
{
float xn = cascadeEnds[i] * tanHalfHFOV;
float xf = cascadeEnds[i + 1] * tanHalfHFOV;
float yn = cascadeEnds[i] * tanHalfVFOV;
float yf = cascadeEnds[i + 1] * tanHalfVFOV;
Vector4[] frustumCorners =
{
// Near face
new Vector4(xn, yn, cascadeEnds[i], 1.0),
new Vector4(-xn, yn, cascadeEnds[i], 1.0),
new Vector4(xn, -yn, cascadeEnds[i], 1.0),
new Vector4(-xn, -yn, cascadeEnds[i], 1.0),
// Far face
new Vector4(xf, yf, cascadeEnds[i + 1], 1.0),
new Vector4(-xf, yf, cascadeEnds[i + 1], 1.0),
new Vector4(xf, -yf, cascadeEnds[i + 1], 1.0),
new Vector4(-xf, -yf, cascadeEnds[i + 1], 1.0)
};
// Store the frustum corners in light space
var frustumCornersLS = new Vector4[8];
// Transform frustum corners to world space
for (int j = 0; j < 8; j++)
frustumCorners[j] *= worldViewProj;
frustumCenters[i] = GetFrustumCenter(frustumCorners);
// Create light view projection from from world-space frustum center
lightViewSpaces[i] = Matrix4.CreateLookAt(frustumCenters[i] + LightDirection, frustumCenters[i], up);
// Convert frustum corners to light-space
for (int j = 0; j < 8; j++)
frustumCornersLS[j] = frustumCorners[j] * lightViewSpaces[i];
// Calculate AABB of light-space frustum
GetMinMax(frustumCornersLS, out Vector3 min, out Vector3 max);
// Store AABB in orthoInfo
orthoInfo[i].r = max.X;
orthoInfo[i].l = min.X;
orthoInfo[i].b = min.Y;
orthoInfo[i].t = max.Y;
orthoInfo[i].f = max.Z;
orthoInfo[i].n = min.Z;
}
}
Частью этого, на мой взгляд, может быть проблема, является преобразование углов усеченного конуса в светлое пространство.Несмотря на то, что он правильно определяет расположение теней, он, кажется, не справляется с изменением угла камеры:
// Create light view projection from from world-space frustum center
lightViewSpaces[i] = Matrix4.CreateLookAt(frustumCenters[i] + LightDirection, frustumCenters[i], up);
Любая помощь с этим будет принята с благодарностью.Рад предоставить больше изображений и кода, если это необходимо.