定向光的全向阴影

Omnidirectional shadows for directional light

当使用阴影贴图时,光投影(正交)按以下方式使用(其他行星类似):

    const glm::mat4 lightProjection = glm::ortho(-saturn->GetRadius() * 3.0f, saturn->GetRadius() * 3.0f, -saturn->GetRadius() * 3.0f, saturn->GetRadius() * 3.0f, camera.GetNear(), camera.GetFar());
    const glm::mat4 lightView = glm::lookAt(_sun->GetPosition(), saturn->GetPosition(), glm::vec3(0.0, 1.0, 0.0));
    const glm::mat4 lightSpaceMatrix = lightProjection * lightView;
    saturn->SetLightSpaceMatrix(lightSpaceMatrix);

在渲染行星时,我更改了 lightSpaceMatrix,尝试通过以下方式重新创建伪全向光(在某些方向):

void Application::RenderPlanetsAndSatellites(const Shader& shader) {
    shader.Use();

    for (const auto& renderableComponentPS : _renderableComponentsPS) {
        shader.SetMat4("lightSpaceMatrix", renderableComponentPS.planet->GetLightSpaceMatrix());

        ...

        renderableComponentPS.planet->SetShader(shader);
        renderableComponentPS.planet->AdjustToParent(isTimeRun);
        renderableComponentPS.planet->Render();

        for (const auto& satellite : renderableComponentPS.satellites) {
            satellite->SetShader(shader);
            satellite->AdjustToParent(isTimeRun);
            satellite->Render();
        }
    }
}

顶点着色器:

#version 460 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 aTangent;
layout (location = 4) in vec3 aBitangent;

out VS_OUT {
    vec3 FragPos;
    vec2 TexCoords;
    vec3 TangentLightPos;
    vec3 TangentViewPos;
    vec3 TangentFragPos;
    vec4 FragPosLightSpace;
} vs_out;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;

uniform vec3 lightPos;
uniform vec3 viewPos;

uniform float zCoef; // For log z-buffer (2.0 / log2(farPlane + 1.0))

void main() {
    vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
    vs_out.TexCoords = aTexCoords;

    mat3 normalMatrix = mat3(transpose(inverse(model)));
    vec3 T = normalize(normalMatrix * aTangent);
    vec3 N = normalize(normalMatrix * aNormal);
    T = normalize(T - dot(T, N) * N);
    vec3 B = cross(N, T);

    mat3 TBN = transpose(mat3(T, B, N));
    vs_out.TangentLightPos = TBN * lightPos;
    vs_out.TangentViewPos  = TBN * viewPos;
    vs_out.TangentFragPos  = TBN * vs_out.FragPos;
    vs_out.FragPosLightSpace = lightSpaceMatrix * vec4(vs_out.FragPos, 1.0);

    gl_Position = projection * view * vec4(vs_out.FragPos, 1.0f);

    // Log z-buffer [логарифмический z-буфер]
    gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * zCoef - 1.0;
    gl_Position.z *= gl_Position.w;
}

片段着色器中的阴影计算:

float CalculateShadow(vec4 fragPosLightSpace) {
    // Perform perspective divide
    vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;

    // Transform to [0,1] range
    projCoords = projCoords * 0.5 + 0.5;

    // Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
    float closestDepth = texture(shadowMap, projCoords.xy).r;

    // Get depth of current fragment from light's perspective
    float currentDepth = projCoords.z;
    vec3 lightDir = lightPos - fs_in.FragPos;
    vec3 lightDirNorm = normalize(lightDir);

    float shadow;

    ApplyPCF(shadow, projCoords, currentDepth);
    return shadow;
}

但由于某种原因,这不起作用。离太阳最近的行星似乎开始覆盖所有其他行星:

伙计们,我解决了这个问题...

想法是将一个场景组件(行星、它的卫星、光环等)渲染成阴影贴图,然后立即进入常规缓冲区,然后清除阴影贴图(深度缓冲区),这样行星离太阳最近的不会覆盖所有其他的,等等

清理是必要的,因为只使用一张阴影贴图,如果不清理,深度将被来自场景各处的对象重叠。

因此,通过改变lightSpaceMatrix,可以营造出场景中使用全向光源的印象。