Skip to content

Instantly share code, notes, and snippets.

@yiwenl
Last active May 23, 2019 08:20
Show Gist options
  • Save yiwenl/acb9800ce465aa77113c4c55c918a6ef to your computer and use it in GitHub Desktop.
Save yiwenl/acb9800ce465aa77113c4c55c918a6ef to your computer and use it in GitHub Desktop.
#extension GL_EXT_shader_texture_lod : enable
uniform samplerCube uRadianceMap;
uniform samplerCube uIrradianceMap;
#define saturate(x) clamp(x, 0.0, 1.0)
#define PI 3.1415926535897932384626433832795
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;
}
// https://www.unrealengine.com/blog/physically-based-shading-on-mobile
vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
{
const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022 );
const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04 );
vec4 r = Roughness * c0 + c1;
float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
return SpecularColor * AB.x + AB.y;
}
// http://the-witness.net/news/2012/02/seamless-cube-map-filtering/
vec3 fix_cube_lookup( vec3 v, float cube_size, float lod ) {
float M = max(max(abs(v.x), abs(v.y)), abs(v.z));
float scale = 1.0 - exp2(lod) / cube_size;
if (abs(v.x) != M) v.x *= scale;
if (abs(v.y) != M) v.y *= scale;
if (abs(v.z) != M) v.z *= scale;
return v;
}
vec3 correctGamma(vec3 color, float g) {
return pow(color, vec3(1.0/g));
}
vec3 getPbr(vec3 N, vec3 V, vec3 baseColor, float roughness, float metallic, float specular) {
vec3 diffuseColor = baseColor - baseColor * metallic;
vec3 specularColor = mix( vec3( 0.08 * specular ), baseColor, specular );
vec3 color;
float roughness4 = pow(roughness, 4.0);
// sample the pre-filtered cubemap at the corresponding mipmap level
float numMips = 6.0;
float mip = numMips - 1.0 + log2(roughness);
vec3 lookup = -reflect( V, N );
lookup = fix_cube_lookup( lookup, 512.0, mip );
vec3 radiance = pow( textureCubeLodEXT( uRadianceMap, lookup, mip ).rgb, vec3( 2.2 ) );
vec3 irradiance = pow( textureCube( uIrradianceMap, N ).rgb, vec3( 1 ) );
// get the approximate reflectance
float NoV = saturate( dot( N, V ) );
vec3 reflectance = EnvBRDFApprox( specularColor, roughness4, NoV );
// combine the specular IBL and the BRDF
vec3 diffuse = diffuseColor * irradiance;
vec3 _specular = radiance * reflectance;
color = diffuse + _specular;
vec3 ao = texture2D(uAoMap, vTextureCoord).rgb;
color *= ao;
return color;
}
#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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment