387 lines
12 KiB
Plaintext
387 lines
12 KiB
Plaintext
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
struct deferredMaterialData {
|
||
|
|
vec3 normal;
|
||
|
|
vec3 baseColor;
|
||
|
|
vec3 diffuse;
|
||
|
|
vec3 position;
|
||
|
|
vec3 vertex;
|
||
|
|
vec3 specularReflectance;
|
||
|
|
|
||
|
|
|
||
|
|
float reflectance;
|
||
|
|
float metallic;
|
||
|
|
float roughness;
|
||
|
|
float clearCoatRoughness;
|
||
|
|
float geometricRoughness;
|
||
|
|
float ambientOcclusion;
|
||
|
|
float shadowOcclusion;
|
||
|
|
float eta;
|
||
|
|
float refracted_NoV;
|
||
|
|
float index;
|
||
|
|
|
||
|
|
float alpha;
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
float D_GGX(float NoH, float a) {
|
||
|
|
float a2 = a * a;
|
||
|
|
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
||
|
|
return a2 / (PI * f * f);
|
||
|
|
}
|
||
|
|
|
||
|
|
float D_GGX_Anisotropy(float NoH, vec3 h, vec3 x, vec3 y, float ax, float ay) {
|
||
|
|
float XoH = dot(x, h);
|
||
|
|
float YoH = dot(y, h);
|
||
|
|
float d = XoH * XoH * (ax * ax) + YoH * YoH * (ay * ay) + NoH * NoH;
|
||
|
|
return (ax * ay) / (PI * d * d);
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 F_Schlick(float VoH, vec3 specularReflectance, float f90) {
|
||
|
|
return specularReflectance + (vec3(f90) - specularReflectance) * pow(1.0 - VoH, 5.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
float V_SmithGGXCorrelated(float NoV, float NoL, float a) {
|
||
|
|
float a2 = a * a;
|
||
|
|
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
||
|
|
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
||
|
|
return 0.5 / (GGXV + GGXL);
|
||
|
|
}
|
||
|
|
|
||
|
|
float Fd_Lambert() {
|
||
|
|
return 1.0 / PI;
|
||
|
|
}
|
||
|
|
|
||
|
|
float F_Schlick_Scalar(float VoH, float specularReflectance, float f90) {
|
||
|
|
return specularReflectance + (f90 - specularReflectance) * pow(1.0 - VoH, 5.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
float square(float v) {
|
||
|
|
return v * v;
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 irradianceSH(vec3 n) {
|
||
|
|
return
|
||
|
|
vec3(0.754553530212464, 0.748541695286661, 0.790922541330174)
|
||
|
|
+ vec3(-0.083855089181764, 0.092536341322488, 0.322767327275582) * (n.y)
|
||
|
|
+ vec3(0.308154551673257, 0.366799355358085, 0.466705760819624) * (n.z)
|
||
|
|
+ vec3(-0.188887618191928, -0.277403749518126, -0.377844811540716) * (n.x)
|
||
|
|
|
||
|
|
+ vec3(-0.252782448589491, -0.316051613736677, -0.396141020484574) * (n.y * n.x)
|
||
|
|
+ vec3(0.071362454444021, 0.159789075773366, 0.29059362717571) * (n.y * n.z)
|
||
|
|
+ vec3(-0.031040420617065, -0.031141089772695, -0.031044001883204) * (3.0 * n.z * n.z - 1.0)
|
||
|
|
+ vec3(-0.161001896026477, -0.203649521035777, -0.246641086569566) * (n.z * n.x)
|
||
|
|
+ vec3(0.045710934605387, 0.048121779682969, 0.046326375668417) * (n.x * n.x - n.y * n.y);
|
||
|
|
}
|
||
|
|
|
||
|
|
vec2 prefilteredDFGKaris(float NoV, float roughness) {
|
||
|
|
// see https://www.unrealengine.com/blog/physically-based-shading-on-mobile
|
||
|
|
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
||
|
|
const vec4 c1 = vec4( 1.0, 0.0425, 1.040, -0.040);
|
||
|
|
vec4 r = roughness * c0 + c1;
|
||
|
|
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
|
||
|
|
return vec2(-1.04, 1.04) * a004 + r.zw;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
float sRGBtoLinear(float c) {
|
||
|
|
return (c <= 0.04045) ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 sRGBtoLinear(vec3 c) {
|
||
|
|
return vec3(sRGBtoLinear(c.r), sRGBtoLinear(c.g), sRGBtoLinear(c.b));
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 decodeEnvironmentMap(vec4 c) {
|
||
|
|
return c.rgb;//;sRGBtoLinear(c.rgb) ;
|
||
|
|
}
|
||
|
|
|
||
|
|
float getSquareFalloffAttenuation(float distanceSquare) {
|
||
|
|
float factor = distanceSquare * lightGeometry.x;
|
||
|
|
float smoothFactor = max(1.0 - factor * factor, 0.0);
|
||
|
|
return smoothFactor * smoothFactor;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
float getPhotometricAttenuation(vec3 lightToPos, vec3 lightDir) {
|
||
|
|
return 1.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
float getAngleAttenuation(vec3 l, vec3 lightDir) {
|
||
|
|
float cd = dot(lightDir, l);
|
||
|
|
float attenuation = clamp(cd * lightGeometry.y + lightGeometry.z, 0.0, 1.0);
|
||
|
|
return attenuation * attenuation;
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 beerLambert(float NoV, float NoL, vec3 alpha, float d) {
|
||
|
|
return exp(alpha * -(d * ((NoL + NoV) / max(NoL * NoV, 1e-3))));
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 fixCubemapLookup(vec3 v, float lod) {
|
||
|
|
vec3 r = abs(v);
|
||
|
|
float M = max(max(v.x, v.y), v.z);
|
||
|
|
float scale = 1.0 - exp2(lod) * (1.0 / 256.0);
|
||
|
|
if (v.x != M) v.x *= scale;
|
||
|
|
if (v.y != M) v.y *= scale;
|
||
|
|
if (v.z != M) v.z *= scale;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
vec3 evaluateSpecularIBL(vec3 r, float roughness) {
|
||
|
|
float lod = 5.0 * roughness;
|
||
|
|
|
||
|
|
r = fixCubemapLookup(r, lod);
|
||
|
|
|
||
|
|
return decodeEnvironmentMap( texture(reflectionSampler, r, lod) ); //, lod * 3.
|
||
|
|
}
|
||
|
|
|
||
|
|
float computeSpecularambientOcclusion(float NoV, float ambientOcclusion, float roughness) {
|
||
|
|
return clamp(pow(NoV + ambientOcclusion, exp2(-16.0 * roughness - 1.0)) - 1.0 + ambientOcclusion, 0.0, 1.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 getSpecularDominantDirection(vec3 n, vec3 r, float roughness) {
|
||
|
|
float s = 1.0 - roughness;
|
||
|
|
return mix(n, r, s * (sqrt(s) + roughness));
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
vec3 evaluateIBL( deferredMaterialData materialData ) { //, deferredLightData params
|
||
|
|
|
||
|
|
vec3 normal = materialData.normal;
|
||
|
|
vec3 vertex = materialData.vertex;
|
||
|
|
|
||
|
|
|
||
|
|
float roughness = materialData.roughness;
|
||
|
|
|
||
|
|
float NoV = max( dot(normal, vertex), 0.0 );
|
||
|
|
|
||
|
|
#if ANISOTROPY == 1
|
||
|
|
vec3 t = normalize( materialData.tangent );
|
||
|
|
vec3 b = normalize( cross(t, normal));
|
||
|
|
|
||
|
|
vec3 anisotropicTangent = cross(-vertex, b);
|
||
|
|
vec3 anisotropicNormal = cross(anisotropicTangent, b);
|
||
|
|
vec3 bentNormal = normalize(mix(normal, anisotropicNormal, anisotropy));
|
||
|
|
|
||
|
|
vec3 r = reflect( vertex, bentNormal );
|
||
|
|
#else
|
||
|
|
vec3 r = reflect( -vertex, normal );
|
||
|
|
r = getSpecularDominantDirection(normal, r, roughness * roughness);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
float NoR = max( dot(r, normal), 0.0);
|
||
|
|
|
||
|
|
// specular indirect
|
||
|
|
vec3 indirectSpecular = evaluateSpecularIBL( reflect(vertex, normal), roughness);
|
||
|
|
|
||
|
|
// horizon occlusion, can be removed for performance
|
||
|
|
//float horizon = min(1.0 + NoR, 1.0);
|
||
|
|
//indirectSpecular *= horizon * horizon;
|
||
|
|
|
||
|
|
vec2 env = prefilteredDFGKaris( NoV, materialData.roughness );
|
||
|
|
// we should multiply env.y by f90 for more accurate results
|
||
|
|
vec3 specularColor = materialData.specularReflectance * env.x + env.y * (1.0 - clearCoat) *
|
||
|
|
clamp(dot(materialData.specularReflectance, vec3(50.0 * 0.33)), 0.0, 1.0);
|
||
|
|
|
||
|
|
// diffuse indirect
|
||
|
|
vec3 indirectDiffuse = max(irradianceSH(normal), 0.0) * Fd_Lambert();
|
||
|
|
// ambient occlusion
|
||
|
|
float ambientOcclusionFade = clamp(dot(normalize(normal), vertex), 0.0, 1.0);
|
||
|
|
float ambientOcclusion = mix(1.0, materialData.ambientOcclusion, ambientOcclusionFade);
|
||
|
|
indirectDiffuse *= ambientOcclusion;
|
||
|
|
//indirectDiffuse *= 4.0;
|
||
|
|
// TODO: Not really useful without SSambientOcclusion/HBambientOcclusion/etc.
|
||
|
|
indirectSpecular *= computeSpecularambientOcclusion(NoV, ambientOcclusion, materialData.roughness);
|
||
|
|
|
||
|
|
// clear coat
|
||
|
|
float Fcc = F_Schlick_Scalar(NoV, 0.04, 1.0) * 0.2;
|
||
|
|
#if ANISOTROPY == 1
|
||
|
|
// We used the bent normal for the base layer
|
||
|
|
r = reflect(-vertex, normal);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
|
||
|
|
vec3 indirectClearCoatSpecular = evaluateSpecularIBL(reflect(vertex, normal), materialData.clearCoatRoughness);
|
||
|
|
|
||
|
|
|
||
|
|
vec3 clearCoatAbsorption = mix(vec3(1.0),
|
||
|
|
beerLambert(materialData.refracted_NoV, materialData.refracted_NoV, clearCoatColor, clearCoatThickness),
|
||
|
|
clearCoat);
|
||
|
|
|
||
|
|
// indirect contribution
|
||
|
|
vec3 color =
|
||
|
|
(materialData.diffuse * indirectDiffuse + indirectSpecular * specularColor)//kaj materialData.diffuse * indirectDiffuse
|
||
|
|
* (1.0 - Fcc) * clearCoatAbsorption +
|
||
|
|
indirectClearCoatSpecular * Fcc;
|
||
|
|
|
||
|
|
#if TRANSLUCENT_MATERIAL == 1
|
||
|
|
indirectDiffuse = max(irradianceSH(-vertex), 0.0) * Fd_Lambert();
|
||
|
|
vec3 tL = -vertex + normal * translucencyDistortion;
|
||
|
|
float tD = pow(clamp(dot(vertex, -tL), 0.0, 1.0), translucencyPower) * translucencyScale;
|
||
|
|
vec3 tT = (tD + translucencyAmbient) * texture(translucencyThicknessMap, outUV).r;
|
||
|
|
color.rgb += materialData.diffuse * indirectDiffuse * tT;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return color;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
vec3 getNormal(vec3 n) {
|
||
|
|
|
||
|
|
return normalize(n);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
vec3 evaluateLight( deferredMaterialData params ) {
|
||
|
|
|
||
|
|
vec3 n = params.normal;
|
||
|
|
vec3 v = params.vertex;
|
||
|
|
|
||
|
|
vec3 l;
|
||
|
|
float NoL;
|
||
|
|
float energy;
|
||
|
|
float attenuation;
|
||
|
|
|
||
|
|
vec3 lightDir = normalize(lightDirection);
|
||
|
|
float linearRoughness = params.roughness * params.roughness;
|
||
|
|
|
||
|
|
vec3 r = reflect(-v, n);
|
||
|
|
|
||
|
|
if (lightType == 1.0) {
|
||
|
|
|
||
|
|
l = -lightDir;
|
||
|
|
|
||
|
|
// Disc area light
|
||
|
|
vec3 sunDir = -lightDir;
|
||
|
|
float e = sin(radians(0.53));
|
||
|
|
float d = cos(radians(0.53));
|
||
|
|
float DoR = dot(sunDir, r);
|
||
|
|
vec3 s = r - DoR * sunDir;
|
||
|
|
l = DoR < d ? normalize(d * sunDir + normalize(s) * e) : r;
|
||
|
|
|
||
|
|
NoL = dot(n, l);
|
||
|
|
energy = 1.0;
|
||
|
|
attenuation = 1.0;
|
||
|
|
|
||
|
|
|
||
|
|
} else if (lightType == 0.0) {
|
||
|
|
|
||
|
|
vec3 posToLight = lightPosition - params.position;
|
||
|
|
float distanceSquare = dot(posToLight, posToLight);
|
||
|
|
l = normalize(posToLight);
|
||
|
|
NoL = dot(n, l);
|
||
|
|
energy = 50.0;
|
||
|
|
attenuation = getSquareFalloffAttenuation(distanceSquare);
|
||
|
|
attenuation *= 1.0 / max(distanceSquare, 1e-4);
|
||
|
|
attenuation *= getPhotometricAttenuation(-l, lightDir);
|
||
|
|
// if (lightGeometry.w >= 1.0) {
|
||
|
|
// attenuation *= getAngleAttenuation(l, -lightDir);
|
||
|
|
// }
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
vec3 h = normalize(v + l);
|
||
|
|
|
||
|
|
NoL = clamp(NoL, 0.0, 1.0);
|
||
|
|
float NoV = abs(dot(n, v)) + 1e-5;
|
||
|
|
float NoH = clamp(dot(n, h), 0.0, 1.0);
|
||
|
|
float LoH = clamp(dot(l, h), 0.0, 1.0);
|
||
|
|
|
||
|
|
// specular BRDF
|
||
|
|
#if ANISOTROPY == 1
|
||
|
|
vec3 t = normalize(v_tangent.xyz);
|
||
|
|
vec3 b = normalize(cross(t, n));
|
||
|
|
|
||
|
|
float aspect = inversesqrt(1.0 - anisotropy * 0.9);
|
||
|
|
float ax = 1.0 / (linearRoughness * aspect);
|
||
|
|
float ay = aspect / linearRoughness;
|
||
|
|
|
||
|
|
float D = D_GGX_Anisotropy(NoH, h, t, b, ax, ay);
|
||
|
|
#else
|
||
|
|
float D = D_GGX(NoH, linearRoughness);
|
||
|
|
#endif
|
||
|
|
vec3 F = F_Schlick(LoH, params.specularReflectance, clamp(dot(params.specularReflectance, vec3(50.0 * 0.33)), 0.0, 1.0));
|
||
|
|
float V = V_SmithGGXCorrelated(NoV, NoL, linearRoughness);
|
||
|
|
vec3 Fr = (D * V) * F;
|
||
|
|
|
||
|
|
// diffuse BRDF
|
||
|
|
vec3 Fd = params.diffuse * Fd_Lambert();// * 3.6
|
||
|
|
|
||
|
|
// clear coat
|
||
|
|
float linearClearCoatRoughness = params.clearCoatRoughness * params.clearCoatRoughness;
|
||
|
|
float Dcc = D_GGX(NoH, linearClearCoatRoughness);
|
||
|
|
float Fcc = F_Schlick_Scalar(LoH, 0.04, 1.0) * clearCoat;
|
||
|
|
float Vcc = V_SmithGGXCorrelated(NoV, NoL, linearClearCoatRoughness);
|
||
|
|
float FrCC = Dcc * Vcc * Fcc;
|
||
|
|
|
||
|
|
vec3 refracted_l = -refract(l, n, params.eta);
|
||
|
|
float refracted_NoL = clamp(dot(n, refracted_l), 0.0, 1.0);
|
||
|
|
vec3 clearCoatAbsorption = mix(vec3(1.0),
|
||
|
|
beerLambert(params.refracted_NoV, refracted_NoL, clearCoatColor, clearCoatThickness),
|
||
|
|
clearCoat);
|
||
|
|
|
||
|
|
// direct contribution
|
||
|
|
vec3 color = (attenuation * NoL) * lightColor * lightIntensity * energy *
|
||
|
|
((Fd + Fr) * (1.0 - Fcc) * clearCoatAbsorption + FrCC);
|
||
|
|
|
||
|
|
#if TRANSLUCENT_MATERIAL == 1
|
||
|
|
vec3 tL = l + n * translucencyDistortion;
|
||
|
|
float tD = exp2(clamp(dot(v, -tL), 0.0, 1.0) * translucencyPower - translucencyPower) * translucencyScale;
|
||
|
|
vec3 tT = attenuation * lightIntensity * (tD + translucencyAmbient) * texture(translucencyThicknessMap, outUV).r;
|
||
|
|
color.rgb += Fd * lightColor * tT;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// micro-shadowing
|
||
|
|
float aperture = 2.0 * params.ambientOcclusion * params.ambientOcclusion * params.shadowOcclusion;
|
||
|
|
float microShadow = clamp(abs(dot(l, n)) + aperture - 1.0, 0.0, 1.0);
|
||
|
|
color.rgb *= microShadow;
|
||
|
|
|
||
|
|
return color;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
vec4 physically_based_shading( deferredMaterialData materialData ) {
|
||
|
|
|
||
|
|
//deferredLightData lightData;
|
||
|
|
materialData.diffuse = (1.0 - metallic) * materialData.baseColor;
|
||
|
|
|
||
|
|
// Geometric AA
|
||
|
|
vec3 ndFdx = dFdx( materialData.normal );
|
||
|
|
vec3 ndFdy = dFdy( materialData.normal );
|
||
|
|
|
||
|
|
materialData.geometricRoughness = pow( max( dot(ndFdx, ndFdx), dot(ndFdy, ndFdy) ), 0.333);
|
||
|
|
materialData.roughness = max(materialData.roughness, materialData.geometricRoughness);
|
||
|
|
|
||
|
|
materialData.specularReflectance = 0.16 *
|
||
|
|
materialData.reflectance * materialData.reflectance * (1.0 - metallic) +
|
||
|
|
materialData.baseColor * materialData.metallic;
|
||
|
|
|
||
|
|
|
||
|
|
materialData.clearCoatRoughness = max( mix(0.089, 0.6, clearCoatRoughness), materialData.geometricRoughness);
|
||
|
|
materialData.eta = 1.0 / clearCoatIOR;
|
||
|
|
|
||
|
|
materialData.vertex = normalize( cameraPosition - materialData.position ); // v
|
||
|
|
|
||
|
|
vec3 refracted_vertex = -refract(materialData.vertex, materialData.normal, materialData.eta);
|
||
|
|
|
||
|
|
materialData.refracted_NoV = clamp(dot(materialData.normal, refracted_vertex), 0.0, 1.0);
|
||
|
|
|
||
|
|
|
||
|
|
float alpha = 1.0;
|
||
|
|
|
||
|
|
// indirect lighting
|
||
|
|
vec3 color = evaluateIBL( materialData );
|
||
|
|
|
||
|
|
color *= environmentLuminance;
|
||
|
|
|
||
|
|
|
||
|
|
color += evaluateLight(materialData);
|
||
|
|
return vec4(color, alpha);
|
||
|
|
}
|