diff --git a/indra/newview/app_settings/shaders/class1/deferred/genbrdflutF.glsl b/indra/newview/app_settings/shaders/class1/deferred/genbrdflutF.glsl index df0d21b43231e597d32f5b713805457721456939..9f01c289f52b0d673e37be1f10b31e5bf4096ec1 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/genbrdflutF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/genbrdflutF.glsl @@ -81,31 +81,29 @@ vec2 hammersley2d(uint i, uint N) } // Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf -vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +vec3 importanceSample_GGX(vec2 Xi, float a2, vec3 normal) { // Maps a 2D point to a hemisphere with spread based on roughness - float alpha = roughness * roughness; - float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; - float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float phi = 2.0 * PI * Xi.x; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a2 - 1.0) * Xi.y)); float sinTheta = sqrt(1.0 - cosTheta * cosTheta); vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); // Tangent space vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); vec3 tangentX = normalize(cross(up, normal)); - vec3 tangentY = normalize(cross(normal, tangentX)); + vec3 tangentY = cross(normal, tangentX); // Convert to world Space return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); } -// Geometric Shadowing function -float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +// Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs" +float V_SmithGGXCorrelated(float NoV, float NoL, float a2) { - float k = (roughness * roughness) / 2.0; - float GL = dotNL / (dotNL * (1.0 - k) + k); - float GV = dotNV / (dotNV * (1.0 - k) + k); - return GL * GV; + float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2); + float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2); + return (2.0 * NoL) / (GGXV + GGXL); } vec2 BRDF(float NoV, float roughness) @@ -113,21 +111,21 @@ vec2 BRDF(float NoV, float roughness) // Normal always points along z-axis for the 2D lookup const vec3 N = vec3(0.0, 0.0, 1.0); vec3 V = vec3(sqrt(1.0 - NoV*NoV), 0.0, NoV); + float a2 = pow(roughness, 4.0); vec2 LUT = vec2(0.0); for(uint i = 0u; i < NUM_SAMPLES; i++) { vec2 Xi = hammersley2d(i, NUM_SAMPLES); - vec3 H = importanceSample_GGX(Xi, roughness, N); + vec3 H = importanceSample_GGX(Xi, a2, N); vec3 L = 2.0 * dot(V, H) * H - V; float dotNL = max(dot(N, L), 0.0); - float dotNV = max(dot(N, V), 0.0); float dotVH = max(dot(V, H), 0.0); float dotNH = max(dot(H, N), 0.0); if (dotNL > 0.0) { - float G = G_SchlicksmithGGX(dotNL, dotNV, roughness); - float G_Vis = (G * dotVH) / (dotNH * dotNV); + float G = V_SmithGGXCorrelated(NoV, dotNL, a2); + float G_Vis = G * dotVH / dotNH; float Fc = pow(1.0 - dotVH, 5.0); LUT += vec2(Fc * G_Vis, G_Vis); }