Diffuse Burley + Specular Schlick-GGX Light Model
Diffuse Light based on the Disney Principled PBS diffuse light model.
Specular Light based on the Godot Specular Light Implementation.
You can download the Visual Shader Node on Itch.Io.
Shader code
shader_type spatial;
// CC0 1.0 Universal, ElSuicio, 2025.
// GODOT v4.4.1.stable.
// x.com/ElSuicio
// github.com/ElSuicio
// Contact email [interdreamsoft@gmail.com]
const float INV_PI = 0.318309;
uniform vec3 _DiffuseColor : source_color = vec3(1.0);
uniform float _Roughness : hint_range(0.0, 1.0, 0.01) = 1.0;
uniform float _Metallic : hint_range(0.0, 1.0, 0.01) = 0.0;
uniform float _MetallicSpecular : hint_range(0.0, 1.0, 0.01) = 0.5;
float diffuse_burley(
in float cNdotL,
in float cNdotV,
in float cHdotL,
in float sigma // Roughness.
)
{
// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf
float FD90 = 2.0 * sigma * cHdotL * cHdotL - 0.5;
float fd_L = 1.0 + (FD90) * pow(1.0 - cNdotL, 5.0);
float fd_V = 1.0 + (FD90) * pow(1.0 - cNdotV, 5.0);
return fd_V * fd_L * cNdotL * INV_PI;
}
vec3 specular_schlick_ggx(
in float cNdotL,
in float cNdotV,
in float cHdotN,
in float cHdotL,
in vec3 rho, // Diffuse Color.
in float sigma, // Roughness.
in float m, // Metallic.
in float s // Metallic Specular.
)
{
float a = sigma * sigma; // Variance.
float a2 = a * a;
/* Normal Distribution Function (Trowbridge-Reitz) */
float D = 1.0 + (a2 - 1.0) * cHdotN * cHdotN;
D = a2 / (PI * D * D);
/* Geometric Function (Implicit) */
float G = 0.5 / mix(2.0 * cNdotL * cNdotV, cNdotL + cNdotV, a);
/* Fresnel Function (Schlick’s Approximation) */
float dielectric = 0.16 * s * s;
vec3 f0 = mix(vec3( dielectric ), rho, vec3( m ));
float f90 = clamp(dot(f0, vec3(16.5)), m, 1.0);
vec3 F = f0 + (f90 - f0) * pow(1.0 - cHdotL, 5.0);
return max(D * G * F * cNdotL, 0.0);
}
void fragment()
{
ALBEDO = _DiffuseColor;
ROUGHNESS = _Roughness;
METALLIC = _Metallic;
SPECULAR = _MetallicSpecular;
}
void light()
{
vec3 n = normalize( NORMAL );
vec3 l = normalize( LIGHT );
vec3 v = normalize( VIEW );
vec3 h = normalize(v + l); // Halfway Vector.
float NdotL = dot(n, l); // [-1.0, 1.0].
float NdotV = dot(n, v); // [-1.0, 1.0].
float HdotN = dot(h, n); // [-1.0, 1.0].
float HdotL = dot(h, l); // [-1.0, 1.0].
float cNdotL = max(NdotL, 0.0); // [0.0, 1.0].
float cNdotV = max(NdotV, 0.0); // [0.0, 1.0].
float cHdotN = max(HdotN, 0.0); // [0.0, 1.0].
float cHdotL = max(HdotL, 0.0); // [0.0, 1.0].
/* Diffuse Burley */
float d = diffuse_burley(cNdotL, cNdotV, cHdotL, ROUGHNESS);
/* Specular Schlick-GGX */
vec3 s = specular_schlick_ggx(cNdotL, cNdotV, cHdotN, cHdotL, ALBEDO, ROUGHNESS, METALLIC, _MetallicSpecular);
DIFFUSE_LIGHT += LIGHT_COLOR * ATTENUATION * d;
SPECULAR_LIGHT += LIGHT_COLOR * ATTENUATION * s;
}


