From 53372ea8ae0654ae6065f963eabd6215f720544a Mon Sep 17 00:00:00 2001
From: Ptolemy <ptolemy@lindenlab.com>
Date: Thu, 14 Jul 2022 23:53:52 -0700
Subject: [PATCH] SL-17702: PBR: First pass point lights

---
 .../shaders/class1/deferred/deferredUtil.glsl | 91 ++++++++++++++++++-
 .../shaders/class3/deferred/pointLightF.glsl  | 24 ++++-
 .../shaders/class3/deferred/softenLightF.glsl | 27 +-----
 3 files changed, 112 insertions(+), 30 deletions(-)

diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
index 5dfdd2006e7..e28d4f38e8f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
@@ -29,11 +29,15 @@ uniform sampler2DRect   depthMap;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
+const float M_PI = 3.14159265;
+
 void calcHalfVectors(vec3 h, vec3 n, vec3 v, out float nh, out float nv, out float vh)
 {
-    nh = dot(n, h);
-    nv = dot(n, v);
-    vh = dot(v, h);
+//  l  = normalize(lv);
+//  h  = normalize(l + v);
+    nh = clamp(dot(n, h), 0.0, 1.0);
+    nv = clamp(dot(n, v), 0.0, 1.0);
+    vh = clamp(dot(v, h), 0.0, 1.0);
 }
 
 vec2 getScreenCoordinate(vec2 screenpos)
@@ -120,3 +124,84 @@ vec2 getScreenXY(vec4 clip)
 }
 
 // PBR Utils
+
+vec3 fresnelSchlick( vec3 reflect0, vec3 reflect90, float vh)
+{
+    return reflect0 + (reflect90 - reflect0) * pow(clamp(1.0 - vh, 0.0, 1.0), 5.0);
+}
+
+// Approximate Environment BRDF
+vec2 getGGXApprox( vec2 uv )
+{
+    // Reference: Physically Based Shading on Mobile
+    // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
+    //     EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
+    float nv        = uv.x;
+    float roughness = uv.y;
+
+    const vec4  c0        = vec4( -1, -0.0275, -0.572, 0.022 );
+    const vec4  c1        = vec4(  1,  0.0425,  1.04 , -0.04 );
+          vec4  r         = roughness * c0 + c1;
+          float a004      = min( r.x * r.x, exp2( -9.28 * nv ) ) * r.x + r.y;
+          vec2  ScaleBias = vec2( -1.04, 1.04 ) * a004 + r.zw;
+    return ScaleBias;
+}
+
+#define PBR_USE_GGX_APPROX 1
+vec2 getGGX( vec2 brdfPoint )
+{
+#if PBR_USE_GGX_APPROX
+    return getGGXApprox( brdfPoint);
+#else
+    return texture2D(GGXLUT, brdfPoint).rg;   // TODO: use GGXLUT
+#endif
+}
+
+// NOTE: This is different from the GGX texture
+float D_GGX( float nh, float alphaRough )
+{
+    float rough2 = alphaRough * alphaRough;
+    float f      = (nh * nh) * (rough2 - 1.0) + 1.0;
+    return rough2 / (M_PI * f * f);
+}
+
+// NOTE: This is different from the GGX texture
+float V_GGX( float nl, float nv, float alphaRough )
+{
+    float rough2 = alphaRough * alphaRough;
+    float ggxv   = nl * sqrt(nv * nv * (1.0 - rough2) + rough2);
+    float ggxl   = nv * sqrt(nl * nl * (1.0 - rough2) + rough2);
+    float ggx    = ggxv + ggxl;
+    if (ggx > 0.0)
+    {
+        return 0.5 / ggx;
+    }
+    return 0.0;
+}
+
+void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight )
+{
+    float metal      = packedORM.b;
+          c_diff     = mix(diffuse.rgb, vec3(0), metal);
+    float IOR        = 1.5;                                // default Index Of Refraction 1.5 (dielectrics)
+          reflect0   = vec3(0.04);                         // -> incidence reflectance 0.04
+          reflect0   = mix( reflect0, diffuse.rgb, metal); // reflect at 0 degrees
+          reflect90  = vec3(1);                            // reflect at 90 degrees
+          specWeight = 1.0;
+
+    float perceptualRough = packedORM.g;
+          alphaRough      = perceptualRough * perceptualRough;
+}
+
+vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh )
+{
+    return (1.0 - specWeight * fresnelSchlick( reflect0, reflect90, vh)) * (c_diff / M_PI);
+}
+
+vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRough, float specWeight, float vh, float nl, float nv, float nh )
+{
+    vec3  fresnel    = fresnelSchlick( reflect0, reflect90, vh );
+    float vis       = V_GGX( nl, nv, alphaRough );
+    float d         = D_GGX( nh, alphaRough );
+    return specWeight * fresnel * vis * d;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
index 9db906bc5a8..46de34e49a3 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
@@ -57,10 +57,13 @@ uniform vec2 screen_res;
 uniform mat4 inv_proj;
 uniform vec4 viewport;
 
+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 calcHalfVectors(vec3 h, vec3 n, vec3 v, out float nh, out float nv, out float vh);
 vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
 vec4 getPosition(vec2 pos_screen);
 vec2 getScreenXY(vec4 clip);
+void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight );
 vec3 srgb_to_linear(vec3 c);
 
 void main()
@@ -88,9 +91,7 @@ void main()
     }
 
     lv = normalize(lv);
-    da = dot(n, lv);
-
-    float noise = texture2D(noiseMap, tc/128.0).b;
+    da = dot(n, lv); // alias for: nl
 
     vec3 diffuse = texture2DRect(diffuseRect, tc).rgb;
     vec4 spec    = texture2DRect(specularRect, tc);
@@ -108,6 +109,20 @@ void main()
         vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive.  See: pbropaqueF.glsl
         vec3 packedORM     = texture2DRect(emissiveRect, tc).rgb; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl
 
+        vec3 c_diff, reflect0, reflect90;
+        float alphaRough, specWeight;
+        initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight );
+
+        vec3  l    = lv; // already normalized
+        float nl   = clamp(dot(n, l), 0.0, 1.0);
+
+        if (nl > 0.0 || nv > 0.0)
+        {
+            vec3 intensity = size * color;
+            colorDiffuse += intensity * nl * BRDFLambertian ( reflect0, reflect90, c_diff    , specWeight, vh );
+            colorSpec    += intensity * nl * BRDFSpecularGGX( reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh );
+        }
+
         final_color = colorDiffuse + colorSpec;
     }
     else
@@ -116,7 +131,8 @@ void main()
         float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
         dist_atten *= dist_atten;
         dist_atten *= 2.0;
-    
+
+        float noise = texture2D(noiseMap, tc/128.0).b;
         float lit = da * dist_atten * noise;
 
         final_color = color.rgb*lit*diffuse;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index 3aef3ac8ba5..59076d97600 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -23,16 +23,15 @@
  * $/LicenseInfo$
  */
 
-#define PBR_USE_ATMOS              1
-#define PBR_USE_GGX_APPROX         1
-#define PBR_USE_GGX_EMS_HACK       1
+#define PBR_USE_ATMOS              0
+#define PBR_USE_GGX_EMS_HACK       0
 #define PBR_USE_IRRADIANCE_HACK    1
 
 #define DEBUG_PBR_PACKORM0         0 // Rough=0, Metal=0
 #define DEBUG_PBR_PACKORM1         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     1 // Force specLigh to be 0,0.5,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
@@ -134,6 +133,7 @@ vec4 getPositionWithDepth(vec2 pos_screen, float depth);
 
 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 getAmbientClamp();
+vec2 getGGX( vec2 brdfPoint );
 vec3  atmosFragLighting(vec3 l, vec3 additive, vec3 atten);
 vec3  scaleSoftClipFrag(vec3 l);
 vec3  fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten);
@@ -154,25 +154,6 @@ vec4 applyWaterFogView(vec3 pos, vec4 color);
 
 uniform vec3 view_dir; // PBR
 
-// Approximate Environment BRDF
-vec2 getGGXApprox( vec2 uv )
-{
-    vec2  st    = vec2(1.) - uv;
-    float d     = (st.x * st.x * 0.5) * (st.y * st.y);
-    float scale = 1.0 - d;
-    float bias  = d;
-    return vec2( scale, bias );
-}
-
-vec2 getGGX( vec2 brdfPoint )
-{
-    // TODO: use GGXLUT
-    // texture2D(GGXLUT, brdfPoint).rg;
-#if PBR_USE_GGX_APPROX
-    return getGGXApprox( brdfPoint);
-#endif
-}
-
 vec3 calcBaseReflect0(float ior)
 {
     vec3   reflect0 = vec3(pow((ior - 1.0) / (ior + 1.0), 2.0));
-- 
GitLab