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);
 		}