From 402ab8c8f657f050a2ea30ebe562008130cb9bcd Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 13 Sep 2022 15:25:15 -0500
Subject: [PATCH] SL-17701 WIP -- Cleanup/refactor PBR lighting implementation
 and get parity between deferred and alpha passes for sunlight and IBL.

---
 .../shaders/class1/deferred/alphaF.glsl       |  12 -
 .../shaders/class1/deferred/deferredUtil.glsl |  65 +-
 .../shaders/class1/deferred/materialF.glsl    |  29 -
 .../shaders/class1/deferred/pbralphaF.glsl    | 165 ++---
 .../shaders/class3/deferred/softenLightF.glsl | 637 +++---------------
 indra/newview/lldrawpoolalpha.cpp             |  10 +-
 indra/newview/llviewershadermgr.cpp           | 132 ++--
 indra/newview/llviewershadermgr.h             |   2 +-
 8 files changed, 268 insertions(+), 784 deletions(-)

diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index 02b2daf0ac5..fc1cee1f592 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -262,27 +262,15 @@ void main()
 
     vec3 sun_contrib = min(final_da, shadow) * sunlit;
 
-#if !defined(AMBIENT_KILL)
     color.rgb = amblit;
     color.rgb *= ambient;
-#endif // !defined(AMBIENT_KILL)
 
-vec3 post_ambient = color.rgb;
-
-#if !defined(SUNLIGHT_KILL)
     color.rgb += sun_contrib;
-#endif // !defined(SUNLIGHT_KILL)
-
-vec3 post_sunlight = color.rgb;
 
     color.rgb *= diffuse_srgb.rgb;
 
-vec3 post_diffuse = color.rgb;
-
     color.rgb = atmosFragLighting(color.rgb, additive, atten);
 
-vec3 post_atmo = color.rgb;
-
     vec4 light = vec4(0,0,0,0);
     
     color.rgb = scaleSoftClipFrag(color.rgb);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
index 449cbeaa28f..78f6a5b130a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
@@ -471,7 +471,7 @@ vec3 BRDFDiffuse(vec3 color)
 
 vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh )
 {
-    return (1.0 - specWeight * fresnelSchlick( reflect0, reflect90, vh)) * BRDFDiffuse(c_diff);
+    return (1.0 - fresnelSchlick( reflect0, reflect90, vh)) * BRDFDiffuse(c_diff);
 }
 
 vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRough, float specWeight, float vh, float nl, float nv, float nh )
@@ -479,5 +479,64 @@ vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRough, float spe
     vec3 fresnel    = fresnelSchlick( reflect0, reflect90, vh ); // Fresnel
     float vis       = V_GGX( nl, nv, alphaRough );               // Visibility
     float d         = D_GGX( nh, alphaRough );                   // Distribution
-    return specWeight * fresnel * vis * d;
-}
+    return fresnel * vis * d;
+}
+
+// set colorDiffuse and colorSpec to the results of GLTF PBR style IBL
+void pbrIbl(out vec3 colorDiffuse, // diffuse color output
+            out vec3 colorSpec, // specular color output,
+            vec3 radiance, // radiance map sample
+            vec3 irradiance, // irradiance map sample
+            float ao,       // ambient occlusion factor
+            float nv,       // normal dot view vector
+            float perceptualRough, // roughness factor
+            float gloss,        // 1.0 - roughness factor
+            vec3 reflect0,      // see also: initMaterial
+            vec3 c_diff)
+{
+    // Common to RadianceGGX and RadianceLambertian
+    vec2  brdfPoint  = clamp(vec2(nv, perceptualRough), vec2(0,0), vec2(1,1));
+    vec2  vScaleBias = getGGX( brdfPoint); // Environment BRDF: scale and bias applied to reflect0
+    vec3  fresnelR   = max(vec3(gloss), reflect0) - reflect0; // roughness dependent fresnel
+    vec3  kSpec      = reflect0 + fresnelR*pow(1.0 - nv, 5.0);
+
+    vec3 FssEssGGX = kSpec*vScaleBias.x + vScaleBias.y;
+    colorSpec = radiance * FssEssGGX;
+
+    // Reference: getIBLRadianceLambertian fs
+    vec3  FssEssLambert = kSpec * vScaleBias.x + vScaleBias.y; // NOTE: Very similar to FssEssRadiance but with extra specWeight term
+    float Ems           = 1.0 - (vScaleBias.x + vScaleBias.y);
+    vec3  avg           = (reflect0 + (1.0 - reflect0) / 21.0);
+    vec3  AvgEms        = avg * Ems;
+    vec3  FmsEms        = AvgEms * FssEssLambert / (1.0 - AvgEms);
+    vec3  kDiffuse      = c_diff * (1.0 - FssEssLambert + FmsEms);
+    colorDiffuse        = (FmsEms + kDiffuse) * irradiance;
+
+    colorDiffuse *= ao;
+    colorSpec    *= ao;
+}
+
+void pbrDirectionalLight(inout vec3 colorDiffuse,
+    inout vec3 colorSpec,
+    vec3 sunlit,
+    float scol,
+    vec3 reflect0,
+    vec3 reflect90,
+    vec3 c_diff,
+    float alphaRough,
+    float vh,
+    float nl,
+    float nv,
+    float nh)
+{
+    float scale = 16.0;
+    vec3 sunColor = sunlit * scale;
+
+    // scol = sun shadow
+    vec3 intensity  = sunColor * nl * scol;
+    vec3 sunDiffuse = intensity * BRDFLambertian (reflect0, reflect90, c_diff    , 1.0, vh);
+    vec3 sunSpec    = intensity * BRDFSpecularGGX(reflect0, reflect90, alphaRough, 1.0, vh, nl, nv, nh);
+
+    colorDiffuse += sunDiffuse;
+    colorSpec    += sunSpec;
+}
\ No newline at end of file
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index 6f087632a5d..e87d90aa9e8 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -345,35 +345,6 @@ void main()
 
     if (spec.a > 0.0)  // specular reflection
     {
-        /*  // Reverting this specular calculation to previous 'dumbshiny' version - DJH 6/17/2020
-            // Preserving the refactored version as a comment for potential reconsideration,
-            // overriding the general rule to avoid pollutiong the source with commented code.
-            //
-            //  If you're reading this in 2021+, feel free to obliterate.
-
-        vec3 npos = -normalize(pos.xyz);
-
-        //vec3 ref = dot(pos+lv, norm);
-        vec3 h = normalize(light_dir.xyz + npos);
-        float nh = dot(norm.xyz, h);
-        float nv = dot(norm.xyz, npos);
-        float vh = dot(npos, h);
-        float sa = nh;
-        float fres = pow(1 - dot(h, npos), 5)*0.4 + 0.5;
-
-        float gtdenom = 2 * nh;
-        float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
-
-        if (nh > 0.0)
-        {
-            float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt / (nh*da);
-            vec3 sp = sun_contrib*scol / 6.0f;
-            sp = clamp(sp, vec3(0), vec3(1));
-            bloom = dot(sp, sp) / 4.0;
-            color += sp * spec.rgb;
-        }
-        */
-
         float sa        = dot(refnormpersp, sun_dir.xyz);
         vec3  dumbshiny = sunlit * shadow * (texture2D(lightFunc, vec2(sa, spec.a)).r);
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl
index bde015d1096..c57ae3e51f2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl
@@ -25,24 +25,11 @@
 
 /*[EXTRA_CODE_HERE]*/
 
-#define PBR_USE_IBL             1
-#define PBR_USE_SUN             1
-#define PBR_USE_IRRADIANCE_HACK 1
-
 #define DIFFUSE_ALPHA_MODE_NONE     0
 #define DIFFUSE_ALPHA_MODE_BLEND    1
 #define DIFFUSE_ALPHA_MODE_MASK     2
 #define DIFFUSE_ALPHA_MODE_EMISSIVE 3
 
-#define DEBUG_PBR_LIGHT_TYPE 0 // Output Diffuse=0.75, Emissive=0, ORM=0,0,0
-
-#define DEBUG_BASIC         0
-#define DEBUG_VERTEX        0
-#define DEBUG_NORMAL_MAP    0 // Output packed normal map "as is" to diffuse
-#define DEBUG_NORMAL_OUT    0 // Output unpacked normal to diffuse
-#define DEBUG_ORM           0 // Output Occlusion Roughness Metal "as is" to diffuse
-#define DEBUG_POSITION      0
-
 uniform sampler2D diffuseMap;  //always in sRGB space
 uniform sampler2D bumpMap;
 uniform sampler2D emissiveMap;
@@ -56,8 +43,6 @@ uniform vec3 emissiveColor;
 uniform sampler2DRect lightMap;
 #endif
 
-uniform samplerCube environmentMap;
-uniform mat3        env_mat;
 uniform int sun_up_factor;
 uniform vec3 sun_dir;
 uniform vec3 moon_dir;
@@ -108,14 +93,15 @@ uniform vec3 light_direction[8]; // spot direction
 uniform vec4 light_attenuation[8]; // linear, quadratic, is omni, unused, See: LLPipeline::setupHWLights() and syncLightState()
 uniform vec3 light_diffuse[8];
 
-vec2 encode_normal(vec3 n);
 vec3 srgb_to_linear(vec3 c);
 vec3 linear_to_srgb(vec3 c);
 
 // These are in deferredUtil.glsl but we can't set: mFeatures.isDeferred to include it
 vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh );
-vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRoughness, float specWeight, float vh, float nl, float nv, float nh );
 void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao);
+vec3 atmosFragLighting(vec3 l, vec3 additive, vec3 atten);
+vec3 scaleSoftClipFrag(vec3 l);
+
 void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
 float calcLegacyDistanceAttenuation(float distance, float falloff);
 vec2 getGGX( vec2 brdfPoint );
@@ -125,7 +111,29 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
 void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv, 
         vec3 pos, vec3 norm, float glossiness, float envIntensity);
 
-vec3 hue_to_rgb(float hue);
+void pbrDirectionalLight(inout vec3 colorDiffuse,
+    inout vec3 colorSpec,
+    vec3 sunlit,
+    float scol,
+    vec3 reflect0,
+    vec3 reflect90,
+    vec3 c_diff,
+    float alphaRough,
+    float vh,
+    float nl,
+    float nv,
+    float nh);
+
+void pbrIbl(out vec3 colorDiffuse, // diffuse color output
+            out vec3 colorSpec, // specular color output,
+            vec3 radiance, // radiance map sample
+            vec3 irradiance, // irradiance map sample
+            float ao,       // ambient occlusion factor
+            float nv,
+            float perceptualRough, // roughness factor
+            float gloss,        // 1.0 - roughness factor
+            vec3 reflect0,
+            vec3 c_diff);
 
 // lp = light position
 // la = linear attenuation, light radius
@@ -192,21 +200,14 @@ void main()
     }
 #endif
 
-//    vec3 base = vertex_color.rgb * albedo.rgb * albedo.a;
-    vec3 base = vertex_color.rgb * albedo.rgb;
+    vec3 base = srgb_to_linear(vertex_color.rgb) * albedo.rgb;
 
-#ifdef HAS_NORMAL_MAP
     vec4 norm = texture2D(bumpMap, vary_texcoord1.xy);
     norm.xyz = normalize(norm.xyz * 2 - 1);
 
     vec3 tnorm = vec3(dot(norm.xyz,vary_mat0),
                       dot(norm.xyz,vary_mat1),
                       dot(norm.xyz,vary_mat2));
-#else
-    vec4 norm = vec4(0,0,0,1.0);
-//    vec3 tnorm = vary_normal;
-    vec3 tnorm = vec3(0,0,1);
-#endif
 
     tnorm = normalize(tnorm.xyz);
     norm.xyz = tnorm.xyz;
@@ -222,19 +223,13 @@ void main()
     //   occlusion 1.0
     //   roughness 0.0
     //   metal     0.0
-#ifdef HAS_SPECULAR_MAP
     vec3 packedORM = texture2D(specularMap, vary_texcoord2.xy).rgb;  // PBR linear packed Occlusion, Roughness, Metal. See: lldrawpoolapha.cpp
-#else
-    vec3 packedORM = vec3(1,0,0);
-#endif
 
     packedORM.g *= roughnessFactor;
     packedORM.b *= metallicFactor;
 
-    vec3 colorEmissive = emissiveColor;
-#ifdef HAS_EMISSIVE_MAP
-    colorEmissive *= texture2D(emissiveMap, vary_texcoord0.xy).rgb;
-#endif
+    vec3 colorEmissive = srgb_to_linear(emissiveColor);
+    colorEmissive *= srgb_to_linear(texture2D(emissiveMap, vary_texcoord0.xy).rgb);
 
     vec3 colorDiffuse     = vec3(0);
     vec3 colorSpec        = vec3(0);
@@ -246,9 +241,6 @@ void main()
 
     vec3  v               = -normalize(vary_position.xyz);
     vec3  n               = norm.xyz;
-    vec3  t               = vec3(1,0,0);
-    vec3  b               = normalize(cross(n,t));
-    vec3  reflectVN       = normalize(reflect(-v,n));
 
     vec3  h, l;
     float nh, nl, nv, vh, lightDist;
@@ -258,62 +250,27 @@ void main()
     float alphaRough, specWeight;
     initMaterial( base, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight );
 
-    // Common to RadianceGGX and RadianceLambertian
-    vec2  brdfPoint  = clamp(vec2(nv, perceptualRough), vec2(0,0), vec2(1,1));
-    vec2  vScaleBias = getGGX( brdfPoint); // Environment BRDF: scale and bias applied to reflect0
-    vec3  fresnelR   = max(vec3(1.0 - perceptualRough), reflect0) - reflect0; // roughness dependent fresnel
-    vec3  kSpec      = reflect0 + fresnelR*pow(1.0 - nv, 5.0);
-
-    vec3 legacyenv;
-
-    vec3  irradiance = vec3(0);
-    vec3  specLight  = vec3(0);
     float gloss      = 1.0 - perceptualRough;
-    sampleReflectionProbes(irradiance, specLight, legacyenv, pos.xyz, norm.xyz, gloss, 0.0);
-#if PBR_USE_IRRADIANCE_HACK
-        irradiance       = max(amblit,irradiance) * ambocc;
-#else
-irradiance = vec3(amblit);
-#endif
-
-    vec3 FssEssGGX   = kSpec*vScaleBias.x + vScaleBias.y;
-#if PBR_USE_IBL
-    colorSpec       += specWeight * specLight * FssEssGGX;
-#endif
-
-    vec3  FssEssLambert = specWeight * kSpec * vScaleBias.x + vScaleBias.y; // NOTE: Very similar to FssEssRadiance but with extra specWeight term
-    float Ems           = 1.0 - (vScaleBias.x + vScaleBias.y);
-    vec3  avg           = specWeight * (reflect0 + (1.0 - reflect0) / 21.0);
-    vec3  AvgEms        = avg * Ems;
-    vec3  FmsEms        = AvgEms * FssEssLambert / (1.0 - AvgEms);
-    vec3  kDiffuse      = c_diff * (1.0 - FssEssLambert + FmsEms);
-#if PBR_USE_IBL
-    colorDiffuse       += (FmsEms + kDiffuse) * irradiance;
-#endif
-
-    colorDiffuse *= ao;
-    colorSpec    *= ao;
+    vec3  irradiance = vec3(0);
+    vec3  radiance  = vec3(0);
+    vec3  legacyenv = vec3(0);
+    sampleReflectionProbes(irradiance, radiance, legacyenv, pos.xyz, norm.xyz, gloss, 0.0);
+    irradiance       = max(amblit,irradiance) * ambocc;
 
+    pbrIbl(colorDiffuse, colorSpec, radiance, irradiance, ao, nv, perceptualRough, gloss, reflect0, c_diff);
+    
     // Sun/Moon Lighting
     if (nl > 0.0 || nv > 0.0)
     {
-        float scale = 4.9;
-        vec3 sunColor = srgb_to_linear(sunlit * scale); // NOTE: Midday should have strong sunlight
-
-        // scol = sun shadow
-        vec3 intensity  = ambocc * sunColor * nl * scol;
-        vec3 sunDiffuse = intensity * BRDFLambertian (reflect0, reflect90, c_diff    , specWeight, vh);
-        vec3 sunSpec    = intensity * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh);
-#if PBR_USE_SUN
-             colorDiffuse += sunDiffuse;
-             colorSpec    += sunSpec;
-#endif
-        }
+        pbrDirectionalLight(colorDiffuse, colorSpec, srgb_to_linear(sunlit), scol, reflect0, reflect90, c_diff, alphaRough, vh, nl, nv, nh);
+    }
+
     vec3 col = colorDiffuse + colorEmissive + colorSpec;
+    
     vec3 light = vec3(0);
 
     // Punctual lights
-#define LIGHT_LOOP(i) light += srgb_to_linear(vec3(scol)) * calcPointLightOrSpotLight( reflect0, c_diff, srgb_to_linear(2.2*light_diffuse[i].rgb), albedo.rgb, pos.xyz, n, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w );
+#define LIGHT_LOOP(i) light += srgb_to_linear(vec3(scol)) * calcPointLightOrSpotLight( reflect0, c_diff, srgb_to_linear(2.2*light_diffuse[i].rgb), base.rgb, pos.xyz, n, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w );
 
     LIGHT_LOOP(1)
     LIGHT_LOOP(2)
@@ -323,42 +280,10 @@ irradiance = vec3(amblit);
     LIGHT_LOOP(6)
     LIGHT_LOOP(7)
 
-#if !defined(LOCAL_LIGHT_KILL)
-    col += light;
-#endif // !defined(LOCAL_LIGHT_KILL)
-
-#if DEBUG_PBR_LIGHT_TYPE
-    col.rgb  = vec3(0.75);
-    emissive = vec3(0);
-    spec.rgb = vec3(0);
-#endif
-#if DEBUG_BASIC
-    col.rgb = vec3( 1, 0, 1 );
-#endif
-#if DEBUG_VERTEX
-    col.rgb = vertex_color.rgb;
-#endif
-#if DEBUG_NORMAL_MAP
-    col.rgb = texture2D(bumpMap, vary_texcoord1.xy).rgb;
-#endif
-#if DEBUG_NORMAL_OUT
-    col.rgb = vary_normal;
-#endif
-#if DEBUG_ORM
-    col.rgb = linear_to_srgb(spec);
-#endif
-#if DEBUG_POSITION
-    col.rgb = vary_position.xyz;
-#endif
+    col.rgb = linear_to_srgb(col.rgb);
+    col *= atten.r;
+    col += 2.0*additive;
+    col  = scaleSoftClipFrag(col);
 
-//    col.rgb = linear_to_srgb(col.rgb);
-//    frag_color = vec4(albedo.rgb,albedo.a);
-//    frag_color = vec4(base.rgb,albedo.a);
-//    frag_color = vec4(irradiance,albedo.a);
-//    frag_color = vec4(colorDiffuse,albedo.a);
-//    frag_color = vec4(colorEmissive,albedo.a);
-//    frag_color = vec4(sun_dir,albedo.a);
-//    frag_color = vec4(sunlit,albedo.a);
-    col = linear_to_srgb(col.rgb);
     frag_color = vec4(col,albedo.a);
 }
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index d78c47a36a5..50aa93fea63 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -23,106 +23,6 @@
  * $/LicenseInfo$
  */
 
-#define PBR_USE_ATMOS              1
-#define PBR_USE_IBL                1
-#define PBR_USE_SUN                1
-
-#define PBR_USE_LINEAR_ALBEDO      1
-#define PBR_USE_DEFAULT_IRRADIANCE 0 // PBR: irradiance, skins/default/textures/default_irradiance.png
-#define PBR_USE_IRRADIANCE_HACK    1
-
-#define DEBUG_PBR_LIGHT_TYPE       0 // Output no global light to make it easier to see pointLight and spotLight
-#define DEBUG_PBR_PACK_ORM0        0 // Rough=0, Metal=0
-#define DEBUG_PBR_PACK_ORM1        0 // Rough=1, Metal=1
-#define DEBUG_PBR_TANGENT1         1 // Tangent = 1,0,0
-#define DEBUG_PBR_VERT2CAM1        0 // vertex2camera = 0,0,1
-#define DEBUG_PBR_SPECLIGHT051     0 // Force specLigh to be 0,0.5,1
-
-// Pass input through "as is"
-#define DEBUG_PBR_DIFFUSE_MAP      0 // Output: use diffuse in G-Buffer
-#define DEBUG_PBR_EMISSIVE         0 // Output: Emissive
-#define DEBUG_PBR_METAL            0 // Output: grayscale Metal map
-#define DEBUG_PBR_NORMAL_MAP       0 // Output: Normal -- also need to set DEBUG_NORMAL_MAP in pbropaqueF
-#define DEBUG_PBR_OCCLUSION        0 // Output: grayscale Occlusion map
-#define DEBUG_PBR_ORM              0 // Output: Packed Occlusion Roughness Metal
-#define DEBUG_PBR_ROUGH_PERCEPTUAL 0 // Output: grayscale Perceptual Roughness map
-#define DEBUG_PBR_ROUGH_ALPHA      0 // Output: grayscale Alpha Roughness
-
-#define DEBUG_PBR_TANGENT          0 // Output: Tangent
-#define DEBUG_PBR_BITANGENT        0 // Output: Bitangent
-#define DEBUG_PBR_DOT_BV           0 // Output: graysacle dot(Bitangent,Vertex2Camera)
-#define DEBUG_PBR_DOT_TV           0 // Output: grayscale dot(Tangent  ,Vertex2Camera)
-
-// IBL Spec
-#define DEBUG_PBR_NORMAL           0 // Output: passed in normal
-#define DEBUG_PBR_V2C_RAW          0 // Output: vertex2camera
-#define DEBUG_PBR_DOT_NV           0 // Output: grayscale dot(Normal   ,Vertex2Camera)
-#define DEBUG_PBR_BRDF_UV          0 // Output: red green BRDF UV         (GGX input)
-#define DEBUG_PBR_BRDF_SCALE_BIAS  0 // Output: red green BRDF Scale Bias (GGX output)
-#define DEBUG_PBR_BRDF_SCALE_ONLY  0 // Output: grayscale BRDF Scale
-#define DEBUG_PBR_BRDF_BIAS_ONLY   0 // Output: grayscale BRDER Bias
-#define DEBUG_PBR_FRESNEL          0 // Output: roughness dependent fresnel
-#define DEBUG_PBR_KSPEC            0 // Output: K spec
-#define DEBUG_PBR_REFLECTION_DIR   0 // Output: reflection dir
-#define DEBUG_PBR_SPEC_IBL         0 // Output: IBL specularity
-#define DEBUG_PBR_SPEC_LEGACY      0 // Output: legacyenv
-#define DEBUG_PBR_SPEC_REFLECTION  0 // Output: environment reflection
-#define DEBUG_PBR_FSS_ESS_GGX      0 // Output: FssEssGGX
-#define DEBUG_PBR_SPEC             0 // Output: Final spec
-
-// IBL Diffuse
-#define DEBUG_PBR_DIFFUSE_C        0 // Output: diffuse non metal mix
-#define DEBUG_PBR_IRRADIANCE_RAW   0 // Output: Diffuse Irradiance pre-mix
-#define DEBUG_PBR_IRRADIANCE       0 // Output: Diffuse Irradiance, NOTE: SSAO is factored in
-#define DEBUG_PBR_FSS_ESS_LAMBERT  0 // Output: FssEssLambert
-#define DEBUG_PBR_EMS              0 // Output: Ems = (1 - BRDF Scale + BRDF Bias)
-#define DEBUG_PBR_EMS_AVG          0 // Output: Avg Ems
-#define DEBUG_PBR_AVG              0 // Output: Avg
-#define DEBUG_PBR_FMS_EMS          0 // Output: FmsEms
-#define DEBUG_PBR_DIFFUSE_K        0 // Output: diffuse FssEssLambert + FmsEms
-#define DEBUG_PBR_DIFFUSE_PRE_AO   0 // Output: diffuse pre AO
-#define DEBUG_PBR_DIFFUSE          0 // Output: diffuse post AO
-
-// Atmospheric Lighting
-#define DEBUG_PBR_AMBENV           0 // Output: ambient environment
-#define DEBUG_PBR_AMBOCC           0 // Output: ambient occlusion
-#define DEBUG_PBR_DA_RAW           0 // Output: da pre pow()
-#define DEBUG_PBR_DA_POW           0 // Output: da post pow()
-#define DEBUG_PBR_SUN_LIT          0 // Ouput: sunlit
-#define DEBUG_PBR_SUN_CONTRIB      0 // Output: sun_contrib
-#define DEBUG_PBR_SKY_ADDITIVE     0 // Output: additive
-#define DEBUG_PBR_SKY_ATTEN        0 // Output: greyscale atten.r
-
-// Sun
-#define DEBUG_PBR_SUN_FULL_BRIGHT  0 // Sunlit color = <1,1,1>
-#define DEBUG_PBR_SUN_OUT_DIFFUSE  0 // Final sun diffuse : intensity * nl * diffuse
-#define DEBUG_PBR_SUN_OUT_SPECULAR 0 // Final sun specular: intensity * nl * specular
-#define DEBUG_PBR_SUN_LAMBERT      0 // BRDF Diffuse: Lambertian Diffuse color
-#define DEBUG_PBR_SUN_LAMBERT_NL   0 // BRDF Diffuse: nl * Lambertian Diffuse color
-#define DEBUG_PBR_SUN_H            0 // Half Vector
-#define DEBUG_PBR_SUN_L            0 // Light Vector
-#define DEBUG_PBR_SUN_V            0 // Surface to Light Vector
-#define DEBUG_PBR_SUN_NH           0 // dot(n,h)
-#define DEBUG_PBR_SUN_NL           0 // dot(n,l)
-#define DEBUG_PBR_SUN_NV           0 // dot(n,v)
-#define DEBUG_PBR_SUN_VH           0 // dot(v,h)
-#define DEBUG_PBR_SUN_REFLECT0     0 // reflect0 only
-#define DEBUG_PBR_SUN_SPEC_FRESNEL 0 // Fresnel
-#define DEBUG_PBR_SUN_SPEC_D       0 // D(h)
-#define DEBUG_PBR_SUN_SPEC_V       0 // V(l,v,h)
-#define DEBUG_PBR_SUN_SPEC_DF      0 // D() * F()
-#define DEBUG_PBR_SUN_SPEC_DV      0 // D() * V()
-#define DEBUG_PBR_SUN_SPEC_FV      0 // F() * V()
-#define DEBUG_PBR_SUN_SPEC_DFV     0 // D() * F() * V()
-#define DEBUG_PBR_SUN_SPEC_NL_DFV  0 // nl * D() * F() * V()
-#define DEBUG_PBR_SUN_FINAL        0 // LAMBERT_NL + BRDF()
-
-#define DEBUG_PBR_IOR              0 // Output: grayscale IOR
-#define DEBUG_PBR_REFLECT0_BASE    0 // Output: black reflect0 default from ior
-#define DEBUG_PBR_REFLECT0_MIX     0 // Output: diffuse reflect0 calculated from ior
-#define DEBUG_PBR_REFLECTANCE      0 // Output: diffuse reflectance -- NOT USED
-#define DEBUG_PBR_SPEC_WEIGHT      0 // Output: specWeight
-#define DEBUG_PBR_V2C_REMAP        0 // Output: vertex2camera (remap [-1,1] -> [0,1])
 #extension GL_ARB_texture_rectangle : enable
 #extension GL_ARB_shader_texture_lod : enable
 
@@ -169,16 +69,7 @@ uniform vec2 screen_res;
 vec3 getNorm(vec2 pos_screen);
 vec4 getPositionWithDepth(vec2 pos_screen, float depth);
 
-vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh );
-vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRoughness, float specWeight, float vh, float nl, float nv, float nh );
 void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao);
-float calcF0(float ior);
-void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
-
-float getAmbientClamp();
-vec2 getGGX( vec2 brdfPoint );
-void initMaterial( vec3 diffuse, vec3 packedORM,
-        out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight );
 vec3  atmosFragLighting(vec3 l, vec3 additive, vec3 atten);
 vec3  scaleSoftClipFrag(vec3 l);
 vec3  fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten);
@@ -193,18 +84,39 @@ void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3
 vec3 linear_to_srgb(vec3 c);
 vec3 srgb_to_linear(vec3 c);
 
-// Debug Utils
-vec3 BRDFDiffuse(vec3 color);
-vec3 colorize_dot(float x);
-vec3 fresnelSchlick( vec3 reflect0, vec3 reflect90, float vh);
-float D_GGX( float nh, float alphaRough );
-float V_GGX( float nl, float nv, float alphaRough );
-
 #ifdef WATER_FOG
 vec4 applyWaterFogView(vec3 pos, vec4 color);
 #endif
 
-uniform vec3 view_dir; // PBR
+// PBR interface
+void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
+void initMaterial( vec3 diffuse, vec3 packedORM,
+        out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight );
+// perform PBR image based lighting according to GLTF spec
+// all parameters are in linear space
+void pbrIbl(out vec3 colorDiffuse, // diffuse color output
+            out vec3 colorSpec, // specular color output,
+            vec3 radiance, // radiance map sample
+            vec3 irradiance, // irradiance map sample
+            float ao,       // ambient occlusion factor
+            float nv,
+            float perceptualRough, // roughness factor
+            float gloss,        // 1.0 - roughness factor
+            vec3 reflect0,
+            vec3 c_diff);
+
+void pbrDirectionalLight(inout vec3 colorDiffuse,
+    inout vec3 colorSpec,
+    vec3 sunlit,
+    float scol,
+    vec3 reflect0,
+    vec3 reflect90,
+    vec3 c_diff,
+    float alphaRough,
+    float vh,
+    float nl,
+    float nv,
+    float nh);
 
 void main()
 {
@@ -241,8 +153,6 @@ void main()
 
     calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, true);
 
-    //vec3 amb_vec = env_mat * norm.xyz;
-
     vec3 ambenv;
     vec3 glossenv;
     vec3 legacyenv;
@@ -262,480 +172,111 @@ void main()
         vec3 colorDiffuse      = vec3(0);
         vec3 colorEmissive     = spec.rgb; // PBR sRGB Emissive.  See: pbropaqueF.glsl
         vec3 colorSpec         = vec3(0);
-//      vec3 colorClearCoat    = vec3(0);
-//      vec3 colorSheen        = vec3(0);
-//      vec3 colorTransmission = vec3(0);
 
         vec3 packedORM        = texture2DRect(emissiveRect, tc).rgb; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl
-#if DEBUG_PBR_PACK_ORM0
-             packedORM        = vec3(0,0,0);
-#endif
-#if DEBUG_PBR_PACK_ORM1
-             packedORM        = vec3(1,1,1);
-#endif
         float IOR             = 1.5;         // default Index Of Refraction 1.5 (dielectrics)
-#if DEBUG_PBR_REFLECT0_BASE
-        vec3  debug_reflect0  = vec3(calcF0(IOR));
-#endif
         float ao         = packedORM.r;
         float metal      = packedORM.b;
         vec3  v          = -normalize(pos.xyz);
-#if DEBUG_PBR_VERT2CAM1
-              v = vec3(0,0,1);
-#endif
         vec3  n          = norm.xyz;
-//      vec3  t          = texture2DRect(tangentMap, tc).rgb;
-#if DEBUG_PBR_TANGENT1
-        vec3  t          = vec3(1,0,0);
-#endif
-        vec3  b          = cross( n,t);
-        vec3  reflectVN  = normalize(reflect(-v,n));
 
         vec3  h, l;
         float nh, nl, nv, vh, lightDist;
         calcHalfVectors(light_dir, n, v, h, l, nh, nl, nv, vh, lightDist);
 
-        float tv = clamp(dot(t,v),0,1);
-        float bv = clamp(dot(b,v),0,1);
-
-        // Reference: getMetallicRoughnessInfo
-#if PBR_USE_LINEAR_ALBEDO
-        vec3  base            = diffuse.rgb;
-#else
-        vec3  base            = linear_to_srgb(diffuse.rgb);
-#endif
         float perceptualRough = packedORM.g;  // NOTE: do NOT clamp here to be consistent with Blender, Blender is wrong and Substance is right
+        
         vec3 c_diff, reflect0, reflect90;
         float alphaRough, specWeight;
-        initMaterial( base, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight );
-#if DEBUG_PBR_REFLECTANCE
-        float reflectance     = max( max( reflect0.r, reflect0.g ), reflect0.b );
-#endif
-
-        // Common to RadianceGGX and RadianceLambertian
-        vec2  brdfPoint  = clamp(vec2(nv, perceptualRough), vec2(0,0), vec2(1,1));
-        vec2  vScaleBias = getGGX( brdfPoint); // Environment BRDF: scale and bias applied to reflect0
-        vec3  fresnelR   = max(vec3(1.0 - perceptualRough), reflect0) - reflect0; // roughness dependent fresnel
-        vec3  kSpec      = reflect0 + fresnelR*pow(1.0 - nv, 5.0);
+        initMaterial( diffuse.rgb, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight );
 
-        // Reference: getIBLRadianceGGX
-        // https://forum.substance3d.com/index.php?topic=3243.0
-        // Glossiness
-        // This map is the inverse of the roughness map.
-        vec3  irradiance = vec3(0);
-        vec3  specLight  = vec3(0);
         float gloss      = 1.0 - perceptualRough;
-        sampleReflectionProbes(irradiance, specLight, legacyenv, pos.xyz, norm.xyz, gloss, 0.0);
-#if DEBUG_PBR_IRRADIANCE_RAW
-        vec3 debug_irradiance = irradiance;
-#endif
-
-#if PBR_USE_DEFAULT_IRRADIANCE
-        vec2 iruv  = vec2(0.5f + 0.5f * atan(reflectVN.z, reflectVN.x) / M_PI, 1.f - acos(reflectVN.y) / M_PI);
-        irradiance = texture2D(altDiffuseMap, iruv).rgb * ambocc;
-#endif
-#if PBR_USE_IRRADIANCE_HACK
+        vec3  irradiance = vec3(0);
+        vec3  radiance  = vec3(0);
+        sampleReflectionProbes(irradiance, radiance, legacyenv, pos.xyz, norm.xyz, gloss, 0.0);
         irradiance       = max(amblit,irradiance) * ambocc;
-#endif
-#if DEBUG_PBR_SPECLIGHT051
-        specLight        = vec3(0,0.5,1.0);
-        irradiance       = specLight;
-#endif
-        vec3 FssEssGGX = kSpec*vScaleBias.x + vScaleBias.y;
-#if DEBUG_PBR_SPEC_IBL
-        vec3 debug_color_spec = specWeight * specLight * FssEssGGX;
-#endif
-#if PBR_USE_IBL
-        colorSpec += specWeight * specLight * FssEssGGX;
-#endif
-
-        // Reference: getIBLRadianceLambertian
-        vec3  FssEssLambert = specWeight * kSpec * vScaleBias.x + vScaleBias.y; // NOTE: Very similar to FssEssRadiance but with extra specWeight term
-        float Ems           = 1.0 - (vScaleBias.x + vScaleBias.y);
-        vec3  avg           = specWeight * (reflect0 + (1.0 - reflect0) / 21.0);
-        vec3  AvgEms        = avg * Ems;
-        vec3  FmsEms        = AvgEms * FssEssLambert / (1.0 - AvgEms);
-        vec3  kDiffuse      = c_diff * (1.0 - FssEssLambert + FmsEms);
-#if PBR_USE_IBL
-        colorDiffuse       += (FmsEms + kDiffuse) * irradiance;
-#endif
-    #if DEBUG_PBR_DIFFUSE_PRE_AO
-        vec3 debug_diffuse  = colorDiffuse;
-    #endif
-
-        colorDiffuse *= ao; // Occlusion -- NOTE: pbropaque will need occlusion_strength pre-multiplied into spec.r
-        colorSpec    *= ao;
 
-        // Add in sun/moon reflection
+        pbrIbl(colorDiffuse, colorSpec, radiance, irradiance, ao, nv, perceptualRough, gloss, reflect0, c_diff);
+        
+        // Add in sun/moon punctual light
         if (nl > 0.0 || nv > 0.0)
         {
-            float scale = 4.9;
-            vec3 sunColor = srgb_to_linear(sunlit * scale); // NOTE: Midday should have strong sunlight
-#if DEBUG_PBR_SUN_FULL_BRIGHT
-            sunColor = vec3(1);
-#endif
-            // scol = sun shadow
-            vec3 intensity  = ambocc * sunColor * nl * scol;
-#if PBR_USE_LINEAR_ALBEDO
-            vec3 sunDiffuse = intensity * BRDFLambertian (reflect0, reflect90, c_diff    , specWeight, vh);
-            vec3 sunSpec    = intensity * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh);
-#else
-            vec3 sunDiffuse = base * intensity * BRDFLambertian (reflect0, reflect90, c_diff    , specWeight, vh);
-            vec3 sunSpec    =        intensity * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh);
-#endif
-            // Disabling PBR bloom due to two reasons:
-            //   1. The glTF 2.0 Specification does not specify bloom,
-            //   2. As the camera moves there are lots of bloom shimmering.
-            //bloom = dot(sunSpec, sunSpec) / (scale * scale * scale);
-
-    #if DEBUG_PBR_SUN_SPEC_FRESNEL
-            colorDiffuse = vec3(0);
-            colorSpec = fresnelSchlick( reflect0, reflect90, vh );
-            bloom = 0;
-    #endif
-    #if DEBUG_PBR_SUN_SPEC_D
-            colorDiffuse = vec3(0);
-            colorSpec = vec3(D_GGX( nh, alphaRough ));
-            bloom = 0;
-    #endif
-    #if DEBUG_PBR_SUN_SPEC_V
-            colorDiffuse = vec3(0);
-            colorSpec = vec3(V_GGX( nl, nv, alphaRough ));
-            bloom = 0;
-    #endif
-    #if DEBUG_PBR_SUN_SPEC_DF
-            colorDiffuse = vec3(0);
-            colorSpec  = fresnelSchlick( reflect0, reflect90, vh );
-            colorSpec *= D_GGX( nh, alphaRough );
-            bloom = 0;
-    #endif
-    #if DEBUG_PBR_SUN_SPEC_DV
-            colorDiffuse = vec3(0);
-            colorSpec  = vec3(D_GGX( nh, alphaRough ));
-            colorSpec *= vec3(V_GGX( nl, nv, alphaRough ));
-            bloom = 0;
-    #endif
-    #if DEBUG_PBR_SUN_SPEC_FV
-            colorDiffuse = vec3(0);
-            colorSpec  = fresnelSchlick( reflect0, reflect90, vh );
-            colorSpec *= V_GGX( nl, nv, alphaRough );
-            bloom = 0;
-    #endif
-    #if DEBUG_PBR_SUN_SPEC_DFV
-            colorDiffuse = vec3(0);
-            colorSpec  = fresnelSchlick( reflect0, reflect90, vh );
-            colorSpec *= D_GGX( nh, alphaRough );
-            colorSpec *= V_GGX( nl, nv, alphaRough );
-            bloom = 0;
-    #endif
-    #if DEBUG_PBR_SUN_SPEC_NL_DFV
-            colorDiffuse = vec3(0);
-            colorSpec  = nl * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh);
-    #endif
-    #if DEBUG_PBR_SUN_FINAL
-            colorDiffuse = nl * BRDFLambertian (reflect0, reflect90, c_diff    , specWeight, vh);
-            colorSpec    = nl * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh);
-    #endif
-
-    #if DEBUG_PBR_SUN_OUT_DIFFUSE
-            colorDiffuse = linear_to_srgb(sunDiffuse);
-            colorSpec = vec3(0);
-            bloom = 0.0;
-    #endif
-    #if DEBUG_PBR_SUN_OUT_SPECULAR
-            colorDiffuse = linear_to_srgb(sunSpec);
-            colorSpec = vec3(0);
-    #endif
-    #if DEBUG_PBR_SUN_REFLECT0
-            colorDiffuse = reflect0;
-            colorSpec = vec3(0);
-    #endif
-
-#if PBR_USE_SUN
-             colorDiffuse += sunDiffuse;
-             colorSpec    += sunSpec;
-#endif
+            pbrDirectionalLight(colorDiffuse, colorSpec, srgb_to_linear(sunlit), scol, reflect0, reflect90, c_diff, alphaRough, vh, nl, nv, nh);
         }
 
-#if DEBUG_PBR_SUN_LAMBERT
-        colorDiffuse = BRDFLambertian (reflect0, reflect90, c_diff    , specWeight, vh);
-        colorSpec    = vec3(0);
-        bloom        = 0;
-#endif
-#if DEBUG_PBR_SUN_LAMBERT_NL
-        colorDiffuse = nl * BRDFLambertian (reflect0, reflect90, c_diff    , specWeight, vh);
-        colorSpec    = vec3(0);
-        bloom        = 0;
-#endif
-
-    #if DEBUG_PBR_SUN_H
-        colorDiffuse = h*0.5 + 0.5; colorSpec = vec3(0);
-    #endif
-    #if DEBUG_PBR_SUN_L
-        colorDiffuse = l*0.5 + 0.5; colorSpec = vec3(0);
-    #endif
-    #if DEBUG_PBR_SUN_V
-        colorDiffuse = v*0.5 + 0.5; colorSpec = vec3(0);
-    #endif
-    #if DEBUG_PBR_SUN_NH
-        colorDiffuse = colorize_dot(nh); colorSpec = vec3(0);
-    #endif
-    #if DEBUG_PBR_SUN_NL
-        colorDiffuse = colorize_dot(nl); colorSpec = vec3(0);
-    #endif
-    #if DEBUG_PBR_SUN_NV
-        colorDiffuse = colorize_dot(nv); colorSpec = vec3(0);
-    #endif
-    #if DEBUG_PBR_SUN_VH
-        colorDiffuse = colorize_dot(vh); colorSpec = vec3(0);
-    #endif
-
         color.rgb = colorDiffuse + colorEmissive + colorSpec;
 
-#if PBR_USE_ATMOS
         color  = linear_to_srgb(color);
         color *= atten.r;
         color += 2.0*additive;
         color  = scaleSoftClipFrag(color);
         color  = srgb_to_linear(color);
-#endif // PBR_USE_ATMOS
-
-    #if DEBUG_PBR_DIFFUSE
-        color.rgb = colorDiffuse;
-    #endif
-    #if DEBUG_PBR_EMISSIVE
-        color.rgb = colorEmissive;
-    #endif
-    #if DEBUG_PBR_METAL
-        color.rgb = vec3(metal);
-    #endif
-    #if DEBUG_PBR_NORMAL_MAP
-        color.rgb = diffuse.rgb;
-    #endif
-    #if DEBUG_PBR_OCCLUSION
-        color.rgb = vec3(ao);
-    #endif
-    #if DEBUG_PBR_ORM
-        color.rgb = packedORM;
-    #endif
-    #if DEBUG_PBR_ROUGH_PERCEPTUAL
-        color.rgb = vec3(perceptualRough);
-    #endif
-    #if DEBUG_PBR_ROUGH_ALPHA
-        color.rgb = vec3(alphaRough);
-    #endif
 
-    #if DEBUG_PBR_NORMAL
-        color.rgb = norm.xyz*0.5 + vec3(0.5);
-        color.rgb = srgb_to_linear(color.rgb);
-    #endif
-    #if DEBUG_PBR_TANGENT
-        color.rgb = t;
-    #endif
-    #if DEBUG_PBR_BITANGENT
-        color.rgb = b;
-    #endif
-    #if DEBUG_PBR_DOT_NV
-        color.rgb = vec3(nv);
-    #endif
-    #if DEBUG_PBR_DOT_TV
-        color.rgb = vec3(tv);
-    #endif
-    #if DEBUG_PBR_DOT_BV
-        color.rgb = vec3(bv);
-    #endif
-
-    #if DEBUG_PBR_AVG
-        color.rgb = avg;
-    #endif
-    #if DEBUG_PBR_BRDF_UV
-        color.rgb = vec3(brdfPoint,0.0);
-        color.rgb = linear_to_srgb(color.rgb);
-    #endif
-    #if DEBUG_PBR_BRDF_SCALE_BIAS
-        color.rgb = vec3(vScaleBias,0.0);
-    #endif
-    #if DEBUG_PBR_DIFFUSE_C
-        color.rgb = c_diff;
-    #endif
-    #if DEBUG_PBR_BRDF_SCALE_ONLY
-        color.rgb = vec3(vScaleBias.x);
-    #endif
-    #if DEBUG_PBR_BRDF_BIAS_ONLY
-        color.rgb = vec3(vScaleBias.y);
-    #endif
-    #if DEBUG_PBR_DIFFUSE_K
-        color.rgb = kDiffuse;
-    #endif
-    #if DEBUG_PBR_DIFFUSE_MAP
-        color.rgb = diffuse.rgb;
-    #endif
-    #if DEBUG_PBR_DIFFUSE_PRE_AO
-        color.rgb = debug_diffuse;
-    #endif
-    #if DEBUG_PBR_EMS
-        color.rgb = vec3(Ems);
-    #endif
-    #if DEBUG_PBR_EMS_AVG
-        color.rgb = AvgEms;
-    #endif
-    #if DEBUG_PBR_FMS_EMS
-        color.rgb = FmsEms;
-    #endif
-    #if DEBUG_PBR_FSS_ESS_GGX
-        color.rgb = FssEssGGX; // spec
-    #endif
-    #if DEBUG_PBR_FSS_ESS_LAMBERT
-        color.rgb = FssEssLambert; // diffuse
-    #endif
-    #if DEBUG_PBR_FRESNEL
-        color.rgb = fresnelR;
-    #endif
-    #if DEBUG_PBR_IOR
-        color.rgb = vec3(IOR);
-    #endif
-    #if DEBUG_PBR_IRRADIANCE_RAW
-        color.rgb = debug_irradiance;
-        bloom = 0;
-    #endif
-    #if DEBUG_PBR_IRRADIANCE
-        color.rgb = irradiance;
-        bloom = 0;
-    #endif
-    #if DEBUG_PBR_KSPEC
-        color.rgb = kSpec;
-    #endif
-    #if DEBUG_PBR_REFLECT0_BASE
-        color.rgb = vec3(debug_reflect0);
-    #endif
-    #if DEBUG_PBR_REFLECT0_MIX
-        color.rgb = vec3(reflect0);
-    #endif
-    #if DEBUG_PBR_REFLECTANCE
-        color.rgb = vec3(reflectance);
-    #endif
-    #if DEBUG_PBR_REFLECTION_DIR
-        color.rgb = reflect(-v, n);  // NOTE: equivalent to normalize(reflect(pos.xyz, norm.xyz));
-    #endif
-    #if DEBUG_PBR_SPEC
-        color.rgb = colorSpec;
-    #endif
-    #if DEBUG_PBR_SPEC_REFLECTION
-        color.rgb = specLight;
-    #endif
-    #if DEBUG_PBR_SPEC_WEIGHT
-        color.rgb = vec3(specWeight);
-    #endif
-    #if DEBUG_PBR_V2C_RAW
-        color.rgb = v;
-    #endif
-    #if DEBUG_PBR_V2C_REMAP
-        color.rgb = v*0.5 + vec3(0.5);
-    #endif
-
-    #if DEBUG_PBR_DA_RAW
-        color.rgb = vec3(debug_da);
-    #endif
-    #if DEBUG_PBR_DA_POW
-        color.rgb = vec3(da);
-    #endif
-    #if DEBUG_PBR_SKY_ADDITIVE
-        color.rgb = additive;
-    #endif
-    #if DEBUG_PBR_SKY_ATTEN
-      color.rgb = vec3(atten.r);
-    #endif
-    #if DEBUG_PBR_SUN_LIT
-        color.rgb = sunlit;
-    #endif
-    #if DEBUG_PBR_SUN_CONTRIB
-        color.rgb = sun_contrib;
-    #endif
-    #if DEBUG_PBR_LIGHT_TYPE
-        color.rgb = vec3(0);
-    #endif
-
-        frag_color.rgb = color.rgb; // PBR is done in linear
+        frag_color.rgb = color.rgb; //output linear since local lights will be added to this shader's results
     }
-else
-{
-    float da          = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0);
-#if DEBUG_PBR_DA_RAW
-    float debug_da    = da;
-#endif
-    da                = pow(da, light_gamma);
+    else
+    {
+        float da          = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0);
+        da                = pow(da, light_gamma);
 
-    diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14035
+        diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14035
 
-    sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
-    ambenv.rgb = linear_to_srgb(ambenv.rgb); 
-    glossenv.rgb = linear_to_srgb(glossenv.rgb);
-    legacyenv.rgb = linear_to_srgb(legacyenv.rgb);
+        sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
+        ambenv.rgb = linear_to_srgb(ambenv.rgb); 
+        glossenv.rgb = linear_to_srgb(glossenv.rgb);
+        legacyenv.rgb = linear_to_srgb(legacyenv.rgb);
 
-    amblit = max(ambenv, amblit);
-    color.rgb = amblit*ambocc;
+        amblit = max(ambenv, amblit);
+        color.rgb = amblit*ambocc;
 
-    //float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
-    //ambient *= 0.5;
-    //ambient *= ambient;
-    //ambient = (1.0 - ambient);
-    //color.rgb *= ambient;
+        vec3 sun_contrib = min(da, scol) * sunlit;
+        color.rgb += sun_contrib;
+        color.rgb = min(color.rgb, vec3(1,1,1));
+        color.rgb *= diffuse.rgb;
 
-    vec3 sun_contrib = min(da, scol) * sunlit;
-    color.rgb += sun_contrib;
-    color.rgb = min(color.rgb, vec3(1,1,1));
-    color.rgb *= diffuse.rgb;
+        vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
 
-    vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
+        if (spec.a > 0.0)  // specular reflection
+        {
+            float sa        = dot(normalize(refnormpersp), light_dir.xyz);
+            vec3  dumbshiny = sunlit * scol * (texture2D(lightFunc, vec2(sa, spec.a)).r);
 
-    if (spec.a > 0.0)  // specular reflection
-    {
-        float sa        = dot(normalize(refnormpersp), light_dir.xyz);
-        vec3  dumbshiny = sunlit * scol * (texture2D(lightFunc, vec2(sa, spec.a)).r);
+            // add the two types of shiny together
+            vec3 spec_contrib = dumbshiny * spec.rgb;
+            bloom             = dot(spec_contrib, spec_contrib) / 6;
+            color.rgb += spec_contrib;
 
-        // add the two types of shiny together
-        vec3 spec_contrib = dumbshiny * spec.rgb;
-        bloom             = dot(spec_contrib, spec_contrib) / 6;
-        color.rgb += spec_contrib;
+            // add reflection map - EXPERIMENTAL WORK IN PROGRESS
+            applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
+        }
 
-        // add reflection map - EXPERIMENTAL WORK IN PROGRESS
-        applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
-    }
+        color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a);
 
-    color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a);
+        if (envIntensity > 0.0)
+        {  // add environmentmap
+            //fudge darker
+            legacyenv *= 0.5*diffuse.a+0.5;
+            applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity);
+        }
 
-    if (envIntensity > 0.0)
-    {  // add environmentmap
-        //fudge darker
-        legacyenv *= 0.5*diffuse.a+0.5;
-        applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity);
-    }
+        if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS))
+        {
+            color = mix(atmosFragLighting(color, additive, atten), fullbrightAtmosTransportFrag(color, additive, atten), diffuse.a);
+            color = mix(scaleSoftClipFrag(color), fullbrightScaleSoftClip(color), diffuse.a);
+        }
 
-    if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS))
-    {
-        color = mix(atmosFragLighting(color, additive, atten), fullbrightAtmosTransportFrag(color, additive, atten), diffuse.a);
-        color = mix(scaleSoftClipFrag(color), fullbrightScaleSoftClip(color), diffuse.a);
+    #ifdef WATER_FOG
+        vec4 fogged = applyWaterFogView(pos.xyz, vec4(color, bloom));
+        color       = fogged.rgb;
+        bloom       = fogged.a;
+    #endif
+
+        // convert to linear as fullscreen lights need to sum in linear colorspace
+        // and will be gamma (re)corrected downstream...
+        //color = ambenv;
+        //color.b = diffuse.a;
+        frag_color.rgb = srgb_to_linear(color.rgb);
     }
 
-#ifdef WATER_FOG
-    vec4 fogged = applyWaterFogView(pos.xyz, vec4(color, bloom));
-    color       = fogged.rgb;
-    bloom       = fogged.a;
-#endif
-    #if DEBUG_PBR_LIGHT_TYPE
-        color.rgb = vec3(0);
-    #endif
-    // convert to linear as fullscreen lights need to sum in linear colorspace
-    // and will be gamma (re)corrected downstream...
-    //color = ambenv;
-    //color.b = diffuse.a;
-    frag_color.rgb = srgb_to_linear(color.rgb);
-}
-#if DEBUG_PBR_AMBOCC
-    frag_color.rgb = vec3(ambocc);
-#endif
-#if DEBUG_PBR_AMBENV
-    frag_color.rgb = ambenv;
-#endif
     frag_color.a = bloom;
 }
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index ee085a65c2e..b992ab03949 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -617,7 +617,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
 
                 if (is_pbr && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND)
                 {
-                    target_shader = &gDeferredPBRAlphaProgram[rigged];
+                    target_shader = &gDeferredPBRAlphaProgram;
+                    if (params.mAvatar != nullptr)
+                    {
+                        target_shader = target_shader->mRiggedVariant;
+                    }
+
                     if (current_shader != target_shader)
                     {
                         gPipeline.bindDeferredShader(*target_shader);
@@ -662,9 +667,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                     target_shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, params.mGLTFMaterial->mRoughnessFactor);
                     target_shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, params.mGLTFMaterial->mMetallicFactor);
                     target_shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, params.mGLTFMaterial->mEmissiveColor.mV);
-
-                    target_shader->mLightHash = 0;
-                    gGL.syncLightState(); // Set light uniforms
                 }
                 else
                 {
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 391cfab5c00..2ebe0f826f4 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -265,7 +265,8 @@ LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
 LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 LLGLSLShader			gDeferredPBROpaqueProgram;
 LLGLSLShader            gDeferredSkinnedPBROpaqueProgram;
-LLGLSLShader            gDeferredPBRAlphaProgram[2]; // not skinned, skinned
+LLGLSLShader            gDeferredPBRAlphaProgram;
+LLGLSLShader            gDeferredSkinnedPBRAlphaProgram;
 
 //helper for making a rigged variant of a given shader
 bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader)
@@ -374,7 +375,10 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredWLSkyProgram);
 	mShaderList.push_back(&gDeferredWLCloudProgram);
     mShaderList.push_back(&gDeferredWLMoonProgram);
-    mShaderList.push_back(&gDeferredWLSunProgram);    
+    mShaderList.push_back(&gDeferredWLSunProgram);
+    mShaderList.push_back(&gDeferredPBRAlphaProgram);
+    mShaderList.push_back(&gDeferredSkinnedPBRAlphaProgram);
+
 }
 
 LLViewerShaderMgr::~LLViewerShaderMgr()
@@ -1284,8 +1288,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
         gDeferredPBROpaqueProgram.unload();
         gDeferredSkinnedPBROpaqueProgram.unload();
-        gDeferredPBRAlphaProgram[0].unload();
-        gDeferredPBRAlphaProgram[1].unload();
+        gDeferredPBRAlphaProgram.unload();
+        gDeferredSkinnedPBRAlphaProgram.unload();
 
 		return TRUE;
 	}
@@ -1622,76 +1626,70 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 	if (success)
 	{
-        for (int rigged = 0; rigged < 2 && success; ++rigged)
-        {
-            LLGLSLShader* shader = &gDeferredPBRAlphaProgram[rigged];
-            shader->mName = rigged
-                          ? "Skinned Deferred PBR Alpha Shader"
-                          : "Deferred PBR Alpha Shader";
-            shader->mRiggedVariant = rigged
-                                   ? &gDeferredPBRAlphaProgram[1]
-                                   : nullptr;
-            shader->mFeatures.hasObjectSkinning = (bool)rigged;
-            shader->mFeatures.calculatesLighting = false;
-            shader->mFeatures.hasLighting = false;
-            shader->mFeatures.isAlphaLighting = true;
-            shader->mFeatures.hasSrgb = true;
-            shader->mFeatures.encodesNormal = true;
-            shader->mFeatures.calculatesAtmospherics = true;
-            shader->mFeatures.hasAtmospherics = true;
-            shader->mFeatures.hasGamma = true;
-            shader->mFeatures.hasTransport = true;
-            shader->mFeatures.hasShadows = use_sun_shadow;
-            shader->mFeatures.isDeferred = true; // include deferredUtils
-            shader->mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED];
-
-            shader->mShaderFiles.clear();
-            shader->mShaderFiles.push_back(make_pair("deferred/pbralphaV.glsl", GL_VERTEX_SHADER_ARB));
-            shader->mShaderFiles.push_back(make_pair("deferred/pbralphaF.glsl", GL_FRAGMENT_SHADER_ARB));
-
-            shader->clearPermutations();
+        LLGLSLShader* shader = &gDeferredPBRAlphaProgram;
+        shader->mName = "Deferred PBR Alpha Shader";
+                          
+        shader->mFeatures.calculatesLighting = false;
+        shader->mFeatures.hasLighting = false;
+        shader->mFeatures.isAlphaLighting = true;
+        shader->mFeatures.hasSrgb = true;
+        shader->mFeatures.encodesNormal = true;
+        shader->mFeatures.calculatesAtmospherics = true;
+        shader->mFeatures.hasAtmospherics = true;
+        shader->mFeatures.hasGamma = true;
+        shader->mFeatures.hasTransport = true;
+        shader->mFeatures.hasShadows = use_sun_shadow;
+        shader->mFeatures.isDeferred = true; // include deferredUtils
+        shader->mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED];
+
+        shader->mShaderFiles.clear();
+        shader->mShaderFiles.push_back(make_pair("deferred/pbralphaV.glsl", GL_VERTEX_SHADER_ARB));
+        shader->mShaderFiles.push_back(make_pair("deferred/pbralphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+        shader->clearPermutations();
+
+        U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+        shader->addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+        shader->addPermutation("HAS_NORMAL_MAP", "1");
+        shader->addPermutation("HAS_SPECULAR_MAP", "1"); // PBR: Packed: Occlusion, Metal, Roughness
+        shader->addPermutation("HAS_EMISSIVE_MAP", "1");
+        shader->addPermutation("USE_VERTEX_COLOR", "1");
 
-            U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
-            shader->addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
-            shader->addPermutation("HAS_NORMAL_MAP", "1");
-            shader->addPermutation("HAS_SPECULAR_MAP", "1"); // PBR: Packed: Occlusion, Metal, Roughness
-            shader->addPermutation("HAS_EMISSIVE_MAP", "1");
-            shader->addPermutation("USE_VERTEX_COLOR", "1");
-            if (use_sun_shadow)
-            {
-                shader->addPermutation("HAS_SHADOW", "1");
-            }
-
-            if (ambient_kill)
-            {
-                shader->addPermutation("AMBIENT_KILL", "1");
-            }
-
-            if (sunlight_kill)
-            {
-                shader->addPermutation("SUNLIGHT_KILL", "1");
-            }
+        if (use_sun_shadow)
+        {
+            shader->addPermutation("HAS_SHADOW", "1");
+        }
 
-            if (local_light_kill)
-            {
-                shader->addPermutation("LOCAL_LIGHT_KILL", "1");
-            }
+        if (ambient_kill)
+        {
+            shader->addPermutation("AMBIENT_KILL", "1");
+        }
 
-            if (rigged)
-            {
-                shader->addPermutation("HAS_SKIN", "1");
-            }
+        if (sunlight_kill)
+        {
+            shader->addPermutation("SUNLIGHT_KILL", "1");
+        }
 
-            shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        if (local_light_kill)
+        {
+            shader->addPermutation("LOCAL_LIGHT_KILL", "1");
+        }
 
+        shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = make_rigged_variant(*shader, gDeferredSkinnedPBRAlphaProgram);
+        if (success)
+        {
             success = shader->createShader(NULL, NULL);
-            llassert(success);
-
-            // Alpha Shader Hack
-            // See: LLRender::syncMatrices()
-            shader->mFeatures.calculatesLighting = true;
-            shader->mFeatures.hasLighting = true;
         }
+        llassert(success);
+
+        // Alpha Shader Hack
+        // See: LLRender::syncMatrices()
+        shader->mFeatures.calculatesLighting = true;
+        shader->mFeatures.hasLighting = true;
+
+        shader->mRiggedVariant->mFeatures.calculatesLighting = true;
+        shader->mRiggedVariant->mFeatures.hasLighting = true;
     }
 
 	
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 38f67cd23ca..19d8e87d660 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -322,5 +322,5 @@ extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
 extern LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
 extern LLGLSLShader         gDeferredPBROpaqueProgram;
-extern LLGLSLShader         gDeferredPBRAlphaProgram[2]; // not skinned, skinned
+extern LLGLSLShader         gDeferredPBRAlphaProgram;
 #endif
-- 
GitLab