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
// ElSuicio, 2026.
// GODOT v4.6.1.stable.
// x.com/ElSuicio
// github.com/ElSuicio
// Contact email [interdreamsoft@gmail.com]

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 fragment() {
	ALBEDO = _DiffuseColor;
	ROUGHNESS = _Roughness;
	METALLIC = _Metallic;
	SPECULAR = _Specular;
}

void light() {
	vec3 n = normalize(NORMAL);
	vec3 l = normalize(LIGHT);
	vec3 v = normalize(VIEW);
	
	float NdotL = min(max(dot(n, l), 1e-3), 1.0); // cos(theta_l) == cos(theta_i).
	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;
	
	/* Burley + Trowbridge-Reitz-GGX */
	float FD_l = schlick_fresnel(NdotL), FD_v = schlick_fresnel(NdotV);
	float FD90 = 0.5 + 2.0 * ROUGHNESS * HdotL * HdotL;
	
	float fd = 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 ), ALBEDO, 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), ALBEDO, vec3(METALLIC));
	//vec3 F = f0 + (1.0 - f0) * schlick_fresnel(HdotL);
	
	vec3 fs = vec3(D * G * F * NdotL);
	
	// 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;
}
Live Preview
Tags
3d, diffuse, light, lighting, 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