Emmanuel BENOîT
68d01ca42e
Shaders are no longer found under /shaders in the project; they can be anywhere. In addition, paths for both (program) instructions in the script and include directives in shader source code are relative to the file which contains them.
144 lines
3.6 KiB
GLSL
144 lines
3.6 KiB
GLSL
//! type library
|
|
//! include utils.glsl
|
|
|
|
|
|
struct T_PBRMaterial
|
|
{
|
|
vec3 cAlbedo;
|
|
float roughness;
|
|
float metallic;
|
|
float subsurface;
|
|
float anisotropy;
|
|
float specular; // Specular strengh for non-metals
|
|
float specularTint; // Albedo color% in specular tint (non-metals)
|
|
};
|
|
|
|
struct T_PBRPrecomputed
|
|
{
|
|
float nDotV , ax , ay , fv , vgs;
|
|
vec3 tangent , bitangent , cSpecular;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
float PBR_SchlickFresnel(
|
|
in float u )
|
|
{
|
|
const float m = 1 - u , m2 = M_Sqr( m );
|
|
return M_Sqr( m2 ) * m;
|
|
}
|
|
|
|
float PBR_GTR2Aniso(
|
|
in float nDotH ,
|
|
in float hDotX ,
|
|
in float hDotY ,
|
|
in float ax ,
|
|
in float ay )
|
|
{
|
|
float x = hDotX / ax , y = hDotY / ay ,
|
|
p = x * x + y * y + nDotH * nDotH;
|
|
return 1 / ( ax * ay * p * p );
|
|
}
|
|
|
|
float PBR_SmithGGXAniso(
|
|
in float nDotV ,
|
|
in float vDotX ,
|
|
in float vDotY ,
|
|
in float ax ,
|
|
in float ay )
|
|
{
|
|
float x = vDotX * ax , y = vDotY * ay;
|
|
return 1 / ( nDotV + sqrt( x * x + y * y + nDotV * nDotV ) );
|
|
}
|
|
|
|
T_PBRPrecomputed PBR_Precompute(
|
|
in T_PBRMaterial material ,
|
|
in vec3 camDir ,
|
|
in vec3 normal )
|
|
{
|
|
T_PBRPrecomputed rv;
|
|
|
|
rv.nDotV = abs( dot( normal , camDir ) ) + 1e-5;
|
|
rv.fv = PBR_SchlickFresnel( rv.nDotV );
|
|
|
|
float tDir = step( .99 , abs( normal.z ) ) ,
|
|
aspect = sqrt( 1 - material.anisotropy * .9 ) ,
|
|
rsqr = M_Sqr( material.roughness );
|
|
|
|
vec3 tUp = mix( vec3( 0 , 0 , 1 ) , vec3( 1 , 0 , 0 ) , tDir ) ,
|
|
tint = M_NormalizeColor( material.cAlbedo );
|
|
rv.tangent = normalize( cross( tUp , normal ) );
|
|
rv.bitangent = normalize( cross( normal , rv.tangent ) );
|
|
|
|
rv.cSpecular = mix(
|
|
material.specular * .08 * mix(
|
|
vec3( 1 ) , tint , material.specularTint ) ,
|
|
material.cAlbedo , material.metallic );
|
|
|
|
rv.ax = max( .001, rsqr / aspect );
|
|
rv.ay = max( .001, rsqr * aspect );
|
|
rv.vgs = PBR_SmithGGXAniso( rv.nDotV ,
|
|
dot( camDir , rv.tangent ) , dot( camDir , rv.bitangent ) ,
|
|
rv.ax , rv.ay );
|
|
|
|
return rv;
|
|
}
|
|
|
|
vec3 PBR_Shade(
|
|
in T_PBRMaterial material ,
|
|
in T_PBRPrecomputed pre ,
|
|
in vec3 camDir ,
|
|
in vec3 normal ,
|
|
in vec3 lightDir )
|
|
{
|
|
float nDotL = dot( normal , lightDir );
|
|
if ( nDotL < 0 ) {
|
|
return vec3( 0 );
|
|
}
|
|
|
|
vec3 halfVec = normalize( lightDir + camDir ) ;
|
|
float nDotH = M_Saturate( dot( normal , halfVec ) ) ,
|
|
lDotH = M_Saturate( dot( lightDir , halfVec ) ) ,
|
|
|
|
// Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
|
|
// and mix in diffuse retro-reflection based on roughness
|
|
FL = PBR_SchlickFresnel( nDotL ) ,
|
|
Fd90 = ( 0.5 + 2 * lDotH * lDotH ) * material.roughness ,
|
|
Fd = ( 1 + ( Fd90 - 1 ) * FL )
|
|
* ( 1 + ( Fd90 - 1 ) * pre.fv )
|
|
* ( 1 - 0.51 * material.roughness / 1.51 ) ,
|
|
|
|
// Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
|
|
// 1.25 scale is used to (roughly) preserve albedo
|
|
// Fss90 used to "flatten" retroreflection based on roughness
|
|
Fss90 = lDotH * lDotH * material.roughness ,
|
|
Fss = mix( 1 , Fss90 , FL ) * mix( 1 , Fss90 , pre.fv ) ,
|
|
ss = 1.25 * ( Fss * ( 1 / ( nDotL + pre.nDotV ) - .5 ) + .5 ) ,
|
|
|
|
// Specular
|
|
Ds = PBR_GTR2Aniso( nDotH , dot( halfVec , pre.tangent ) ,
|
|
dot( halfVec , pre.bitangent ) ,
|
|
pre.ax , pre.ay ) ,
|
|
FH = PBR_SchlickFresnel( lDotH ) ,
|
|
Gs = PBR_SmithGGXAniso( nDotL , dot( lightDir , pre.tangent ) ,
|
|
dot( lightDir , pre.bitangent ) ,
|
|
pre.ax , pre.ay ) * pre.vgs;
|
|
|
|
vec3 Fs = mix( pre.cSpecular , vec3(1) , FH );
|
|
return nDotL * ( mix( Fd , ss , material.subsurface )
|
|
* material.cAlbedo
|
|
* ( 1 - material.metallic )
|
|
+ Gs * Fs * Ds ) / PI;
|
|
}
|
|
|
|
vec3 PBR_Shade(
|
|
in T_PBRMaterial material ,
|
|
in vec3 camDir ,
|
|
in vec3 normal ,
|
|
in vec3 lightDir )
|
|
{
|
|
return PBR_Shade(
|
|
material ,
|
|
PBR_Precompute( material , camDir , normal ) ,
|
|
camDir , normal , lightDir );
|
|
}
|