206 lines
6.4 KiB
GLSL
Executable File
206 lines
6.4 KiB
GLSL
Executable File
|
|
|
|
// Struct definitions (unchanged)
|
|
struct deferredMaterialData {
|
|
vec3 baseColor;
|
|
vec3 diffuse;
|
|
vec3 specularReflectance;
|
|
vec3 normal;
|
|
vec3 vertex;
|
|
float roughness;
|
|
float metallic;
|
|
float ambientOcclusion;
|
|
float alpha;
|
|
float clearcoat;
|
|
float clearcoatRoughness;
|
|
#if ANISOTROPY == 1
|
|
vec3 tangent;
|
|
#endif
|
|
#if TRANSLUCENT_MATERIAL == 1
|
|
float translucency;
|
|
float translucencyDistortion;
|
|
float translucencyPower;
|
|
float translucencyScale;
|
|
float translucencyAmbient;
|
|
#endif
|
|
float geometricRoughness;
|
|
};
|
|
|
|
struct deferredLightData {
|
|
vec3 direction;
|
|
float length;
|
|
float radius;
|
|
float inverseFalloff;
|
|
int lightType;
|
|
vec3 color;
|
|
};
|
|
|
|
// ————————— Optimized BRDF & utilities —————————
|
|
|
|
float D_GGX(float NoH, float a) {
|
|
float a2 = a * a;
|
|
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
|
return a2 / max(PI * f * f, 1e-5);
|
|
}
|
|
|
|
float D_GGX_Anisotropy(float NoH, vec3 h, vec3 x, vec3 y, float ax, float ay) {
|
|
float XoH = dot(x, h), YoH = dot(y, h);
|
|
float d = XoH * XoH * (ax*ax) + YoH * YoH * (ay*ay) + NoH * NoH;
|
|
return (ax * ay) / max(PI * d * d, 1e-5);
|
|
}
|
|
|
|
vec3 F_Schlick(float VoH, vec3 F0, float f90) {
|
|
float pow5 = pow(1.0 - VoH, 5.0);
|
|
return F0 + (vec3(f90) - F0) * pow5;
|
|
}
|
|
|
|
float V_SmithGGXCorrelated(float NoV, float NoL, float a) {
|
|
float a2 = a * a;
|
|
float gv = sqrt(max((-NoV*a2 + NoV) * NoV + a2, 0.0));
|
|
float gl = sqrt(max((-NoL*a2 + NoL) * NoL + a2, 0.0));
|
|
return 0.5 / max(NoL * gv + NoV * gl, 1e-5);
|
|
}
|
|
|
|
float Fd_Lambert() {
|
|
return 1.0 / PI;
|
|
}
|
|
|
|
float F_Schlick_Scalar(float VoH, float F0, float f90) {
|
|
float pow5 = pow(1.0 - VoH, 5.0);
|
|
return F0 + (f90 - F0) * pow5;
|
|
}
|
|
|
|
vec3 irradianceSH(vec3 n) {
|
|
float nx = n.x, ny = n.y, nz = n.z;
|
|
float nymnx = ny * nx, nynz = ny * nz, nz2 = nz * nz, nxx_nyy = nx*nx - ny*ny;
|
|
return
|
|
vec3(0.7545535, 0.7485417, 0.7909225)
|
|
+ vec3(-0.08385509, 0.09253634, 0.3227673) * ny
|
|
+ vec3(0.3081546, 0.3667994, 0.4667058) * nz
|
|
+ vec3(-0.1888876, -0.2774037, -0.3778448) * nx
|
|
+ vec3(-0.2527824, -0.3160516, -0.396141) * nymnx
|
|
+ vec3(0.07136245, 0.1597891, 0.2905936) * nynz
|
|
+ vec3(-0.03104042) * (3.0 * nz2 - 1.0) // all three components identical
|
|
+ vec3(-0.1610019, -0.2036495, -0.246641) * (nz * nx)
|
|
+ vec3(0.04571093, 0.04812178, 0.04632638) * nxx_nyy;
|
|
}
|
|
|
|
vec2 prefilteredDFGKaris(float NoV, float roughness) {
|
|
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 expTerm = exp2(-9.28 * NoV);
|
|
float a004 = min(r.x * r.x, expTerm) * r.x + r.y;
|
|
return vec2(-1.04, 1.04) * a004 + r.zw;
|
|
}
|
|
|
|
vec3 decodeEnvironmentMap(vec4 c) {
|
|
return c.rgb; // assume linear
|
|
}
|
|
|
|
float getSquareFalloffAttenuation(float dist2, float invFalloff) {
|
|
float sf = max(1.0 - (dist2 * invFalloff) * (dist2 * invFalloff), 0.0);
|
|
return sf * sf;
|
|
}
|
|
|
|
vec3 fixCubemapLookup(vec3 v, float lod) {
|
|
vec3 a = abs(v);
|
|
float M = max(max(a.x, a.y), a.z);
|
|
float sc = 1.0 - exp2(lod) * (1.0/256.0);
|
|
if (a.x != M) v.x *= sc;
|
|
if (a.y != M) v.y *= sc;
|
|
if (a.z != M) v.z *= sc;
|
|
return v;
|
|
}
|
|
|
|
vec3 evaluateSpecularIBL(vec3 r, float roughness) {
|
|
float lod = 5.0 * roughness;
|
|
return decodeEnvironmentMap(textureLod(reflectionSampler, fixCubemapLookup(r, lod), lod)) * 1.8;
|
|
}
|
|
|
|
float computeSpecularao(float NoV, float ao, float roughness) {
|
|
float powe = exp2(-16.0 * roughness - 1.0);
|
|
return clamp(pow(NoV + ao, powe) - 1.0 + ao, 0.0, 1.0);
|
|
}
|
|
|
|
vec3 getSpecularDominantDirection(vec3 n, vec3 r, float roughness2) {
|
|
float s = 1.0 - roughness2;
|
|
return mix(n, r, s * (sqrt(s) + sqrt(roughness2)));
|
|
}
|
|
|
|
// ————————— Lighting functions —————————
|
|
|
|
vec3 indirectLight(in deferredMaterialData m) {
|
|
float rough2 = m.roughness * m.roughness;
|
|
float NoV = max(dot(m.normal, m.vertex), 0.0);
|
|
vec3 r = reflect(-m.vertex, m.normal);
|
|
r = getSpecularDominantDirection(m.normal, r, rough2);
|
|
|
|
vec3 diff = m.diffuse * irradianceSH(m.normal) * (1.0 - m.metallic) * m.ambientOcclusion;
|
|
vec3 spec = evaluateSpecularIBL(r, m.roughness)
|
|
* computeSpecularao(NoV, m.ambientOcclusion, m.roughness);
|
|
return diff + spec;
|
|
}
|
|
|
|
vec3 directLight(in deferredLightData light, in deferredMaterialData m) {
|
|
vec3 n = m.normal;
|
|
vec3 v = m.vertex;
|
|
|
|
vec3 L = normalize(-light.direction);
|
|
float att = 1.0;
|
|
if (light.lightType == 1) {
|
|
float Nl = max(dot(n, L), 0.0);
|
|
att = smoothstep(0.9999, 1.0, Nl);
|
|
}
|
|
|
|
float NoL = max(dot(n, L), 0.0), NoV = max(dot(n, v), 0.0);
|
|
vec3 diff = m.diffuse * NoL;
|
|
|
|
vec3 H = normalize(L + v);
|
|
float NoH = max(dot(n, H), 0.0), VoH = max(dot(v, H), 0.0);
|
|
|
|
#if ANISOTROPY == 1
|
|
vec3 t = normalize(m.tangent);
|
|
vec3 b = normalize(cross(t, n));
|
|
float ax = sqrt(m.roughness);
|
|
float ay = ax;
|
|
float D = D_GGX_Anisotropy(NoH, H, t, b, ax, ay);
|
|
#else
|
|
float D = D_GGX(NoH, m.roughness * m.roughness);
|
|
#endif
|
|
|
|
float V = V_SmithGGXCorrelated(NoV, NoL, m.roughness * m.roughness);
|
|
vec3 F = F_Schlick(VoH, m.specularReflectance, 1.0);
|
|
vec3 spec = (D * V) * F / max(4.0 * NoV * NoL, 1e-5);
|
|
|
|
if (m.clearcoat > 0.0) {
|
|
float Cr2 = m.clearcoatRoughness * m.clearcoatRoughness;
|
|
float Dc = D_GGX(NoH, Cr2);
|
|
float Vc = V_SmithGGXCorrelated(NoV, NoL, Cr2);
|
|
float Fc = F_Schlick_Scalar(VoH, 0.04, 1.0);
|
|
spec += m.clearcoat * (Dc * Vc * Fc / max(4.0 * NoV * NoL, 1e-5));
|
|
}
|
|
|
|
#if TRANSLUCENT_MATERIAL == 1
|
|
vec3 dL = normalize(L + m.translucencyDistortion * vec3(0.1));
|
|
float Nt = max(dot(n, dL), 0.0);
|
|
float trs = pow(Nt, m.translucencyPower) * m.translucencyScale;
|
|
trs = clamp(trs + m.translucencyAmbient, 0.0, 1.0);
|
|
diff += m.translucency * trs * light.color;
|
|
#endif
|
|
|
|
return att * light.color * (diff * (1.0 - m.metallic) + spec);
|
|
}
|
|
|
|
// ————————— Main shading entry —————————
|
|
|
|
vec4 physically_based_shading(deferredLightData light, deferredMaterialData m) {
|
|
m.diffuse = m.baseColor * (1.0 - m.metallic);
|
|
m.specularReflectance = mix(vec3(0.04), m.baseColor, m.metallic);
|
|
m.geometricRoughness = m.roughness * m.roughness;
|
|
m.vertex = normalize(cameraPosition - m.vertex);
|
|
|
|
vec3 color = indirectLight(m) + directLight(light, m);
|
|
return vec4(color, m.alpha);
|
|
}
|