@@ -0,0 +1,103 @@
#define saturate(x) clamp(x, 0.0, 1.0)
#define PI 3.14159265359
// OrenNayar diffuse
vec3 getDiffuse( vec3 diffuseColor, float roughness4, float NoV, float NoL, float VoH )
{
float VoL = 2.0 * VoH - 1.0;
float c1 = 1.0 - 0.5 * roughness4 / (roughness4 + 0.33);
float cosri = VoL - NoV * NoL;
float c2 = 0.45 * roughness4 / (roughness4 + 0.09) * cosri * ( cosri >= 0.0 ? min( 1.0, NoL / NoV ) : NoL );
return diffuseColor / PI * ( NoL * c1 + c2 );
}
// GGX Normal distribution
float getNormalDistribution( float roughness4, float NoH )
{
float d = ( NoH * roughness4 - NoH ) * NoH + 1.0;
return roughness4 / ( d*d );
}
// Smith GGX geometric shadowing from "Physically-Based Shading at Disney"
float getGeometricShadowing( float roughness4, float NoV, float NoL, float VoH, vec3 L, vec3 V )
{
float gSmithV = NoV + sqrt( NoV * (NoV - NoV * roughness4) + roughness4 );
float gSmithL = NoL + sqrt( NoL * (NoL - NoL * roughness4) + roughness4 );
return 1.0 / ( gSmithV * gSmithL );
}
// Fresnel term
vec3 getFresnel( vec3 specularColor, float VoH )
{
vec3 specularColorSqrt = sqrt( clamp( vec3(0.0, 0.0, 0.0), vec3(0.99, 0.99, 0.99), specularColor ) );
vec3 n = ( 1.0 + specularColorSqrt ) / ( 1.0 - specularColorSqrt );
vec3 g = sqrt( n * n + VoH * VoH - 1.0 );
return 0.5 * pow( (g - VoH) / (g + VoH), vec3(2.0) ) * ( 1.0 + pow( ((g+VoH)*VoH - 1.0) / ((g-VoH)*VoH + 1.0), vec3(2.0) ) );
}
const float A = 0.15;
const float B = 0.50;
const float C = 0.10;
const float D = 0.20;
const float E = 0.02;
const float F = 0.30;
vec3 Uncharted2Tonemap( vec3 x )
{
return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
}
// From "I'm doing it wrong"
// http://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
float getAttenuation( vec3 lightPosition, vec3 vertexPosition, float lightRadius )
{
float r = lightRadius;
vec3 L = lightPosition - vertexPosition;
float dist = length(L);
float d = max( dist - r, 0.0 );
L /= dist;
float denom = d / r + 1.0;
float attenuation = 1.0 / (denom*denom);
float cutoff = 0.0052;
attenuation = (attenuation - cutoff) / (1.0 - cutoff);
attenuation = max(attenuation, 0.0);
return attenuation;
}
vec3 getPbrPointLight(vec3 normal, vec3 position, vec3 lightPosition, vec3 lightColor, float lightRadius) {
// vLightPosition = ( uViewMatrix * vec4( uLightPosition, 1.0 ) ).xyz;
vec3 N = normalize( normal );
vec3 L = normalize( lightPosition - position );
vec3 V = normalize( -position );
vec3 H = normalize(V + L);
float NoL = saturate( dot( N, L ) );
float NoV = saturate( dot( N, V ) );
float VoH = saturate( dot( V, H ) );
float NoH = saturate( dot( N, H ) );
// deduce the diffuse and specular color from the baseColor and how metallic the material is
vec3 diffuseColor = uBaseColor - uBaseColor * uMetallic;
vec3 specularColor = mix( vec3( 0.8 * uSpecular ), uBaseColor, uMetallic );
// compute the brdf terms
float distribution = getNormalDistribution( uRoughness, NoH );
vec3 fresnel = getFresnel( specularColor, VoH );
float geom = getGeometricShadowing( uRoughness, NoV, NoL, VoH, L, V );
// get the specular and diffuse and combine them
vec3 diffuse = getDiffuse( diffuseColor, uRoughness, NoV, NoL, VoH );
vec3 specular = NoL * ( distribution * fresnel * geom );
vec3 color = lightColor * ( diffuse + specular );
// get the light attenuation from its radius
float attenuation = getAttenuation( lightPosition, position, lightRadius );
color *= attenuation;
return color;
}