2

我在 PBR 管道中渲染硬阴影时遇到了问题。我相信 PBR 计算有问题,因为使用 Blinn-Phong 光照模型一切看起来都很好。

这些是闪电计算 - 基本 PBR

struct DirectionalLight
{
    vec3 direction;
};

layout(std140, binding = 2) uniform Scene
{
    DirectionalLight directionalLight;
    vec3 viewPosition;
} u_scene;

layout(std140, binding = 4) uniform Material
{
    vec4 baseColor;
    float roughness;
    float metalness;
} u_material;

const float PI = 3.14159265359;
const float epsilon = 0.00001;

int lightCount = 1;

vec3 CalculateDirectionalLight(vec3 N, vec3 V, float NdotV, vec3 F0)
{
    vec3 result;
    for(int i = 0; i < lightCount; ++i) {
        vec3 L = normalize(-u_scene.directionalLight.direction);

        float NdotL = max(0.0f, dot(N, L));

        vec3 H = normalize(V + L);
        float NdotH = max(0.0f, dot(N, H));

        vec3 F  = FresnelSchlickRoughness(max(0.0f, dot(H, V)), F0, u_material.roughness);
        float D = NDFGGX(NdotH, u_material.roughness);
        float G = GeometrySmith(NdotL, NdotV, u_material.roughness);

        vec3 kd = (1.0f - F) * (1.0f - u_material.metalness);
        vec3 diffuse = kd * u_material.baseColor.rgb;

        vec3 nominator = F * G * D;
        float denominator = max(epsilon, 4.0f * NdotV * NdotL);
        vec3 specular = nominator / denominator;
        specular = clamp(specular, vec3(0.0f), vec3(10.0f));

        result += (diffuse + specular) /* u_material.radiance */ * NdotL;
    }

    return result;
}

float NDFGGX(float NdotH, float roughness)
{
    float alpha = roughness * roughness;
    float alphaSq = alpha * alpha;

    float denom = (NdotH * NdotH) * (alphaSq - 1.0) + 1.0;
    return alphaSq / (PI * denom * denom);
}

float GeometrySchlickGGX(float Ndot, float k)
{
    float nom   = Ndot;
    float denom = Ndot * (1.0 - k) + k;

    return nom / denom;
}

float GeometrySmith(float NdotL, float NdotV, float roughness)
{    
    float r = (roughness + 1.0f);
    float k = (r * r) / 8.0f;

    float ggx2 = GeometrySchlickGGX(NdotV, k);
    float ggx1 = GeometrySchlickGGX(NdotL, k);

    return ggx1 * ggx2;
}

vec3 FresnelSchlick(float cosTheta, vec3 F0)
{
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
{
    return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
}

影子函数

layout(binding = 2) uniform sampler2D u_shadowMap;

float ShadowFade = 1.0;

float GetShadowBias()
{
    const float MINIMUM_SHADOW_BIAS = 0.002;
    float bias = max(MINIMUM_SHADOW_BIAS * (1.0 - dot(normalize(v_normal), -normalize(u_scene.directionalLight.direction))), MINIMUM_SHADOW_BIAS);
    return bias;
}

float HardShadows_DirectionalLight(vec4 fragPosLightSpace)
{
    vec3 shadowCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
    float bias = GetShadowBias();
    float shadowMapDepth = texture(u_shadowMap, vec2(shadowCoords.xy * 0.5 + 0.5)).r;
    return step(shadowCoords.z, shadowMapDepth + bias) * ShadowFade;
}

和主要功能

void main()
{   
    vec3 F0 = vec3(0.04f);
    F0 = mix(F0, u_material.baseColor.rgb, u_material.metalness);
    
    vec3 N = normalize(v_normal);
    vec3 V = normalize(u_scene.viewPosition - v_position);
    float NdotV = max(0.0f, dot(N, V));

    //v_positionFromLight is calculated in a vertex shader like this:
    //v_positionFromLight = u_lightViewProjection * vec4(v_position, 1.0f);
    //where v_position is modelMatrix * a_position;
    //where a_position is a input position of a vertex

    float shadow = HardShadows_DirectionalLight(v_positionFromLight);
    vec3 ambient = u_material.baseColor.rgb * 0.3f;
    vec3 lightContribution = ambient + CalculateDirectionalLight(N, V, NdotV, F0) * shadow;

    f_color = vec4(lightContribution, 1.0);
}

这就是场景的样子——应该有可见的阴影,但没有: 在此处输入图像描述

我测试了两件事。首先 - Blinn-Phong 光照模型 - 阴影渲染得很好。第二 - 在没有 PBR 闪电的情况下输出阴影计算,如下所示:

void main()
{   
    float shadow = HardShadows_DirectionalLight(v_positionFromLight);
    vec3 ambient = u_material.baseColor.rgb * 0.3f;
    f_color = vec4(ambient * shadow, 1.0f);
}

它也有效(除了它们没有放在一个好地方,但这是另一个话题): 在此处输入图像描述

为什么这个 PBR 模型不适用于阴影?我该如何解决?

4

0 回答 0