Карта каскадных теней - вопросы ортогональной проекции - PullRequest
0 голосов
/ 17 февраля 2019

Я пытаюсь обновить рендеринг карты теней в моей игре 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);

Любая помощь с этим будет принята с благодарностью.Рад предоставить больше изображений и кода, если это необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...