From cbd17fce86cc30434d6d665338a7d771bddcad8b Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Thu, 25 May 2023 16:09:22 -0400
Subject: [PATCH] Fix underwater fog mismatch between opaque and alpha blend
 when local lights are nearby (#227)

* Fix water fog mismatch between alpha blend and opaque when local light is nearby

* Add PBR underwater alpha blend shader
---
 .../shaders/class2/deferred/alphaF.glsl       |  9 ++-
 .../shaders/class2/deferred/pbralphaF.glsl    |  9 +++
 .../shaders/class3/deferred/materialF.glsl    | 12 ++--
 indra/newview/lldrawpoolalpha.cpp             |  5 +-
 indra/newview/llviewershadermgr.cpp           | 62 +++++++++++++++++++
 indra/newview/llviewershadermgr.h             |  1 +
 6 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index ae8cd97b180..cd57b47eae0 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -274,6 +274,10 @@ void main()
 
     color.rgb = atmosFragLightingLinear(color.rgb, additive, atten);
 
+#ifdef WATER_FOG
+    color = applyWaterFogViewLinear(pos.xyz, color, sunlit_linear);
+#endif // WATER_FOG
+
     vec4 light = vec4(0,0,0,0);
     
    #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, diffuse_linear.rgb, pos.xyz, norm, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
@@ -291,11 +295,6 @@ void main()
     color.rgb += light.rgb;
 #endif // !defined(LOCAL_LIGHT_KILL)
 
-
-#ifdef WATER_FOG
-    color = applyWaterFogViewLinear(pos.xyz, color, sunlit_linear);
-#endif // WATER_FOG
-
 #endif // #else // FOR_IMPOSTOR
 
 #ifdef IS_HUD
diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
index e6aef7abdc8..9ac106149ec 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
@@ -84,6 +84,10 @@ vec3 linear_to_srgb(vec3 c);
 void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
 vec3 atmosFragLightingLinear(vec3 color, vec3 additive, vec3 atten);
 
+#ifdef WATER_FOG
+vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
+#endif
+
 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);
 float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
@@ -237,6 +241,11 @@ void main()
 
     color.rgb = atmosFragLightingLinear(color.rgb, additive, atten);
     
+#ifdef WATER_FOG
+    vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0), sunlit_linear);
+    color = temp.rgb;
+#endif
+
     vec3 light = vec3(0);
 
     // Punctual lights
diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
index ba19fe0f19a..5fb5647d35b 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
@@ -38,7 +38,7 @@ uniform float emissive_brightness;  // fullbright flag, 1.0 == fullbright, 0.0 o
 uniform int sun_up_factor;
 
 #ifdef WATER_FOG
-vec4 applyWaterFogView(vec3 pos, vec4 color);
+vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
 #endif
 
 vec3 atmosFragLightingLinear(vec3 l, vec3 additive, vec3 atten);
@@ -411,6 +411,11 @@ void main()
 
     color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); 
 
+#ifdef WATER_FOG
+    vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0), sunlit_linear);
+    color = temp.rgb;
+#endif
+
     vec3 npos = normalize(-pos.xyz);
     vec3 light = vec3(0, 0, 0);
 
@@ -431,11 +436,6 @@ void main()
     glare = min(glare, 1.0);
     float al = max(diffcol.a, glare) * vertex_color.a;
     
-#ifdef WATER_FOG
-    vec4 temp = applyWaterFogView(pos, vec4(color, 0.0));
-    color = temp.rgb;
-#endif
-
     frag_color = max(vec4(color, al), vec4(0));
 
 #else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer 
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 67bc0463c8a..6aa23165896 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -197,7 +197,10 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
         prepare_alpha_shader(&materialShader[i], false, true, water_sign);
     }
 
-    pbr_shader = LLPipeline::sRenderingHUDs ? &gHUDPBRAlphaProgram : &gDeferredPBRAlphaProgram;
+    pbr_shader = 
+        (LLPipeline::sUnderWaterRender) ? &gDeferredPBRAlphaWaterProgram : 
+        (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram : 
+        &gDeferredPBRAlphaProgram;
 
     prepare_alpha_shader(pbr_shader, false, true, water_sign);
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 8e5f5ef8661..44147184ef1 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -222,6 +222,8 @@ LLGLSLShader            gDeferredSkinnedPBROpaqueProgram;
 LLGLSLShader            gHUDPBRAlphaProgram;
 LLGLSLShader            gDeferredPBRAlphaProgram;
 LLGLSLShader            gDeferredSkinnedPBRAlphaProgram;
+LLGLSLShader            gDeferredPBRAlphaWaterProgram;
+LLGLSLShader            gDeferredSkinnedPBRAlphaWaterProgram;
 
 //helper for making a rigged variant of a given shader
 bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader)
@@ -296,8 +298,10 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
     mShaderList.push_back(&gDeferredWLMoonProgram);
     mShaderList.push_back(&gDeferredWLSunProgram);
     mShaderList.push_back(&gDeferredPBRAlphaProgram);
+    mShaderList.push_back(&gDeferredPBRAlphaWaterProgram);
     mShaderList.push_back(&gHUDPBRAlphaProgram);
     mShaderList.push_back(&gDeferredSkinnedPBRAlphaProgram);
+    mShaderList.push_back(&gDeferredSkinnedPBRAlphaWaterProgram);
     mShaderList.push_back(&gDeferredPostGammaCorrectProgram); // for gamma
     mShaderList.push_back(&gNoPostGammaCorrectProgram);
     mShaderList.push_back(&gLegacyPostGammaCorrectProgram);
@@ -1020,6 +1024,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         gDeferredSkinnedPBROpaqueProgram.unload();
         gDeferredPBRAlphaProgram.unload();
         gDeferredSkinnedPBRAlphaProgram.unload();
+        gDeferredPBRAlphaWaterProgram.unload();
+        gDeferredSkinnedPBRAlphaWaterProgram.unload();
 
 		return TRUE;
 	}
@@ -1411,6 +1417,62 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         shader->mRiggedVariant->mFeatures.hasLighting = true;
     }
 
+    if (success)
+    {
+        LLGLSLShader* shader = &gDeferredPBRAlphaWaterProgram;
+        shader->mName = "Deferred PBR Alpha Underwater Shader";
+                          
+        shader->mFeatures.calculatesLighting = false;
+        shader->mFeatures.hasLighting = false;
+        shader->mFeatures.isAlphaLighting = true;
+        shader->mFeatures.hasWaterFog = true;
+        shader->mFeatures.hasSrgb = true;
+        shader->mFeatures.encodesNormal = true;
+        shader->mFeatures.calculatesAtmospherics = true;
+        shader->mFeatures.hasAtmospherics = true;
+        shader->mFeatures.hasGamma = true;
+        shader->mFeatures.hasShadows = use_sun_shadow;
+        shader->mFeatures.isDeferred = true; // include deferredUtils
+        shader->mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED];
+
+        shader->mShaderGroup = LLGLSLShader::SG_WATER;
+
+        shader->mShaderFiles.clear();
+        shader->mShaderFiles.push_back(make_pair("deferred/pbralphaV.glsl", GL_VERTEX_SHADER));
+        shader->mShaderFiles.push_back(make_pair("deferred/pbralphaF.glsl", GL_FRAGMENT_SHADER));
+
+        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");
+        shader->addPermutation("WATER_FOG", "1");
+
+        if (use_sun_shadow)
+        {
+            shader->addPermutation("HAS_SUN_SHADOW", "1");
+        }
+
+        shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = make_rigged_variant(*shader, gDeferredSkinnedPBRAlphaWaterProgram);
+        if (success)
+        {
+            success = shader->createShader(NULL, NULL);
+        }
+        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;
+    }
+
     if (success)
     {
         LLGLSLShader* shader = &gHUDPBRAlphaProgram;
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 492e60b840a..f4d5df701d6 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -277,5 +277,6 @@ extern LLGLSLShader         gHUDPBROpaqueProgram;
 extern LLGLSLShader         gPBRGlowProgram;
 extern LLGLSLShader         gDeferredPBROpaqueProgram;
 extern LLGLSLShader         gDeferredPBRAlphaProgram;
+extern LLGLSLShader         gDeferredPBRAlphaWaterProgram;
 extern LLGLSLShader         gHUDPBRAlphaProgram;
 #endif
-- 
GitLab