Disney BRDF with Maps

Original:
https://github.com/wdas/brdf/blob/main/src/brdfs/disney.brdf

Shader code
//# Copyright Disney Enterprises, Inc.  All rights reserved.
//#
//# Licensed under the Apache License, Version 2.0 (the "License");
//# you may not use this file except in compliance with the License
//# and the following modification to it: Section 6 Trademarks.
//# deleted and replaced with:
//#
//# 6. Trademarks. This License does not grant permission to use the
//# trade names, trademarks, service marks, or product names of the
//# Licensor and its affiliates, except as required for reproducing
//# the content of the NOTICE file.
//#
//# You may obtain a copy of the License at
//# http://www.apache.org/licenses/LICENSE-2.0

shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, specular_schlick_ggx;


group_uniforms transparancy;
uniform int cull_mode = 0; // 0 = Disabled | 1 = Back | 2 = Front

uniform int transparency_mode = 0; // 0 = Disabled | 1 = Alpha | 2 = Alpha Scissor | 3 = Alpha Hash | 4 = Depth Pre-pass
uniform float alpha_scissor_threshold :hint_range(0.0, 1.0) = 0.5;
uniform float alpha_hash_scale :hint_range(0.1, 10.0) = 1.0;

group_uniforms albedo;
uniform vec4 baseColor : source_color = vec4(1.0, 1.0, 1.0, 1.0);
//uniform float baseColor_strength : hint_range(0.0, 1.0) = 1.0;

uniform sampler2D albedo_texture :source_color, filter_linear_mipmap_anisotropic, repeat_enable;

group_uniforms roughness;
uniform float roughness : hint_range(0.0, 1.0) = 1.0;
uniform sampler2D roughness_texture :hint_roughness_r, filter_linear_mipmap_anisotropic, repeat_enable;
uniform int roughness_texture_channel : hint_range(0, 4) = 0; // 0 = Red | 1 = Green | 2 = Blue | 3 = Alpha | 4 = Gray

group_uniforms metallic;
uniform float metallic : hint_range(0.0, 1.0) = 0.0;
uniform sampler2D metallic_texture :hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;
uniform int metallic_texture_channel : hint_range(0, 4) = 0; // 0 = Red | 1 = Green | 2 = Blue | 3 = Alpha | 4 = Gray

group_uniforms specular;
uniform float specular : hint_range(0.0, 1.0) = 0.5;
uniform sampler2D specular_texture :hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;
uniform float specularTint : hint_range(0.0, 1.0) = 0.0;
uniform int specular_texture_channel : hint_range(0, 4) = 0; // 0 = Red | 1 = Green | 2 = Blue | 3 = Alpha | 4 = Gray

group_uniforms normal_map;
uniform sampler2D normal_texture : hint_roughness_normal, filter_linear_mipmap_anisotropic, repeat_enable;
uniform float normal_scale :hint_range(0.0, 1.0) = 1.0;

group_uniforms ambient_occlusion;
uniform sampler2D ao_texture :hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;
uniform int ao_texture_channel : hint_range(0, 4) = 0; // 0 = Red | 1 = Green | 2 = Blue | 3 = Alpha | 4 = Gray

group_uniforms emission;
uniform float emission_energy :hint_range(0.0, 2048.0) = 0.0;
uniform vec3 emission_color : source_color = vec3(0.0);
uniform sampler2D emission_texture :source_color, hint_default_black, filter_linear_mipmap_anisotropic, repeat_enable;

group_uniforms subsurface;
uniform float subsurface : hint_range(0.0, 1.0) = 0.0;

group_uniforms anisotropic;
uniform float anisotropic : hint_range(0.0, 1.0) = 0.0;

group_uniforms sheen;
uniform float sheen : hint_range(0.0, 1.0) = 0.0;
uniform float sheenTint : hint_range(0.0, 1.0) = 0.5;

group_uniforms clearcoat;
uniform float clearcoat : hint_range(0.0, 1.0) = 0.0;
uniform float clearcoatGloss : hint_range(0.0, 1.0) = 1.0;

group_uniforms UV1;
uniform bool uv1_triplanar = false;
varying vec3 uv1_triplanar_pos;

uniform float uv1_blend_sharpness : hint_range(0.0, 150.0, 0.001) = 1.0;
varying vec3 uv1_power_normal;

uniform vec3 uv1_offset = vec3(0.0);
uniform vec3 uv1_scale = vec3(1.0);

group_uniforms UV2;
uniform vec3 uv2_offset = vec3(0.0);
uniform vec3 uv2_scale = vec3(1.0);

group_uniforms transform;
uniform bool is_using_z_clip = false;
uniform float z_clip_scale : hint_range(0.01, 1.0, 0.01) = 1;
uniform float fov_override : hint_range(1.0, 179.0, 0.1) = 75.0;


varying float v_metallic;
varying float v_roughness;
varying float v_specular;
varying vec3 v_albedo;

varying vec3 v_tangent;
varying vec3 v_binormal;

group_uniforms EXPERIMENTAL;
/** You can use this F0 instead of specular approach if you set dielectric_f0_scale = 1.0 and specular = 1.0. F0 = ((IOR - 1.0) / (IOR + 1.0))^2. IOR - Index of Refraction. IOR Tables: https://pixelandpoly.com/ior.html */ 
uniform float dielectric_f0 = 1.0;
uniform float dielectric_f0_scale = 0.08;
uniform float subsurface_scale = 1.25;
/** F0 = ((IOR - 1.0) / (IOR + 1.0))^2. IOR - Index of Refraction. IOR Tables: https://pixelandpoly.com/ior.html */
uniform float clearcoat_f0 = 0.04;
uniform float clearcoat_distribution = 0.25;


//////////////////////////////////////////////////////


void vertex() {
	UV = UV * uv1_scale.xy + uv1_offset.xy;
	
	
	// UV1 Triplanar: Enabled
	uv1_power_normal = pow(abs(NORMAL), vec3(uv1_blend_sharpness));
	uv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;
	uv1_power_normal /= dot(uv1_power_normal, vec3(1.0));
	uv1_triplanar_pos *= vec3(1.0, -1.0, 1.0);
	
	
	if (is_using_z_clip)
	{
		Z_CLIP_SCALE = z_clip_scale;
		
		if (!IN_SHADOW_PASS)
		{
			float flip_y = sign(PROJECTION_MATRIX[1][1]);
			float aspect = PROJECTION_MATRIX[1][1] / PROJECTION_MATRIX[0][0];
			float f = flip_y / tan(fov_override * PI / 360.0);
			PROJECTION_MATRIX[0][0] = f / aspect;
			PROJECTION_MATRIX[1][1] = f;
		}
	}
}


float sqr(float x)
{
	return x * x;
}


float SchlickFresnel(float u) 
{
	float m = clamp(1.0 - u, 0.0, 1.0);
	float m2 = m * m;
	
	return m2 * m2 * m;
}


float GTR1(float NdotH, float a)
{
	if (a >= 1.0) { return 1.0 / PI; }
	
	float a2 = a * a;
	float t = 1.0 + (a2 - 1.0) * NdotH * NdotH;
	
	return (a2 - 1.0) / (PI * log(a2) * t);
}


float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
{
	return 1.0 / (PI * ax * ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH * NdotH));
}


float smithG_GGX(float NdotV, float alphaG)
{
	float a = alphaG * alphaG;
	float b = NdotV * NdotV;
	
	return 1.0 / (NdotV + sqrt(a + b - a * b));
}


float smithG_GGX_aniso(float NdotV, float VdotX, float VdotY, float ax, float ay)
{
	return 1.0 / (NdotV + sqrt(sqr(VdotX * ax) + sqr(VdotY * ay) + sqr(NdotV)));
}


vec3 mon2lin(vec3 x)
{
	return vec3(pow(x[0], 2.2), pow(x[1], 2.2), pow(x[2], 2.2));//x;//pow(x, vec3(0.5));
}


float hash(vec2 p)
{
	p = fract(p * vec2(123.34, 345.45));
	p += dot(p, p + 34.345);
	
	return fract(p.x * p.y);
}


float get_texture_channel(vec4 tex, int channel)
{
	if (channel == 0) { return tex.r; }
	else if (channel == 1) { return tex.g; }
	else if (channel == 2) { return tex.b; }
	else if (channel == 3) { return tex.a; }
	return dot(tex.rgb, vec3(0.299, 0.587, 0.114)); // Gray
}


vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos)
{
	vec4 samp = vec4(0.0);
	samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;
	samp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;
	samp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;
	return samp;
}


void fragment() {
	// CULL MODE
	
	if (cull_mode == 1 && !FRONT_FACING) { discard; }
	if (cull_mode == 2 && FRONT_FACING) { discard; }
	
	// TEXTURES
	
	vec4 albedo_tex;
	float roughness_tex;
	float metallic_tex;
	float ao_tex;
	float specular_tex;
	vec3 emission_tex;
	
	if (uv1_triplanar)
	{
		albedo_tex = triplanar_texture(albedo_texture, uv1_power_normal, uv1_triplanar_pos);
		roughness_tex = get_texture_channel(triplanar_texture(roughness_texture, uv1_power_normal, uv1_triplanar_pos), roughness_texture_channel);
		metallic_tex = get_texture_channel(triplanar_texture(metallic_texture, uv1_power_normal, uv1_triplanar_pos), metallic_texture_channel);
		ao_tex = get_texture_channel(triplanar_texture(ao_texture, uv1_power_normal, uv1_triplanar_pos), ao_texture_channel);
		specular_tex = get_texture_channel(triplanar_texture(specular_texture, uv1_power_normal, uv1_triplanar_pos), specular_texture_channel);
		emission_tex = triplanar_texture(emission_texture, uv1_power_normal, uv1_triplanar_pos).rgb;
		NORMAL_MAP = triplanar_texture(normal_texture, uv1_power_normal, uv1_triplanar_pos).rgb;
	}
	else
	{
		albedo_tex = texture(albedo_texture, UV);
		roughness_tex = get_texture_channel(texture(roughness_texture, UV), roughness_texture_channel);
		metallic_tex = get_texture_channel(texture(metallic_texture, UV), metallic_texture_channel);
		ao_tex = get_texture_channel(texture(ao_texture, UV), ao_texture_channel);
		specular_tex = texture(specular_texture, UV).r;
		emission_tex = texture(emission_texture, UV).rgb;
		NORMAL_MAP = texture(normal_texture, UV).rgb;
	}
	
	NORMAL_MAP_DEPTH = normal_scale;
	
	// FINAL VALUES
	
	vec4 final_base = baseColor * albedo_tex;
	
	//vec3 albedo = texture(albedo_texture, UV).rgb;
	//vec3 final_rgb = baseColor.rgb * albedo;
	//vec4 final_base = vec4(final_rgb, texture(albedo_texture, UV).a * baseColor.a);
	
	float final_roughness = roughness * roughness_tex;
	float final_metallic = metallic * metallic_tex;
	float final_specular = specular * specular_tex;

	v_albedo = final_base.rgb;
	v_metallic = final_metallic;
	v_roughness = final_roughness;
	v_specular = final_specular;
	v_tangent = TANGENT;
	v_binormal = BINORMAL;
	
	
	// TRANSPARENCY
	
	float alpha = final_base.a;
	
	if (transparency_mode == 0) { ALPHA = 1.0; } // Disabled
	
	else if (transparency_mode == 1){ ALPHA = alpha; } // Alpha
	
	else if (transparency_mode == 2) // Alpha Scissor
	{
		ALPHA_SCISSOR_THRESHOLD = alpha_scissor_threshold;
		ALPHA = alpha;
	}
	
	else if (transparency_mode == 3) // Hash
	{
		float h = hash(FRAGCOORD.xy * alpha_hash_scale);
		
		if (alpha < h) { discard; }
		ALPHA = 1.0;
	}
	else if (transparency_mode == 4) { // Depth Pre-pass
		ALPHA_HASH_SCALE = alpha_hash_scale;
		ALPHA = alpha;
	}
	
	
	// OUTPUT
	
	ALBEDO = final_base.rgb;
	METALLIC = final_metallic;
	ROUGHNESS = final_roughness;
	SPECULAR = final_specular;
	ANISOTROPY = anisotropic;
	CLEARCOAT = clearcoat;
	CLEARCOAT_ROUGHNESS = 1.0 - clearcoatGloss;
	AO = ao_tex;
	EMISSION = emission_tex * emission_color * emission_energy;
}



void light() {
	vec3 N = normalize(NORMAL);
	vec3 V = normalize(VIEW);
	vec3 up = abs(N.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
	vec3 X = normalize(v_tangent); //normalize(cross(up, N)));
	vec3 Y = normalize(v_binormal); //normalize(cross(N, X)));
	
	vec3 Cdlin = mon2lin(v_albedo);
	float Cdlum = 0.3 * Cdlin.r + 0.6 * Cdlin.g + 0.1 * Cdlin.b; // luminance approx.
	
	vec3 Ctint = Cdlum > 0.0 ? Cdlin / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
	vec3 Cspec0 = mix(v_specular * dielectric_f0_scale * dielectric_f0 * mix(vec3(1.0), Ctint, specularTint), Cdlin, v_metallic);
	vec3 Csheen = mix(vec3(1.0), Ctint, sheenTint);
	
	float NdotV = max(dot(N, V), 0.0001);
	vec3 L = normalize(LIGHT);//normalize(vec3(0.4, 1.0, 0.2));
	float NdotL = max(dot(N, L), 0.0);
	vec3 H = normalize(L + V);
	float NdotH = max(dot(N, H), 0.0);
	float LdotH = max(dot(L, H), 0.0);
	
	// Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
	// and mix in diffuse retro-reflection based on roughness
	float FL = SchlickFresnel(NdotL);
	float FV = SchlickFresnel(NdotV);
	float Fd90 = 0.5 + 2.0 * LdotH * LdotH * v_roughness;
	float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);
	
	// Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
	// 1.25(subsurface_scale) scale is used to (roughly) preserve albedo
	// Fss90 used to "flatten" retroreflection based on roughness
	float Fss90 = LdotH * LdotH * v_roughness;
	float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
	float ss = subsurface_scale * (Fss * (1.0 / max(NdotL + NdotV, 0.0001) - 0.5) + 0.5);
	
	// Specular
	
	float aspect = sqrt(1.0 - anisotropic * 0.9);
	float ax = max(0.001, sqr(v_roughness) / aspect);
	float ay = max(0.001, sqr(v_roughness) * aspect);
	float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay);
	float FH = SchlickFresnel(LdotH);
	vec3 Fs = mix(Cspec0, vec3(1.0), FH);
	float Gs = smithG_GGX_aniso(NdotL, dot(L, X), dot(L, Y), ax, ay);
	Gs *= smithG_GGX_aniso(NdotV, dot(V, X), dot(V, Y), ax, ay);
	
	// Sheen
	vec3 Fsheen = FH * sheen * Csheen;
	
	// Clearcoat
	float Dr = GTR1(NdotH, mix(0.1, 0.001, clearcoatGloss));
	float Fr = mix(clearcoat_f0, 1.0, FH);
	float Gr = smithG_GGX(NdotL, clearcoat_distribution) * smithG_GGX(NdotV, clearcoat_distribution);
	
	// Final BRDF
	vec3 diffuseTerm = ((1.0 / PI) * mix(Fd, ss, subsurface) * Cdlin + Fsheen) * (1.0 - v_metallic);
	vec3 specularTerm = Gs * Fs * Ds;
	vec3 clearcoatTerm = vec3(0.25 * clearcoat * Gr * Fr * Dr);
	
	//vec3 finalColor = diffuseTerm + specularTerm + clearcoatTerm;
	
	vec3 diffuseLight = diffuseTerm * LIGHT_COLOR * ATTENUATION * NdotL;
	vec3 specularLight = (specularTerm + clearcoatTerm) * LIGHT_COLOR * ATTENUATION * NdotL;
	
	DIFFUSE_LIGHT += diffuseLight;
	SPECULAR_LIGHT += specularLight;
}
Live Preview
Tags
brdf
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.

Related shaders

guest

0 Comments
Oldest
Newest Most Voted