Description
Changelog
Reviews

This is an addon for Godot 4.4+ that adds the Schlick-GGX node to the visual shader system. This node outputs the Specular Light based on the Godot Specular Light Implementation.

Schlick-GGX Specular Reflectance Model (Node).

GDSL:

shader_type spatial;

const float INV_PI = 0.31830988618379067154;

group_uniforms _BurleyGGX;
uniform vec3 _DiffuseColor : source_color = vec3(1.0);
uniform float _Roughness : hint_range(0.0, 1.0, 1e-3) = 1.0;
uniform float _Metallic : hint_range(0.0, 1.0, 1e-3) = 0.0;
uniform float _Specular : hint_range(0.0, 1.0, 1e-3) = 0.5;

float schlick_fresnel(float u)
{
    float m = clamp(1.0 - u, 0.0, 1.0);
    return m * m * m * m * m; // pow(m, 5).
}

void brdf(
    in vec3 n,
    in vec3 l,
    in vec3 v,
    in vec3 rho,
    in float roughness,
    in float metallic,
    in float specular,
    inout vec3 fd,
    inout vec3 fs
)
{
    float NdotL = dot(n, l); // cos(theta_l) == cos(theta_i).

    if(NdotL < 0.0)
    {
        return;
    }

    float NdotV = min(max(dot(n, v), 1e-3), 1.0); // cos(theta_v) == cos(theta_r).

    vec3 h = normalize(v + l);

    float HdotN = dot(h, n); // cos(theta_h).
    float HdotL = dot(h, l); // cos(theta_d).

    float alpha = roughness * roughness;
    float alpha2 = alpha * alpha;

    // https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf

    /* Burley */
    float FD_l = schlick_fresnel(NdotL), FD_v = schlick_fresnel(NdotV);

    float retroreflection = roughness * HdotL * HdotL;
    float FD90 = 0.5 + 2.0 * retroreflection;

    fd = vec3(INV_PI * mix(1.0, FD90, FD_l) * mix(1.0, FD90, FD_v) * NdotL);

    /* Normal Distribution Function (GGX) */
    float t = 1.0 + (alpha2 - 1.0) * HdotN * HdotN;
    float D = alpha2 / (PI * t * t);

    /* Geometric Function (Implicit) */
    float G = 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, alpha);

    /* Geometric Function (Smith-GGX) */
    //float GL = 1.0 / (NdotL + sqrt(alpha2 + (1.0 - alpha2) * (NdotL * NdotL)));
    //float GV = 1.0 / (NdotV + sqrt(alpha2 + (1.0 - alpha2) * (NdotV * NdotV)));
    //float G = GL * GV;

    /* Godot Fresnel Function (Schlick’s Approximation) */
    float dielectric = 0.16 * specular * specular;

    vec3 f0 = mix(vec3( dielectric ), rho, vec3( metallic )); 
    float f90 = clamp(dot(f0, vec3(16.5)), metallic, 1.0);

    vec3 F = f0 + (f90 - f0) * schlick_fresnel(HdotL);

    /* Fresnel Function (Schlick’s Approximation) */
    //vec3 f0 = mix(vec3(specular * 0.08), rho, vec3(metallic));
    //vec3 F = f0 + (1.0 - f0) * schlick_fresnel(HdotL);

    fs = D * G * F * NdotL;
}

void fragment() {
    ALBEDO = _DiffuseColor;
    ROUGHNESS = _Roughness;
    METALLIC = _Metallic;
    SPECULAR = _Specular;
}

void light() {
    vec3 n = normalize(NORMAL);
    vec3 l = normalize(LIGHT);
    vec3 v = normalize(VIEW);

    vec3 fd = vec3(0.0);
    vec3 fs = vec3(0.0);

    brdf(n, l, v, ALBEDO, ROUGHNESS, METALLIC, _Specular, fd, fs);

    // To compare with the Slice-Image.
    //vec3 radiance = (LIGHT_COLOR / PI) * ATTENUATION;

    // In PI light units.
    vec3 radiance = LIGHT_COLOR * ATTENUATION;

    DIFFUSE_LIGHT += radiance * fd;
    SPECULAR_LIGHT += radiance * fs;
}

[ Support Email: [email protected] ]

Changelog for version v1.0.3

No changelog provided for this version.

Reviews (0)

Visual Shader Schlick-GGX Light Model Node has no reviews yet.

Login to write a review.