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;
}
Tags
3d, diffuse, light, Specular
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from ElSuicio

Related shaders

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments