- Warning : This code is not optimized.
analytic
//----------------------------------------------------------------------------------------------------
// PBR test shader by hanecci
//
// This software is released under the Unlicense. ( http://unlicense.org/ )
//
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any means.
//
//----------------------------------------------------------------------------------------------------
# variables go here...
# only floats supported right now.
# [type] [name] [min val] [max val] [default val]
::begin parameters
color base_color 1.0 0.0 0.0, 0.1 1.0
float metalness 0.0 1.0 1.0
float roughness 0.0 1.0 0.1
float min_roughness 0.0 1.0 0.01
bool enable_diffuse 1
bool enable_specular 1
bool use_fresnel 1
bool use_ndf 1
bool use_geom 1
::end parameters
# Then comes the shader. This should be GLSL code
# that defines a function called BRDF (although you can
# add whatever other functions you want too).
::begin shader
const float PI = 3.14159265358979323846;
const float INV_PI = ( 1.0 / PI );
float sqr(float x) { return x*x; }
//----------------------------------------------------------------------------------------------------
float fresnelSchlick( float f0, float dot_v_h )
{
return f0 + ( 1 - f0 ) * pow( 1 - dot_v_h, 5 );
}
float fresnelSchlick( float dot_v_h )
{
float value = clamp( 1 - dot_v_h, 0.0, 1.0 );
float value2 = value * value;
return ( value2 * value2 * value );
}
float geomSchlickGGX( float alpha, float dot_n_v )
{
float k = 0.5 * alpha;
float geom = dot_n_v / ( dot_n_v * ( 1 - k ) + k );
return geom;
}
float ndfGGX(float alpha, float NdotH )
{
float alpha2 = alpha * alpha;
float t = 1 + ( alpha2 - 1 ) * NdotH * NdotH;
return INV_PI * alpha2 / ( t * t );
}
vec3 BRDF( vec3 l, vec3 v, vec3 n, vec3 x, vec3 y )
{
float dot_n_v = dot( n, v );
float dot_n_l = dot( n, l );
vec3 color = vec3( 0.0, 0.0, 0.0 );
vec3 diffuse_color = vec3( 0.0, 0.0, 0.0 );
float dot_n_l_clamp = max( dot_n_l , 0.0 );
if ( enable_diffuse )
{
diffuse_color = base_color;
}
vec3 specular_color = vec3( 0.0, 0.0, 0.0 );
if ( enable_specular )
{
vec3 h = normalize( l + v );
specular_color = mix( vec3( base_color ), vec3( 1.0 ), ( 1.0 - metalness ) );
if ( use_fresnel )
{
float dot_v_h = dot( v, h );
float fresnel = fresnelSchlick( dot_v_h );
vec3 f0_color = mix( base_color, vec3( 1.0 ), ( 1.0 - metalness ) );
specular_color = mix( f0_color , vec3( 1.0 ), fresnel );
}
float alpha = 1.0;
if ( use_ndf || use_geom )
{
float clamp_roughness = max( roughness, min_roughness );
alpha = clamp_roughness * clamp_roughness;
}
float ndf = 1.0;
if ( use_ndf )
{
float dot_n_h = dot ( n, h );
ndf = ndfGGX( alpha, dot_n_h );
}
float geom = 1.0;
if ( use_geom )
{
geom = geomSchlickGGX( alpha, dot_n_v );
}
float specular_brdf = ( 0.25 * ndf * geom ) / ( dot_n_l * dot_n_v );
specular_color *= specular_brdf;
}
if ( enable_diffuse && enable_specular )
{
color = INV_PI * ( 1.0 - metalness ) * diffuse_color + specular_color;
}
else if ( enable_diffuse && ( ! enable_specular ) )
{
color = INV_PI * diffuse_color * ( 1.0 - metalness );
}
else if ( ( ! enable_diffuse ) && enable_specular )
{
color = specular_color;
}
color *= dot_n_l_clamp;
return color;
}
::end shader