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;
}

