diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index b8071248e2861f9789905744eeb7abbd81060e7f..43d095f73ac8aa5c35d79929e87fe7dca0d3a62f 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -41,7 +41,6 @@ class LLShaderFeatures
     bool hasLighting = false; // implies no transport (it's possible to have neither though)
     bool isAlphaLighting = false; // indicates lighting shaders need not be linked in (lighting performed directly in alpha shader to match deferred lighting functions)
     bool isSpecular = false;
-    bool hasWaterFog = false; // implies no gamma
     bool hasTransport = false; // implies no lighting (it's possible to have neither though)
     bool hasSkinning = false;
     bool hasObjectSkinning = false;
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 0e7f9e1331c0c395d0156d638b4c4ca8530037be..f78be910d2fbd59bf142857939928239338cd6ca 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -81,14 +81,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 	// NOTE order of shader object attaching is VERY IMPORTANT!!!
 	if (features->calculatesAtmospherics)
 	{
-		if (features->hasWaterFog)
-		{
-			if (!shader->attachVertexObject("windlight/atmosphericsVarsWaterV.glsl"))
-			{
-				return FALSE;
-			}
-		}
-        else if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl"))
+		if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl"))
 		{
 			return FALSE;
 		}
@@ -201,14 +194,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 
 	if(features->calculatesAtmospherics || features->hasGamma || features->isDeferred)
 	{
-		if (features->hasWaterFog)
-		{
-			if (!shader->attachFragmentObject("windlight/atmosphericsVarsWaterF.glsl"))
-			{
-				return FALSE;
-			}
-		}
-        else if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl"))
+		if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl"))
 		{
 			return FALSE;
 		}
@@ -292,7 +278,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 	}
 	
 	// NOTE order of shader object attaching is VERY IMPORTANT!!!
-	if (features->hasWaterFog)
+	if (features->hasAtmospherics)
 	{
         if (!shader->attachFragmentObject("environment/waterFogF.glsl"))
 		{
@@ -302,82 +288,40 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 	
 	if (features->hasLighting)
 	{
-		if (features->hasWaterFog)
+		if (features->disableTextureIndex)
 		{
-			if (features->disableTextureIndex)
+			if (features->hasAlphaMask)
 			{
-				if (features->hasAlphaMask)
-				{
-                    if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl"))
-					{
-						return FALSE;
-					}
-				}
-				else
+                if (!shader->attachFragmentObject("lighting/lightAlphaMaskNonIndexedF.glsl"))
 				{
-                    if (!shader->attachFragmentObject("lighting/lightWaterNonIndexedF.glsl"))
-					{
-						return FALSE;
-					}
+					return FALSE;
 				}
 			}
-			else 
+			else
 			{
-				if (features->hasAlphaMask)
-				{
-                    if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskF.glsl"))
-					{
-						return FALSE;
-					}
-				}
-				else
+                if (!shader->attachFragmentObject("lighting/lightNonIndexedF.glsl"))
 				{
-                    if (!shader->attachFragmentObject("lighting/lightWaterF.glsl"))
-					{
-						return FALSE;
-					}
+					return FALSE;
 				}
-				shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
 			}
 		}
-		
-		else
+		else 
 		{
-			if (features->disableTextureIndex)
+			if (features->hasAlphaMask)
 			{
-				if (features->hasAlphaMask)
+                if (!shader->attachFragmentObject("lighting/lightAlphaMaskF.glsl"))
 				{
-                    if (!shader->attachFragmentObject("lighting/lightAlphaMaskNonIndexedF.glsl"))
-					{
-						return FALSE;
-					}
-				}
-				else
-				{
-                    if (!shader->attachFragmentObject("lighting/lightNonIndexedF.glsl"))
-					{
-						return FALSE;
-					}
+					return FALSE;
 				}
 			}
-			else 
+			else
 			{
-				if (features->hasAlphaMask)
-				{
-                    if (!shader->attachFragmentObject("lighting/lightAlphaMaskF.glsl"))
-					{
-						return FALSE;
-					}
-				}
-				else
+                if (!shader->attachFragmentObject("lighting/lightF.glsl"))
 				{
-                    if (!shader->attachFragmentObject("lighting/lightF.glsl"))
-					{
-						return FALSE;
-					}
+					return FALSE;
 				}
-				shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
 			}
+			shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
 		}
 	}
 	
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index 5d58cc91cd4df7d8e59c32be1631b89e376c5970..8b2a69b92492c520326753b6c54d7855e25abc36 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -35,21 +35,19 @@ in vec3 vary_position;
 in vec4 vertex_color;
 in vec2 vary_texcoord0;
 
-#ifdef WATER_FOG
-vec4 applyWaterFogView(vec3 pos, vec4 color);
-#endif
-
 vec3 srgb_to_linear(vec3 cs);
 vec3 linear_to_srgb(vec3 cl);
-vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
-void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
 
 #ifdef HAS_ALPHA_MASK
 uniform float minimum_alpha;
 #endif
 
 #ifdef IS_ALPHA
+uniform vec4 waterPlane;
 void waterClip(vec3 pos);
+void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive,
+                         out vec3 atten);
+vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
 #endif
 
 void main() 
@@ -79,25 +77,20 @@ void main()
     vec3 pos = vary_position;
 
 #ifndef IS_HUD
+    color.rgb = srgb_to_linear(color.rgb);
+    color.a = final_alpha;
+#ifdef IS_ALPHA
+
     vec3 sunlit;
     vec3 amblit;
     vec3 additive;
     vec3 atten;
     calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten);
-#endif
 
-#ifdef WATER_FOG
+    color.rgb = applySkyAndWaterFog(pos, additive, atten, color).rgb;
     
-    vec4 fogged = applyWaterFogView(pos, vec4(color.rgb, final_alpha));
-    color.rgb = fogged.rgb;
-    color.a   = fogged.a;
-#else
-    color.a   = final_alpha;
 #endif
 
-#ifndef IS_HUD
-    color.rgb = srgb_to_linear(color.rgb);
-    color.rgb = atmosFragLighting(color.rgb, additive, atten);
 #endif
 
     frag_color = max(color, vec4(0));
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
index cfdb393b348297af48c4e493277f8c98913abb2f..f796bb5f3fecb0e835af4f4a9bc875ecf2129b71 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
@@ -30,12 +30,14 @@ uniform vec4 waterFogColor;
 uniform float waterFogDensity;
 uniform float waterFogKS;
 
-vec3 getPositionEye();
-
 vec3 srgb_to_linear(vec3 col);
 vec3 linear_to_srgb(vec3 col);
 
-vec4 applyWaterFogView(vec3 pos, vec4 color)
+vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
+
+// get a water fog color that will apply the appropriate haze to a color given
+// a blend function of (ONE, SOURCE_ALPHA)
+vec4 getWaterFogViewNoClip(vec3 pos)
 {
     vec3 view = normalize(pos);
     //normalize view vector
@@ -67,38 +69,76 @@ vec4 applyWaterFogView(vec3 pos, vec4 color)
     float L = min(t1/t2*t3, 1.0);
     
     float D = pow(0.98, l*kd);
+
+    return vec4(srgb_to_linear(kc.rgb*L), D);
+}
+
+vec4 getWaterFogView(vec3 pos)
+{
+    if (dot(pos, waterPlane.xyz) + waterPlane.w > 0.0)
+    {
+        return vec4(0,0,0,1);
+    }
+
+    return getWaterFogViewNoClip(pos);
+}
+
+vec4 applyWaterFogView(vec3 pos, vec4 color)
+{
+    vec4 fogged = getWaterFogView(pos);
     
-    color.rgb = color.rgb * D + kc.rgb * L;
+    color.rgb = color.rgb * fogged.a + fogged.rgb;
 
     return color;
 }
 
-vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color, vec3 sunlit)
+vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color)
 {
-    color.rgb = linear_to_srgb(color.rgb);
-    color = applyWaterFogView(pos, color);
-    color.rgb = srgb_to_linear(color.rgb);
+    vec4 fogged = getWaterFogViewNoClip(pos);
+    color.rgb *= fogged.a;
+    color.rgb += fogged.rgb;
     return color;
 }
 
-vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit)
+vec4 applyWaterFogViewLinear(vec3 pos, vec4 color)
 {
     if (dot(pos, waterPlane.xyz) + waterPlane.w > 0.0)
     {
         return color;
     }
 
-    return applyWaterFogViewLinearNoClip(pos, color, sunlit);
+    return applyWaterFogViewLinearNoClip(pos, color);
 }
 
-vec4 applyWaterFogViewLinear(vec3 pos, vec4 color)
+// for post deferred shaders, apply sky and water fog in a way that is consistent with
+// the deferred rendering haze post effects
+vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color)
 {
-    return applyWaterFogViewLinear(pos, color, vec3(1));
-}
+    bool eye_above_water = dot(vec3(0), waterPlane.xyz) + waterPlane.w > 0.0;
+    bool obj_above_water = dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0;
 
-vec4 applyWaterFog(vec4 color)
-{
-    //normalize view vector
-    return applyWaterFogViewLinear(getPositionEye(), color);
-}
+    if (eye_above_water)
+    {
+        if (!obj_above_water)
+        { 
+            color.rgb = applyWaterFogViewLinearNoClip(pos, color).rgb;
+        }
+        else
+        {
+            color.rgb = atmosFragLighting(color.rgb, additive, atten);
+        }
+    }
+    else
+    {
+        if (obj_above_water)
+        {
+            color.rgb = atmosFragLighting(color.rgb, additive, atten);
+        }
+        else
+        {
+            color.rgb = applyWaterFogViewLinearNoClip(pos, color).rgb;
+        }
+    }
 
+    return color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
deleted file mode 100644
index 09b4a6e3179f7b95962a710682c635f44ecce688..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
+++ /dev/null
@@ -1,42 +0,0 @@
-/** 
- * @file class1\lighting\lightWaterF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-out vec4 frag_color;
-
-in vec4 vertex_color;
-in vec2 vary_texcoord0;
-
-vec3 atmosLighting(vec3 light);
-vec4 applyWaterFog(vec4 color);
-
-void default_lighting_water()
-{
-	vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color;
-
-	color.rgb = atmosLighting(color.rgb);
-
-	frag_color = max(applyWaterFog(color), vec4(0));
-}
-
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl
deleted file mode 100644
index 4888fa547c7df30d86c8d2ad269360026d9226ae..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-/** 
- * @file class1\lighting\lightWaterNonIndexedF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-out vec4 frag_color;
-
-in vec4 vertex_color;
-in vec2 vary_texcoord0;
-
-uniform sampler2D diffuseMap;
-
-vec3 atmosLighting(vec3 light);
-vec4 applyWaterFog(vec4 color);
-
-void default_lighting_water()
-{
-	vec4 color = texture(diffuseMap,vary_texcoord0.xy) * vertex_color;
-
-	color.rgb = atmosLighting(color.rgb);
-
-	frag_color = max(applyWaterFog(color), vec4(0));
-}
-
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
deleted file mode 100644
index 2e87ac5bbc2d091f0ea7ac597b7a980e093b6ec0..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-/** 
- * @file simpleWaterF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
- 
-
-
-void default_lighting_water();
-
-void main() 
-{
-	default_lighting_water();
-}
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
index 6ecbfaecb10e8ab3596304579cf8a5a0a3467815..4f88aed7657ece9f621ee17497ab79fb78aed131 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
@@ -30,7 +30,6 @@ vec3 getSunlitColor();
 vec3 getAmblitColor();
 vec3 getAdditiveColor();
 vec3 getAtmosAttenuation();
-vec3 getPositionEye();
 
 uniform float scene_light_strength;
 
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
index cc3617ba61b8f3a0f91afee4bcea22a5494788f3..7b59e07243ce7dc224b2655be957aba8f3cff5e5 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
@@ -42,7 +42,6 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
 
 void calcAtmospherics(vec3 inPositionEye) {
     vec3 P = inPositionEye;
-    setPositionEye(P);
     vec3 tmpsunlit = vec3(1);
     vec3 tmpamblit = vec3(1);
     vec3 tmpaddlit = vec3(1);
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
index 34669a67963383fcebfd388cc77d73b8e74326f8..9d5f60b313a30b5b808c2827f2c817dab007e3c2 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
@@ -44,5 +44,5 @@ vec3 getAdditiveColor()
 
 vec3 getAtmosAttenuation()
 {
-	return vec3(vary_AtmosAttenuation);
+	return vary_AtmosAttenuation;
 }
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
index 1b854d80b3c4abb02efbf7279a530c64bb7aabef..0617bc990817b7a2bf542aa9728086a3824036c9 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
@@ -31,7 +31,6 @@ vec3 additive_color;
 vec3 atmos_attenuation;
 vec3 sunlit_color;
 vec3 amblit_color;
-vec3 position_eye;
 
 vec3 getSunlitColor()
 {
@@ -51,16 +50,6 @@ vec3 getAtmosAttenuation()
 	return atmos_attenuation;
 }
 
-vec3 getPositionEye()
-{
-	return position_eye;
-}
-
-void setPositionEye(vec3 v)
-{
-	position_eye = v;
-}
-
 void setSunlitColor(vec3 v)
 {
 	sunlit_color  = v;
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl
deleted file mode 100644
index 7a6741fe0e5de4ce6bde4e120d801d5d87a87a7b..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl
+++ /dev/null
@@ -1,50 +0,0 @@
-/** 
- * @file class2\wl\atmosphericVarsWaterF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
- 
-in vec3 vary_PositionEye;
-in vec3 vary_AdditiveColor;
-in vec3 vary_AtmosAttenuation;
-
-vec3 getSunlitColor()
-{
-	return vec3(0,0,0);
-}
-vec3 getAmblitColor()
-{
-	return vec3(0,0,0);
-}
-vec3 getAdditiveColor()
-{
-	return vary_AdditiveColor;
-}
-vec3 getAtmosAttenuation()
-{
-	return vary_AtmosAttenuation;
-}
-vec3 getPositionEye()
-{
-	return vary_PositionEye;
-}
-
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl
deleted file mode 100644
index 23c3aed4d8597c64bd27ebd7e5ada533930ae984..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl
+++ /dev/null
@@ -1,81 +0,0 @@
-/** 
- * @file class2\wl\atmosphericVarsWaterV.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
- 
-out vec3 vary_PositionEye;
-out vec3 vary_AdditiveColor;
-out vec3 vary_AtmosAttenuation;
-
-vec3 atmos_attenuation;
-vec3 sunlit_color;
-vec3 amblit_color;
-
-vec3 getSunlitColor()
-{
-	return sunlit_color;
-}
-vec3 getAmblitColor()
-{
-	return amblit_color;
-}
-
-vec3 getAdditiveColor()
-{
-	return vary_AdditiveColor;
-}
-vec3 getAtmosAttenuation()
-{
-	return atmos_attenuation;
-}
-
-vec3 getPositionEye()
-{
-	return vary_PositionEye;
-}
-
-void setPositionEye(vec3 v)
-{
-	vary_PositionEye = v;
-}
-
-void setSunlitColor(vec3 v)
-{
-	sunlit_color  = v;
-}
-
-void setAmblitColor(vec3 v)
-{
-	amblit_color = v;
-}
-
-void setAdditiveColor(vec3 v)
-{
-	vary_AdditiveColor = v;
-}
-
-void setAtmosAttenuation(vec3 v)
-{
-	atmos_attenuation = v;
-	vary_AtmosAttenuation = v;
-}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index b63f3b60f9aa6367dd0372aea72e7b8a9672ac98..acd32a81b3c45ad0e2d9c31a7319190bab84e069 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -65,16 +65,11 @@ uniform vec3 light_diffuse[8];
 
 void waterClip(vec3 pos);
 
-#ifdef WATER_FOG
-vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
-#endif
-
 vec3 srgb_to_linear(vec3 c);
 vec3 linear_to_srgb(vec3 c);
 
 vec2 encode_normal (vec3 n);
-vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten);
-
+vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
 void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
 
 #ifdef HAS_SUN_SHADOW
@@ -270,12 +265,6 @@ void main()
 
     color.rgb *= diffuse_linear.rgb;
 
-    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,6 +280,8 @@ void main()
     // sum local light contrib in linear colorspace
     color.rgb += light.rgb;
 
+    color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, color).rgb;
+
 #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 35d752be0214dbbe0e807994a009d3e06b926b03..003dd05e6f016bb6db7be4abbf1d469406cabf25 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
@@ -82,11 +82,7 @@ vec3 srgb_to_linear(vec3 c);
 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
+vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
 
 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);
@@ -228,13 +224,6 @@ void main()
 
     color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten);
 
-    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
@@ -250,7 +239,8 @@ void main()
 
     color.rgb += light.rgb;
 
-    
+    color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
+
     float a = basecolor.a*vertex_color.a;
     
     frag_color = max(vec4(color.rgb,a), vec4(0));
@@ -305,6 +295,7 @@ void main()
     
     float a = basecolor.a*vertex_color.a;
     color += colorEmissive;
+
     color = linear_to_srgb(color);
     frag_color = max(vec4(color.rgb,a), vec4(0));
 }
diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
index 5483a4e29c470aadc9abd0213e61510bab2ebb0e..8430cca325e2ad4b10eae981d2c9ea40361f8419 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
@@ -40,6 +40,8 @@ in vec3 vary_position;
 uniform samplerCube environmentMap;
 
 vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
+vec4 applyWaterFogViewLinear(vec3 pos, vec4 color);
+
 void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
 
 vec3 linear_to_srgb(vec3 c);
@@ -83,7 +85,6 @@ void main()
     color.rgb = srgb_to_linear(color.rgb);
 
     applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity);
-    color.rgb = atmosFragLighting(color.rgb, additive, atten);
 #endif
 
 	color.a = 1.0;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..e8f7d73f1fead655cdfd875149c83458ee81f891
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl
@@ -0,0 +1,107 @@
+/**
+ * @file class3/deferred/hazeF.glsl
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+out vec4 frag_color;
+
+uniform sampler2D normalMap;
+
+// Inputs
+uniform vec3 sun_dir;
+uniform vec3 moon_dir;
+uniform int  sun_up_factor;
+in vec2 vary_fragcoord;
+
+vec3 getNorm(vec2 pos_screen);
+vec4 getPositionWithDepth(vec2 pos_screen, float depth);
+void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
+
+float getDepth(vec2 pos_screen);
+
+vec3 linear_to_srgb(vec3 c);
+vec3 srgb_to_linear(vec3 c);
+
+uniform vec4 waterPlane;
+
+uniform int cube_snapshot;
+
+uniform float sky_hdr_scale;
+
+void main()
+{
+    vec2  tc           = vary_fragcoord.xy;
+    float depth        = getDepth(tc.xy);
+    vec4  pos          = getPositionWithDepth(tc, depth);
+    vec4  norm         = texture(normalMap, tc);
+    norm.xyz           = getNorm(tc);
+    vec3  light_dir   = (sun_up_factor == 1) ? sun_dir : moon_dir;
+
+    vec3  color = vec3(0);
+    float bloom = 0.0;
+
+    vec3 sunlit;
+    vec3 amblit;
+    vec3 additive;
+    vec3 atten;
+
+    calcAtmosphericVarsLinear(pos.xyz, norm.xyz, light_dir, sunlit, amblit, additive, atten);
+
+    vec3 sunlit_linear = srgb_to_linear(sunlit);
+    
+    // mask off atmospherics below water (when camera is under water)
+    bool do_atmospherics = false;
+        
+    if (dot(vec3(0), waterPlane.xyz) + waterPlane.w > 0.0 ||
+        dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0)
+    {
+        do_atmospherics = true;
+    }
+    
+
+    vec3  irradiance = vec3(0);
+    vec3  radiance  = vec3(0);
+
+    if (depth >= 1.0)
+    {
+        //should only be true of WL sky, just port over base color value
+        discard;
+    }
+
+   float alpha = 0.0;
+
+    if (do_atmospherics)
+    {
+        alpha = atten.r;
+        color = srgb_to_linear(additive*2.0);
+        color *= sky_hdr_scale;
+    }
+    else
+    {
+        color = vec3(0,0,0);
+        alpha = 1.0;
+    }
+
+    frag_color.rgb = max(color.rgb, vec3(0)); //output linear since local lights will be added to this shader's results
+    frag_color.a = alpha;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
index acff03ec4b5ea3588328d84a3af0df4473ce49a2..ec1e49eeb4ee9ab7cf70745e84060dd3a87954d9 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
@@ -37,11 +37,7 @@
 uniform float emissive_brightness;  // fullbright flag, 1.0 == fullbright, 0.0 otherwise
 uniform int sun_up_factor;
 
-#ifdef WATER_FOG
-vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
-#endif
-
-vec3 atmosFragLightingLinear(vec3 l, vec3 additive, vec3 atten);
+vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
 vec3 scaleSoftClipFragLinear(vec3 l);
 void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
 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);
@@ -386,13 +382,6 @@ void main()
         glare += cur_glare;
     }
 
-    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);
 
@@ -408,6 +397,8 @@ void main()
 
     color += light;
 
+    color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
+
     glare *= 1.0-emissive;
     glare = min(glare, 1.0);
     float al = max(diffcol.a, glare) * vertex_color.a;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index 35e99c5bd2befb7894837dd60927ac7682fa9d1e..5e8fe9301a7f86af0908ad65f28066b3198c4004 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -83,10 +83,6 @@ uniform vec4 waterPlane;
 
 uniform int cube_snapshot;
 
-#ifdef WATER_FOG
-vec4 applyWaterFogViewLinear(vec3 pos, vec4 color);
-#endif
-
 uniform float sky_hdr_scale;
 
 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);
@@ -167,18 +163,6 @@ void main()
     vec3 sunlit_linear = srgb_to_linear(sunlit);
     vec3 amblit_linear = amblit;
 
-    bool do_atmospherics = false;
-
-#ifndef WATER_FOG
-    // when above water, mask off atmospherics below water
-    if (dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0)
-    {
-        do_atmospherics = true;
-    }
-#else
-    do_atmospherics = true;
-#endif
-
     vec3  irradiance = vec3(0);
     vec3  radiance  = vec3(0);
 
@@ -203,11 +187,6 @@ void main()
 
         vec3 v = -normalize(pos.xyz);
         color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten);
-        
-        if (do_atmospherics)
-        {
-            color = atmosFragLightingLinear(color, additive, atten);
-        }
     }
     else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS))
     {
@@ -273,21 +252,8 @@ void main()
         {  // add environment map
             applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity);
         }
-
-        
-        if (do_atmospherics)
-        {
-            color = atmosFragLightingLinear(color, additive, atten);
-        }
    }
 
-    
-
-    #ifdef WATER_FOG
-        vec4 fogged = applyWaterFogViewLinear(pos.xyz, vec4(color, bloom));
-        color       = fogged.rgb;
-    #endif
-
     frag_color.rgb = max(color.rgb, vec3(0)); //output linear since local lights will be added to this shader's results
     frag_color.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl
similarity index 53%
rename from indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
rename to indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl
index 670b3ddaf159162e2f916e039ba639e5a1943708..025bcdaf3e18bf4940d2fdb09568f23fc004b1b4 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl
@@ -1,51 +1,49 @@
-/** 
- * @file class1\lighting\lightWaterAlphaMaskF.glsl
+/**
+ * @file class3/deferred/waterHazeF.glsl
  *
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- * 
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
 out vec4 frag_color;
 
-uniform float minimum_alpha;
+// Inputs
+in vec4 vary_fragcoord;
 
-vec3 atmosLighting(vec3 light);
-vec4 applyWaterFog(vec4 color);
+uniform sampler2D normalMap;
 
-in vec4 vertex_color;
-in vec2 vary_texcoord0;
+vec4 getPositionWithDepth(vec2 pos_screen, float depth);
+float getDepth(vec2 pos_screen);
 
-void default_lighting_water()
-{
-	vec4 color = diffuseLookup(vary_texcoord0.xy);
-
-	if (color.a < minimum_alpha)
-	{
-		discard;
-	}
+vec4 getWaterFogView(vec3 pos);
 
-	color.rgb *= vertex_color.rgb;
+void main()
+{
+    vec2  tc           = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5;
+    float depth        = getDepth(tc.xy);
+    vec4  pos          = getPositionWithDepth(tc, depth);
+    vec4  norm         = texture(normalMap, tc);
 
-	color.rgb = atmosLighting(color.rgb);
+    vec4 fogged = getWaterFogView(pos.xyz);
 
-	frag_color = max(applyWaterFog(color), vec4(0));
+    frag_color.rgb = max(fogged.rgb, vec3(0)); //output linear since local lights will be added to this shader's results
+    frag_color.a = fogged.a;
 }
-
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeV.glsl
similarity index 53%
rename from indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
rename to indra/newview/app_settings/shaders/class3/deferred/waterHazeV.glsl
index 2e5ed570148696d0fdce1310f6c4112e8aaa08ff..16381a5d517a81d2213859b9858088ed6b30558c 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeV.glsl
@@ -1,55 +1,59 @@
-/** 
- * @file class1\lighting\lightWaterAlphaMaskNonIndexedF.glsl
+/**
+ * @file class3/deferred/waterHazeV.glsl
  *
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- * 
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
 
-out vec4 frag_color;
+in vec3 position;
 
-uniform float minimum_alpha;
+uniform vec2 screen_res;
 
-uniform sampler2D diffuseMap;
+out vec4 vary_fragcoord;
 
-vec3 atmosLighting(vec3 light);
-vec4 applyWaterFog(vec4 color);
+// forwards
+void setAtmosAttenuation(vec3 c);
+void setAdditiveColor(vec3 c);
 
-in vec4 vertex_color;
-in vec2 vary_texcoord0;
+uniform vec4 waterPlane;
 
-void default_lighting_water()
+uniform int above_water;
+
+uniform mat4 modelview_projection_matrix;
+
+void main()
 {
-	vec4 color = texture(diffuseMap,vary_texcoord0.xy);
+	//transform vertex
+	vec4 pos = vec4(position.xyz, 1.0);
 
-	if (color.a < minimum_alpha)
-	{
-		discard;
-	}
+    if (above_water > 0)
+    {
+        pos = modelview_projection_matrix*pos;
+    }
 
-	color.rgb *= vertex_color.rgb;
+    gl_Position = pos; 
 
-	color.rgb = atmosLighting(color.rgb);
+    // appease OSX GLSL compiler/linker by touching all the varyings we said we would
+    setAtmosAttenuation(vec3(1));
+    setAdditiveColor(vec3(0));
 
-	color = applyWaterFog(color);
-	
-	frag_color = max(color, vec4(0));
+	vary_fragcoord = pos;
 }
-
diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl
index e99ad5b474cee30b4f1e5e7da8570c1cf5db9460..ddb1b7968111df9fcd38ba274fda220363d981ad 100644
--- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl
@@ -55,7 +55,7 @@ in vec4 littleWave;
 in vec4 view;
 in vec3 vary_position;
 
-vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color, vec3 sunlit);
+vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color);
 
 void main() 
 {
@@ -77,5 +77,7 @@ void main()
     vec4 fb = vec4(waterFogColorLinear, 0.0);
 #endif
     
-	frag_color = max(applyWaterFogViewLinearNoClip(vary_position, fb, vec3(1)), vec4(0));
+    fb = applyWaterFogViewLinearNoClip(vary_position, fb);
+
+    frag_color = max(fb, vec4(0));
 }
diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
index ddade462bea1088be7c4feb9994564478255111e..f53bc2e13ec110b68ae66b692f92dee16d087a8d 100644
--- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
@@ -32,9 +32,8 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
 #endif
 
 vec3 scaleSoftClipFragLinear(vec3 l);
-vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten);
 void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
-vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
+vec4 applyWaterFogViewLinear(vec3 pos, vec4 color);
 
 // PBR interface
 vec2 BRDF(float NoV, float roughness);
@@ -223,9 +222,8 @@ void main()
         refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0));
     }
 
-    fb = applyWaterFogViewLinear(refPos, fb, sunlit);
 #else
-    vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0), sunlit_linear);
+    vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0));
 #endif
 
     // fudge sample on other side of water to be a tad darker
@@ -282,8 +280,6 @@ void main()
 
     color = ((1.0 - f) * color) + fb.rgb;
 
-    color = atmosFragLightingLinear(color, additive, atten);
-
     float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0.05);
     
     frag_color = max(vec4(color, spec), vec4(0));
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index fca0f1c978bd01d1e8ada273c94e453151ca2f81..50210b06c4e9fd290b8c1e2620b46eddd301946f 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -320,6 +320,14 @@ void LLFacePool::addFaceReference(LLFace *facep)
 	}
 }
 
+void LLFacePool::pushFaceGeometry()
+{
+    for (LLFace* const& face : mDrawFace)
+    {
+        face->renderIndexed();
+    }
+}
+
 BOOL LLFacePool::verify() const
 {
 	BOOL ok = TRUE;
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 5414dba6bf5a32318814b73a2197e5504ec2ebad..4300670445e63e7a87700bcca1deeb906b884bc4 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -118,8 +118,8 @@ class LLDrawPool
 	virtual LLViewerTexture* getTexture() = 0;
 	virtual BOOL isFacePool() { return FALSE; }
 	virtual void resetDrawOrders() = 0;
+    virtual void pushFaceGeometry() {}
 
-protected:
 	S32 mShaderLevel;
 	S32	mId;
 	U32 mType;				// Type of draw pool
@@ -429,6 +429,9 @@ class LLFacePool : public LLDrawPool
 	
 	BOOL isFacePool() { return TRUE; }
 
+    // call drawIndexed on every draw face
+    void pushFaceGeometry();
+
 	friend class LLFace;
 	friend class LLPipeline;
 public:
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 052a1d796ad7b57ccdb71bd26de540bb3e956e8a..41dc95a8cb241239b5005ef8d3eaf20c6c0e98a0 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -178,27 +178,24 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
 
     fullbright_shader   = 
         (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram :
-        (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterAlphaProgram : 
         (LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram :
         &gDeferredFullbrightAlphaMaskAlphaProgram;
     prepare_alpha_shader(fullbright_shader, true, true, water_sign);
 
     simple_shader   = 
         (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
-        (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : 
         (LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram :
         &gDeferredAlphaProgram;
 
     prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms)
 
-    LLGLSLShader* materialShader = LLPipeline::sUnderWaterRender ? gDeferredMaterialWaterProgram : gDeferredMaterialProgram;
+    LLGLSLShader* materialShader = gDeferredMaterialProgram;
     for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
     {
         prepare_alpha_shader(&materialShader[i], false, true, water_sign);
     }
 
     pbr_shader = 
-        (LLPipeline::sUnderWaterRender) ? &gDeferredPBRAlphaWaterProgram : 
         (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram : 
         &gDeferredPBRAlphaProgram;
 
@@ -727,11 +724,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
 
                         llassert(mask < LLMaterial::SHADER_COUNT);
                         target_shader = &(gDeferredMaterialProgram[mask]);
-
-                        if (LLPipeline::sUnderWaterRender)
-                        {
-                            target_shader = &(gDeferredMaterialWaterProgram[mask]);
-                        }
                     }
                     else if (!params.mFullbright)
                     {
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 342b76d93bb8bba1ff96716ca3bbb4cd10b429e4..7f6409dbde5a092da2a9b3b0d6bf3fc5c29a0041 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -509,14 +509,7 @@ void LLDrawPoolAvatar::beginRigid()
 
 	if (gPipeline.shadersLoaded())
 	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorProgram;
-		}
+		sVertexProgram = &gObjectAlphaMaskNoColorProgram;
 		
 		if (sVertexProgram != NULL)
 		{	//eyeballs render with the specular shader
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 6a7e05ac740f231d30e349c7da6c8955875acd9d..c0e4ed38c1cbb6a5ef94c97147caf3088c501125 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -82,14 +82,7 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 	
     U32 idx = shader_idx[pass];
     
-    if (LLPipeline::sUnderWaterRender)
-    {
-        mShader = &(gDeferredMaterialWaterProgram[idx]);
-    }
-    else
-    {
-        mShader = &(gDeferredMaterialProgram[idx]);
-    }
+    mShader = &(gDeferredMaterialProgram[idx]);
     
     if (rigged)
     {
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index a89c9d4561c8a52c01be061a9dc499a82d0166c9..696618f75bbb296b71c4a9a66256349856cb63ac 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -193,10 +193,6 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
     {
         shader = &gHUDFullbrightProgram;
     }
-    else if (LLPipeline::sUnderWaterRender)
-    {
-        shader = &gDeferredFullbrightWaterProgram;
-    }
     else
     {
         shader = &gDeferredFullbrightProgram;
@@ -225,10 +221,6 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
     {
         shader = &gHUDFullbrightAlphaMaskProgram;
     }
-    else if (LLPipeline::sUnderWaterRender)
-    {
-        shader = &gDeferredFullbrightAlphaMaskWaterProgram;
-    }
     else
     {
         shader = &gDeferredFullbrightAlphaMaskProgram;
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index 26782e53f0d0466424f2dbd4eb54dd31042d3557..6ffc8f7bddd14e3b5b22b4ca4be70b95fea51b90 100644
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -102,6 +102,7 @@ namespace Details
 
     void LLEventPollImpl::handleMessage(const LLSD& content)
     {
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
         std::string	msg_name = content["message"];
         LLSD message;
         message["sender"] = mSenderIp;
@@ -149,6 +150,14 @@ namespace Details
 
         mAdapter = httpAdapter;
 
+        LL::WorkQueue::ptr_t main_queue = nullptr;
+
+        // HACK -- grab the mainloop workqueue to move execution of the handler
+        // to a place that's safe in the main thread
+#if 1
+        main_queue = LL::WorkQueue::getInstance("mainloop");
+#endif
+
         // continually poll for a server update until we've been flagged as 
         // finished 
         while (!mDone)
@@ -266,13 +275,26 @@ namespace Details
             // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
             LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << acknowledge << ")" << LL_ENDL;
 
+
             LLSD::array_const_iterator i = events.beginArray();
             LLSD::array_const_iterator end = events.endArray();
             for (; i != end; ++i)
             {
                 if (i->has("message"))
                 {
-                    handleMessage(*i);
+                    if (main_queue)
+                    { // shuttle to a sensible spot in the main thread instead
+                        // of wherever this coroutine happens to be executing
+                        const LLSD& msg = *i;
+                        main_queue->post([this, msg]()
+                            { 
+                                handleMessage(msg); 
+                            });
+                    }
+                    else
+                    {
+                        handleMessage(*i);
+                    }
                 }
             }
         }
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 42587658a6d26da68f2a0480fd15d6e83acc2d3d..7009fb98ab6421e3503d646cedc84e50947fae5a 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -63,6 +63,7 @@
 #include <boost/algorithm/string/replace.hpp>
 #include "llinventoryobserver.h"
 #include "llinventorydefines.h"
+#include "llworld.h"
 
 #include "lltrans.h"
 
@@ -983,12 +984,21 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 
     LLEnvironment& env = LLEnvironment::instance();
 
-    auto group = LLGLSLShader::SG_WATER;
+    auto group = LLGLSLShader::SG_ANY;
     LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[group];
     
 	{
         F32 water_height = env.getWaterHeight();
 
+        if (LLViewerCamera::instance().cameraUnderWater())
+        { // when the camera is under water, use the water height at the camera position
+            LLViewerRegion* region = LLWorld::instance().getRegionFromPosAgent(LLViewerCamera::instance().getOrigin());
+            if (region)
+            {
+                water_height = region->getWaterHeight();
+            }
+        }
+
         //transform water plane to eye space
         glh::vec3f norm(0.f, 0.f, 1.f);
         glh::vec3f p(0.f, 0.f, water_height);
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index a63d46f502c2610167f7376a2367e46159fcb8de..9f30d60fedb8ead68d6741fd1b78ff1ef81a6fd7 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -64,6 +64,9 @@ bool LLSpatialGroup::sNoDelete = false;
 static F32 sLastMaxTexPriority = 1.f;
 static F32 sCurMaxTexPriority = 1.f;
 
+// enable expensive sanity checks around redundant drawable and group insertion to LLCullResult
+#define LL_DEBUG_CULL_RESULT 0
+
 //static counter for frame to switch LOD on
 
 void sg_assert(BOOL expr)
@@ -4015,6 +4018,10 @@ void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
 
 void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
 {
+#if LL_DEBUG_CULL_RESULT
+    // group must NOT be in the drawble groups list already
+    llassert(std::find(&mDrawableGroups[0], mDrawableGroupsEnd, group) == mDrawableGroupsEnd);
+#endif
 	if (mDrawableGroupsSize < mDrawableGroupsAllocated)
 	{
 		mDrawableGroups[mDrawableGroupsSize] = group;
@@ -4029,6 +4036,10 @@ void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
 
 void LLCullResult::pushDrawable(LLDrawable* drawable)
 {
+#if LL_DEBUG_CULL_RESULT
+    // drawable must NOT be in the visible list already
+    llassert(std::find(&mVisibleList[0], mVisibleListEnd, drawable) == mVisibleListEnd);
+#endif
 	if (mVisibleListSize < mVisibleListAllocated)
 	{
 		mVisibleList[mVisibleListSize] = drawable;
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index b37f08283de1851415c97722b4f49364f9cc1daa..4134e35f878a1df58b469e2e98238af9264e4947 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -50,6 +50,7 @@
 #include "llquaternion.h"
 #include "llwindow.h"			// getPixelAspectRatio()
 #include "lltracerecording.h"
+#include "llenvironment.h"
 
 // System includes
 #include <iomanip> // for setprecision
@@ -96,35 +97,41 @@ LLViewerCamera::LLViewerCamera() : LLCamera()
 	gSavedSettings.getControl("CameraAngle")->getCommitSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle, this, _2));
 }
 
-void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
-											const LLVector3 &up_direction,
-											const LLVector3 &point_of_interest)
+void LLViewerCamera::updateCameraLocation(const LLVector3 &center, const LLVector3 &up_direction, const LLVector3 &point_of_interest)
 {
-	// do not update if avatar didn't move
-	if (!LLViewerJoystick::getInstance()->getCameraNeedsUpdate())
-	{
-		return;
-	}
-
-	LLVector3 last_position;
-	LLVector3 last_axis;
-	last_position = getOrigin();
-	last_axis = getAtAxis();
-
-	mLastPointOfInterest = point_of_interest;
-
-	LLViewerRegion * regp = gAgent.getRegion();
-	F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f;
-
-	LLVector3 origin = center;
-	if (origin.mV[2] > water_height)
-	{
-		origin.mV[2] = llmax(origin.mV[2], water_height+0.20f);
-	}
-	else
-	{
-		origin.mV[2] = llmin(origin.mV[2], water_height-0.20f);
-	}
+    // do not update if avatar didn't move
+    if (!LLViewerJoystick::getInstance()->getCameraNeedsUpdate())
+    {
+        return;
+    }
+
+    LLVector3 last_position;
+    LLVector3 last_axis;
+    last_position = getOrigin();
+    last_axis     = getAtAxis();
+
+    mLastPointOfInterest = point_of_interest;
+
+    LLViewerRegion* regp = LLWorld::instance().getRegionFromPosAgent(getOrigin());
+    if (!regp)
+    {
+        regp = gAgent.getRegion();
+    }
+
+    F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f;
+
+    LLVector3 origin = center;
+
+    {
+        if (origin.mV[2] > water_height)
+        {
+            origin.mV[2] = llmax(origin.mV[2], water_height + 0.20f);
+        }
+        else
+        {
+            origin.mV[2] = llmin(origin.mV[2], water_height - 0.20f);
+        }
+    }
 
 	setOriginAndLookAt(origin, up_direction, point_of_interest);
 
@@ -755,11 +762,19 @@ LLVector3 LLViewerCamera::roundToPixel(const LLVector3 &pos_agent)
 
 BOOL LLViewerCamera::cameraUnderWater() const
 {
-	if(!gAgent.getRegion())
+    LLViewerRegion* regionp = LLWorld::instance().getRegionFromPosAgent(getOrigin());
+
+    if (!regionp)
+    {
+        regionp = gAgent.getRegion();
+    }
+
+	if(!regionp)
 	{
 		return FALSE ;
 	}
-	return getOrigin().mV[VZ] < gAgent.getRegion()->getWaterHeight();
+
+	return getOrigin().mV[VZ] < regionp->getWaterHeight();
 }
 
 BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index cdf5e2875ff94540ba6ecfe174a79931660b5720..3225299493046e282fcce764a027c3246ea5493e 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -99,7 +99,6 @@ LLGLSLShader        gSkinnedObjectFullbrightAlphaMaskProgram;
 LLGLSLShader		gObjectBumpProgram;
 LLGLSLShader        gSkinnedObjectBumpProgram;
 LLGLSLShader		gObjectAlphaMaskNoColorProgram;
-LLGLSLShader		gObjectAlphaMaskNoColorWaterProgram;
 
 //environment shaders
 LLGLSLShader		gWaterProgram;
@@ -138,7 +137,6 @@ LLGLSLShader			gDeferredSkinnedDiffuseProgram;
 LLGLSLShader			gDeferredSkinnedBumpProgram;
 LLGLSLShader			gDeferredBumpProgram;
 LLGLSLShader			gDeferredTerrainProgram;
-LLGLSLShader            gDeferredTerrainWaterProgram;
 LLGLSLShader			gDeferredTreeProgram;
 LLGLSLShader			gDeferredTreeShadowProgram;
 LLGLSLShader            gDeferredSkinnedTreeShadowProgram;
@@ -149,9 +147,10 @@ LLGLSLShader			gDeferredMultiLightProgram[16];
 LLGLSLShader			gDeferredSpotLightProgram;
 LLGLSLShader			gDeferredMultiSpotLightProgram;
 LLGLSLShader			gDeferredSunProgram;
+LLGLSLShader            gHazeProgram;
+LLGLSLShader            gHazeWaterProgram;
 LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
-LLGLSLShader			gDeferredSoftenWaterProgram;
 LLGLSLShader			gDeferredShadowProgram;
 LLGLSLShader            gDeferredSkinnedShadowProgram;
 LLGLSLShader			gDeferredShadowCubeProgram;
@@ -171,8 +170,6 @@ LLGLSLShader			gHUDAlphaProgram;
 LLGLSLShader            gDeferredSkinnedAlphaProgram;
 LLGLSLShader			gDeferredAlphaImpostorProgram;
 LLGLSLShader            gDeferredSkinnedAlphaImpostorProgram;
-LLGLSLShader			gDeferredAlphaWaterProgram;
-LLGLSLShader            gDeferredSkinnedAlphaWaterProgram;
 LLGLSLShader			gDeferredAvatarEyesProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
 LLGLSLShader            gHUDFullbrightProgram;
@@ -180,12 +177,6 @@ LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
 LLGLSLShader			gHUDFullbrightAlphaMaskProgram;
 LLGLSLShader			gDeferredFullbrightAlphaMaskAlphaProgram;
 LLGLSLShader			gHUDFullbrightAlphaMaskAlphaProgram;
-LLGLSLShader			gDeferredFullbrightWaterProgram;
-LLGLSLShader            gDeferredSkinnedFullbrightWaterProgram;
-LLGLSLShader			gDeferredFullbrightWaterAlphaProgram;
-LLGLSLShader			gDeferredSkinnedFullbrightWaterAlphaProgram;
-LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
-LLGLSLShader            gDeferredSkinnedFullbrightAlphaMaskWaterProgram;
 LLGLSLShader			gDeferredEmissiveProgram;
 LLGLSLShader            gDeferredSkinnedEmissiveProgram;
 LLGLSLShader			gDeferredPostProgram;
@@ -215,7 +206,6 @@ LLGLSLShader            gDeferredBufferVisualProgram;
 
 // Deferred materials shaders
 LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
-LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 LLGLSLShader			gHUDPBROpaqueProgram;
 LLGLSLShader            gPBRGlowProgram;
 LLGLSLShader            gPBRGlowSkinnedProgram;
@@ -224,8 +214,6 @@ 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)
@@ -258,30 +246,22 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gObjectFullbrightAlphaMaskProgram);
     mShaderList.push_back(&gSkinnedObjectFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNoColorProgram);
-	mShaderList.push_back(&gObjectAlphaMaskNoColorWaterProgram);
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
+    mShaderList.push_back(&gHazeProgram);
+    mShaderList.push_back(&gHazeWaterProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
-	mShaderList.push_back(&gDeferredSoftenWaterProgram);
 	mShaderList.push_back(&gDeferredAlphaProgram);
     mShaderList.push_back(&gHUDAlphaProgram);
     mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredAlphaImpostorProgram);
     mShaderList.push_back(&gDeferredSkinnedAlphaImpostorProgram);
-	mShaderList.push_back(&gDeferredAlphaWaterProgram);
-    mShaderList.push_back(&gDeferredSkinnedAlphaWaterProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
     mShaderList.push_back(&gHUDFullbrightProgram);
 	mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram);
     mShaderList.push_back(&gHUDFullbrightAlphaMaskProgram);
     mShaderList.push_back(&gDeferredFullbrightAlphaMaskAlphaProgram);
     mShaderList.push_back(&gHUDFullbrightAlphaMaskAlphaProgram);
-	mShaderList.push_back(&gDeferredFullbrightWaterProgram);
-    mShaderList.push_back(&gDeferredSkinnedFullbrightWaterProgram);
-    mShaderList.push_back(&gDeferredFullbrightWaterAlphaProgram);
-    mShaderList.push_back(&gDeferredSkinnedFullbrightWaterAlphaProgram);
-	mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram);
-    mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskWaterProgram);
 	mShaderList.push_back(&gDeferredFullbrightShinyProgram);
     mShaderList.push_back(&gHUDFullbrightShinyProgram);
     mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
@@ -291,17 +271,14 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredEmissiveProgram);
     mShaderList.push_back(&gDeferredSkinnedEmissiveProgram);
 	mShaderList.push_back(&gDeferredAvatarEyesProgram);
-    mShaderList.push_back(&gDeferredTerrainWaterProgram);
-	mShaderList.push_back(&gDeferredAvatarAlphaProgram);
+    mShaderList.push_back(&gDeferredAvatarAlphaProgram);
 	mShaderList.push_back(&gDeferredWLSkyProgram);
 	mShaderList.push_back(&gDeferredWLCloudProgram);
     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);
@@ -594,7 +571,6 @@ std::string LLViewerShaderMgr::loadBasicShaders()
 
 	vector< pair<string, S32> > shaders;
 	shaders.push_back( make_pair( "windlight/atmosphericsVarsV.glsl",       mShaderLevel[SHADER_WINDLIGHT] ) );
-	shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterV.glsl",  mShaderLevel[SHADER_WINDLIGHT] ) );
 	shaders.push_back( make_pair( "windlight/atmosphericsHelpersV.glsl",    mShaderLevel[SHADER_WINDLIGHT] ) );
 	shaders.push_back( make_pair( "lighting/lightFuncV.glsl",               mShaderLevel[SHADER_LIGHTING] ) );
 	shaders.push_back( make_pair( "lighting/sumLightsV.glsl",               sum_lights_class ) );
@@ -674,7 +650,6 @@ std::string LLViewerShaderMgr::loadBasicShaders()
 
 	std::vector<S32> index_channels;    
 	index_channels.push_back(-1);    shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl",      mShaderLevel[SHADER_WINDLIGHT] ) );
-	index_channels.push_back(-1);    shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterF.glsl",     mShaderLevel[SHADER_WINDLIGHT] ) );
 	index_channels.push_back(-1);    shaders.push_back( make_pair( "windlight/atmosphericsHelpersF.glsl",       mShaderLevel[SHADER_WINDLIGHT] ) );
 	index_channels.push_back(-1);    shaders.push_back( make_pair( "windlight/gammaF.glsl",                 mShaderLevel[SHADER_WINDLIGHT]) );
     index_channels.push_back(-1);    shaders.push_back( make_pair( "windlight/atmosphericsFuncs.glsl",       mShaderLevel[SHADER_WINDLIGHT] ) );
@@ -689,12 +664,8 @@ std::string LLViewerShaderMgr::loadBasicShaders()
     index_channels.push_back(-1);    shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl",             ssr ? 3 : 1) );
 	index_channels.push_back(-1);    shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl",                    mShaderLevel[SHADER_LIGHTING] ) );
 	index_channels.push_back(-1);    shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl",                   mShaderLevel[SHADER_LIGHTING] ) );
-	index_channels.push_back(-1);    shaders.push_back( make_pair( "lighting/lightWaterNonIndexedF.glsl",               mShaderLevel[SHADER_LIGHTING] ) );
-	index_channels.push_back(-1);    shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskNonIndexedF.glsl",              mShaderLevel[SHADER_LIGHTING] ) );
 	index_channels.push_back(ch);    shaders.push_back( make_pair( "lighting/lightF.glsl",                  mShaderLevel[SHADER_LIGHTING] ) );
 	index_channels.push_back(ch);    shaders.push_back( make_pair( "lighting/lightAlphaMaskF.glsl",                 mShaderLevel[SHADER_LIGHTING] ) );
-	index_channels.push_back(ch);    shaders.push_back( make_pair( "lighting/lightWaterF.glsl",             mShaderLevel[SHADER_LIGHTING] ) );
-	index_channels.push_back(ch);    shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskF.glsl",    mShaderLevel[SHADER_LIGHTING] ) );
 	
 	for (U32 i = 0; i < shaders.size(); i++)
 	{
@@ -732,7 +703,6 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 		gWaterProgram.mName = "Water Shader";
 		gWaterProgram.mFeatures.calculatesAtmospherics = true;
         gWaterProgram.mFeatures.hasAtmospherics = true;
-        gWaterProgram.mFeatures.hasWaterFog = true;
 		gWaterProgram.mFeatures.hasGamma = true;
 		gWaterProgram.mFeatures.hasSrgb = true;
         gWaterProgram.mFeatures.hasReflectionProbes = true;
@@ -763,7 +733,6 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 		gWaterEdgeProgram.mName = "Water Edge Shader";
 		gWaterEdgeProgram.mFeatures.calculatesAtmospherics = true;
         gWaterEdgeProgram.mFeatures.hasAtmospherics = true;
-        gWaterEdgeProgram.mFeatures.hasWaterFog = true;
 		gWaterEdgeProgram.mFeatures.hasGamma = true;
 		gWaterEdgeProgram.mFeatures.hasSrgb = true;
         gWaterEdgeProgram.mFeatures.hasReflectionProbes = true;
@@ -793,7 +762,7 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 		//load under water vertex shader
 		gUnderWaterProgram.mName = "Underwater Shader";
 		gUnderWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gUnderWaterProgram.mFeatures.hasWaterFog = true;
+		gUnderWaterProgram.mFeatures.hasAtmospherics = true;
 		gUnderWaterProgram.mShaderFiles.clear();
 		gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER));
 		gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/underWaterF.glsl", GL_FRAGMENT_SHADER));
@@ -908,7 +877,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         gDeferredSkinnedBumpProgram.unload();
 		gDeferredImpostorProgram.unload();
 		gDeferredTerrainProgram.unload();
-		gDeferredTerrainWaterProgram.unload();
 		gDeferredLightProgram.unload();
 		for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; ++i)
 		{
@@ -919,7 +887,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSunProgram.unload();
 		gDeferredBlurLightProgram.unload();
 		gDeferredSoftenProgram.unload();
-		gDeferredSoftenWaterProgram.unload();
 		gDeferredShadowProgram.unload();
         gDeferredSkinnedShadowProgram.unload();
 		gDeferredShadowCubeProgram.unload();
@@ -937,20 +904,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAlphaProgram.unload();
         gHUDAlphaProgram.unload();
         gDeferredSkinnedAlphaProgram.unload();
-		gDeferredAlphaWaterProgram.unload();
-        gDeferredSkinnedAlphaWaterProgram.unload();
 		gDeferredFullbrightProgram.unload();
         gHUDFullbrightProgram.unload();
 		gDeferredFullbrightAlphaMaskProgram.unload();
         gHUDFullbrightAlphaMaskProgram.unload();
         gDeferredFullbrightAlphaMaskAlphaProgram.unload();
         gHUDFullbrightAlphaMaskAlphaProgram.unload();
-		gDeferredFullbrightWaterProgram.unload();
-        gDeferredSkinnedFullbrightWaterProgram.unload();
-        gDeferredFullbrightWaterAlphaProgram.unload();
-        gDeferredSkinnedFullbrightWaterAlphaProgram.unload();
-		gDeferredFullbrightAlphaMaskWaterProgram.unload();
-        gDeferredSkinnedFullbrightAlphaMaskWaterProgram.unload();
 		gDeferredEmissiveProgram.unload();
         gDeferredSkinnedEmissiveProgram.unload();
 		gDeferredAvatarEyesProgram.unload();
@@ -984,7 +943,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 		{
 			gDeferredMaterialProgram[i].unload();
-			gDeferredMaterialWaterProgram[i].unload();
 		}
 
         gHUDPBROpaqueProgram.unload();
@@ -993,8 +951,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         gDeferredSkinnedPBROpaqueProgram.unload();
         gDeferredPBRAlphaProgram.unload();
         gDeferredSkinnedPBRAlphaProgram.unload();
-        gDeferredPBRAlphaWaterProgram.unload();
-        gDeferredSkinnedPBRAlphaWaterProgram.unload();
 
 		return TRUE;
 	}
@@ -1084,15 +1040,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 
-	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = false;
-	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = false;
-	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = false;
-	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = false;
-	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
-	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
-	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
-	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
-
 	for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 	{
 		if (success)
@@ -1158,77 +1105,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
             success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
             llassert(success);
 		}
-
-		if (success)
-		{
-            mShaderList.push_back(&gDeferredMaterialWaterProgram[i]);
-
-            gDeferredMaterialWaterProgram[i].mName = llformat("Deferred Underwater Material Shader %d", i);
-
-            U32 alpha_mode = i & 0x3;
-
-            gDeferredMaterialWaterProgram[i].mShaderFiles.clear();
-            gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER));
-            gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER));
-            gDeferredMaterialWaterProgram[i].mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-            gDeferredMaterialWaterProgram[i].mShaderGroup = LLGLSLShader::SG_WATER;
-
-            gDeferredMaterialWaterProgram[i].clearPermutations();
-
-            bool has_normal_map   = (i & 0x8) > 0;
-            bool has_specular_map = (i & 0x4) > 0;
-
-            if (has_normal_map)
-            {
-                gDeferredMaterialWaterProgram[i].addPermutation("HAS_NORMAL_MAP", "1");
-            }
-
-            if (has_specular_map)
-            {
-                gDeferredMaterialWaterProgram[i].addPermutation("HAS_SPECULAR_MAP", "1");
-            }
-
-            gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
-            if (alpha_mode != 0)
-            {
-                gDeferredMaterialWaterProgram[i].mFeatures.hasAlphaMask = true;
-                gDeferredMaterialWaterProgram[i].addPermutation("HAS_ALPHA_MASK", "1");
-            }
-
-            if (use_sun_shadow)
-            {
-                gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", "1");
-            }
-
-            bool has_skin = i & 0x10;
-            if (has_skin)
-            {
-                gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN", "1");
-            }
-            else
-            {
-                gDeferredMaterialWaterProgram[i].mRiggedVariant = &(gDeferredMaterialWaterProgram[i + 0x10]);
-            }
-            gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1");
-
-            gDeferredMaterialWaterProgram[i].mFeatures.hasReflectionProbes = true;
-            gDeferredMaterialWaterProgram[i].mFeatures.hasWaterFog = true;
-            gDeferredMaterialWaterProgram[i].mFeatures.hasSrgb = true;
-            gDeferredMaterialWaterProgram[i].mFeatures.encodesNormal = true;
-            gDeferredMaterialWaterProgram[i].mFeatures.calculatesAtmospherics = true;
-            gDeferredMaterialWaterProgram[i].mFeatures.hasAtmospherics = true;
-            gDeferredMaterialWaterProgram[i].mFeatures.hasGamma = true;
-
-            gDeferredMaterialWaterProgram[i].mFeatures.hasShadows = use_sun_shadow;
-            
-            if (has_skin)
-            {
-                gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true;
-            }
-
-            success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);//&mWLUniforms);
-            llassert(success);
-		}
 	}
 
 	gDeferredMaterialProgram[1].mFeatures.hasLighting = true;
@@ -1240,15 +1116,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 
-	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = true;
-	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = true;
-	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = true;
-	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = true;
-	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
-	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
-	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
-	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
-
     if (success)
     {
         gDeferredPBROpaqueProgram.mName = "Deferred PBR Opaque Shader";
@@ -1356,62 +1223,6 @@ 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;
@@ -1640,7 +1451,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
             shader->mFeatures.hasGamma = true;
             shader->mFeatures.hasShadows = use_sun_shadow;
             shader->mFeatures.hasReflectionProbes = true;
-            shader->mFeatures.hasWaterFog = true;
             shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
 
             shader->mShaderFiles.clear();
@@ -1737,68 +1547,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         }
     }
 
-    if (success)
-    {
-        LLGLSLShader* shader[] = {
-            &gDeferredAlphaWaterProgram,
-            &gDeferredSkinnedAlphaWaterProgram
-        };
-        
-        gDeferredAlphaWaterProgram.mRiggedVariant = &gDeferredSkinnedAlphaWaterProgram;
-		
-        gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader";
-        gDeferredSkinnedAlphaWaterProgram.mName = "Deferred Skinned Alpha Underwater Shader";
-
-        for (int i = 0; i < 2 && success; ++i)
-        {
-            shader[i]->mFeatures.calculatesLighting = false;
-            shader[i]->mFeatures.hasLighting = false;
-            shader[i]->mFeatures.isAlphaLighting = true;
-            shader[i]->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
-            shader[i]->mFeatures.hasWaterFog = true;
-            shader[i]->mFeatures.hasSrgb = true;
-            shader[i]->mFeatures.encodesNormal = true;
-            shader[i]->mFeatures.calculatesAtmospherics = true;
-            shader[i]->mFeatures.hasAtmospherics = true;
-            shader[i]->mFeatures.hasGamma = true;
-            shader[i]->mFeatures.hasShadows = use_sun_shadow;
-            shader[i]->mFeatures.hasReflectionProbes = true;
-            shader[i]->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-            shader[i]->mShaderGroup = LLGLSLShader::SG_WATER;
-            shader[i]->mShaderFiles.clear();
-            shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER));
-            shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER));
-
-            shader[i]->clearPermutations();
-            shader[i]->addPermutation("USE_INDEXED_TEX", "1");
-            shader[i]->addPermutation("WATER_FOG", "1");
-            shader[i]->addPermutation("USE_VERTEX_COLOR", "1");
-            shader[i]->addPermutation("HAS_ALPHA_MASK", "1");
-            if (use_sun_shadow)
-            {
-                shader[i]->addPermutation("HAS_SUN_SHADOW", "1");
-            }
-
-            if (i == 1)
-            { // rigged variant
-                shader[i]->mFeatures.hasObjectSkinning = true;
-                shader[i]->addPermutation("HAS_SKIN", "1");
-            }
-            else
-            {
-                shader[i]->mRiggedVariant = shader[1];
-            }
-            shader[i]->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-
-            success = shader[i]->createShader(NULL, NULL);
-            llassert(success);
-
-            // Hack
-            shader[i]->mFeatures.calculatesLighting = true;
-            shader[i]->mFeatures.hasLighting = true;
-        }
-	}
-
 	if (success)
 	{
 		gDeferredAvatarEyesProgram.mName = "Deferred Avatar Eyes Shader";
@@ -1933,71 +1681,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         llassert(success);
     }
 
-	if (success)
-	{
-		gDeferredFullbrightWaterProgram.mName = "Deferred Fullbright Underwater Shader";
-		gDeferredFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredFullbrightWaterProgram.mFeatures.hasGamma = true;
-		gDeferredFullbrightWaterProgram.mFeatures.hasAtmospherics = true;
-		gDeferredFullbrightWaterProgram.mFeatures.hasWaterFog = true;
-		gDeferredFullbrightWaterProgram.mFeatures.hasSrgb = true;
-		gDeferredFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-		gDeferredFullbrightWaterProgram.mShaderFiles.clear();
-		gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER));
-		gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER));
-		gDeferredFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1");
-        success = make_rigged_variant(gDeferredFullbrightWaterProgram, gDeferredSkinnedFullbrightWaterProgram);
-		success = success && gDeferredFullbrightWaterProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-    
-    if (success)
-    {
-        gDeferredFullbrightWaterAlphaProgram.mName = "Deferred Fullbright Underwater Alpha Shader";
-        gDeferredFullbrightWaterAlphaProgram.mFeatures.calculatesAtmospherics = true;
-        gDeferredFullbrightWaterAlphaProgram.mFeatures.hasGamma = true;
-        gDeferredFullbrightWaterAlphaProgram.mFeatures.hasAtmospherics = true;
-        gDeferredFullbrightWaterAlphaProgram.mFeatures.hasWaterFog = true;
-        gDeferredFullbrightWaterAlphaProgram.mFeatures.hasSrgb = true;
-        gDeferredFullbrightWaterAlphaProgram.mFeatures.isDeferred = true;
-        gDeferredFullbrightWaterAlphaProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-        gDeferredFullbrightWaterAlphaProgram.mShaderFiles.clear();
-        gDeferredFullbrightWaterAlphaProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER));
-        gDeferredFullbrightWaterAlphaProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER));
-        gDeferredFullbrightWaterAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-        gDeferredFullbrightWaterAlphaProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-        gDeferredFullbrightWaterAlphaProgram.clearPermutations();
-        gDeferredFullbrightWaterAlphaProgram.addPermutation("WATER_FOG", "1");
-        gDeferredFullbrightWaterAlphaProgram.addPermutation("IS_ALPHA", "1");
-        success = make_rigged_variant(gDeferredFullbrightWaterAlphaProgram, gDeferredSkinnedFullbrightWaterAlphaProgram);
-        success = success && gDeferredFullbrightWaterAlphaProgram.createShader(NULL, NULL);
-        llassert(success);
-    }
-
-	if (success)
-	{
-		gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader";
-		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasGamma = true;
-		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasAtmospherics = true;
-		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasWaterFog = true;
-		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasSrgb = true;
-		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
-		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.clear();
-		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER));
-		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER));
-		gDeferredFullbrightAlphaMaskWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		gDeferredFullbrightAlphaMaskWaterProgram.clearPermutations();
-		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1");
-		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1");
-        success = make_rigged_variant(gDeferredFullbrightAlphaMaskWaterProgram, gDeferredSkinnedFullbrightAlphaMaskWaterProgram);
-		success = success && gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
-
 	if (success)
 	{
 		gDeferredFullbrightShinyProgram.mName = "Deferred FullbrightShiny Shader";
@@ -2084,40 +1767,52 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		llassert(success);
 	}
 
-	if (success)
-	{
-		gDeferredSoftenWaterProgram.mName = "Deferred Soften Underwater Shader";
-		gDeferredSoftenWaterProgram.mShaderFiles.clear();
-		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER));
-		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER));
-
-        gDeferredSoftenWaterProgram.clearPermutations();
-		gDeferredSoftenWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		gDeferredSoftenWaterProgram.addPermutation("WATER_FOG", "1");
-		gDeferredSoftenWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		gDeferredSoftenWaterProgram.mFeatures.hasWaterFog = true;
-		gDeferredSoftenWaterProgram.mFeatures.hasSrgb = true;
-		gDeferredSoftenWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredSoftenWaterProgram.mFeatures.hasAtmospherics = true;
-		gDeferredSoftenWaterProgram.mFeatures.hasGamma = true;
-        gDeferredSoftenWaterProgram.mFeatures.isDeferred = true;
-        gDeferredSoftenWaterProgram.mFeatures.hasShadows = use_sun_shadow;
-        gDeferredSoftenWaterProgram.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED] > 2;
+    if (success)
+    {
+        gHazeProgram.mName = "Haze Shader";
+        gHazeProgram.mShaderFiles.clear();
+        gHazeProgram.mFeatures.hasSrgb                = true;
+        gHazeProgram.mFeatures.calculatesAtmospherics = true;
+        gHazeProgram.mFeatures.hasAtmospherics        = true;
+        gHazeProgram.mFeatures.hasGamma               = true;
+        gHazeProgram.mFeatures.isDeferred             = true;
+        gHazeProgram.mFeatures.hasShadows             = use_sun_shadow;
+        gHazeProgram.mFeatures.hasReflectionProbes    = mShaderLevel[SHADER_DEFERRED] > 2;
+
+        gHazeProgram.clearPermutations();
+        gHazeProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER));
+        gHazeProgram.mShaderFiles.push_back(make_pair("deferred/hazeF.glsl", GL_FRAGMENT_SHADER));
+
+        gHazeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+
+        success = gHazeProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
 
-        if (use_sun_shadow)
-        {
-            gDeferredSoftenWaterProgram.addPermutation("HAS_SUN_SHADOW", "1");
-        }
 
-		if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
-		{ //if using SSAO, take screen space light map into account as if shadows are enabled
-			gDeferredSoftenWaterProgram.mShaderLevel = llmax(gDeferredSoftenWaterProgram.mShaderLevel, 2);
-            gDeferredSoftenWaterProgram.addPermutation("HAS_SSAO", "1");
-		}
+    if (success)
+    {
+        gHazeWaterProgram.mName = "Water Haze Shader";
+        gHazeWaterProgram.mShaderFiles.clear();
+        gHazeWaterProgram.mShaderGroup           = LLGLSLShader::SG_WATER;
+        gHazeWaterProgram.mFeatures.hasSrgb                = true;
+        gHazeWaterProgram.mFeatures.calculatesAtmospherics = true;
+        gHazeWaterProgram.mFeatures.hasAtmospherics        = true;
+        gHazeWaterProgram.mFeatures.hasGamma               = true;
+        gHazeWaterProgram.mFeatures.isDeferred             = true;
+        gHazeWaterProgram.mFeatures.hasShadows             = use_sun_shadow;
+        gHazeWaterProgram.mFeatures.hasReflectionProbes    = mShaderLevel[SHADER_DEFERRED] > 2;
+
+        gHazeWaterProgram.clearPermutations();
+        gHazeWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterHazeV.glsl", GL_VERTEX_SHADER));
+        gHazeWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterHazeF.glsl", GL_FRAGMENT_SHADER));
+
+        gHazeWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+
+        success = gHazeWaterProgram.createShader(NULL, NULL);
+        llassert(success);
+    }
 
-		success = gDeferredSoftenWaterProgram.createShader(NULL, NULL);
-		llassert(success);
-	}
 
 	if (success)
 	{
@@ -2264,7 +1959,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredTerrainProgram.mFeatures.hasLighting = false;
 		gDeferredTerrainProgram.mFeatures.isAlphaLighting = true;
 		gDeferredTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
-		gDeferredTerrainProgram.mFeatures.hasWaterFog = true;
 		gDeferredTerrainProgram.mFeatures.calculatesAtmospherics = true;
 		gDeferredTerrainProgram.mFeatures.hasAtmospherics = true;
 		gDeferredTerrainProgram.mFeatures.hasGamma = true;
@@ -2277,31 +1971,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		llassert(success);
 	}
 
-	if (success)
-	{
-		gDeferredTerrainWaterProgram.mName = "Deferred Terrain Underwater Shader";
-		gDeferredTerrainWaterProgram.mFeatures.encodesNormal = true;
-		gDeferredTerrainWaterProgram.mFeatures.hasSrgb = true;
-		gDeferredTerrainWaterProgram.mFeatures.calculatesLighting = false;
-		gDeferredTerrainWaterProgram.mFeatures.hasLighting = false;
-		gDeferredTerrainWaterProgram.mFeatures.isAlphaLighting = true;
-		gDeferredTerrainWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
-		gDeferredTerrainWaterProgram.mFeatures.hasWaterFog = true;
-		gDeferredTerrainWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredTerrainWaterProgram.mFeatures.hasAtmospherics = true;
-		gDeferredTerrainWaterProgram.mFeatures.hasGamma = true;
-		
-		gDeferredTerrainWaterProgram.mShaderFiles.clear();
-		gDeferredTerrainWaterProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER));
-		gDeferredTerrainWaterProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER));
-		gDeferredTerrainWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		gDeferredTerrainWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		gDeferredTerrainWaterProgram.clearPermutations();
-		gDeferredTerrainWaterProgram.addPermutation("WATER_FOG", "1");
-		success = gDeferredTerrainWaterProgram.createShader(NULL, NULL);
-        llassert(success);
-	}
-
 	if (success)
 	{
 		gDeferredAvatarProgram.mName = "Deferred Avatar Shader";
@@ -2660,24 +2329,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectAlphaMaskNoColorProgram.createShader(NULL, NULL);
 	}
 	
-	if (success)
-	{
-		gObjectAlphaMaskNoColorWaterProgram.mName = "No color alpha mask Water Shader";
-		gObjectAlphaMaskNoColorWaterProgram.mFeatures.calculatesLighting = true;
-		gObjectAlphaMaskNoColorWaterProgram.mFeatures.calculatesAtmospherics = true;
-		gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasWaterFog = true;
-		gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasAtmospherics = true;
-		gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasLighting = true;
-		gObjectAlphaMaskNoColorWaterProgram.mFeatures.disableTextureIndex = true;
-		gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasAlphaMask = true;
-		gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.clear();
-		gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleNoColorV.glsl", GL_VERTEX_SHADER));
-		gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER));
-		gObjectAlphaMaskNoColorWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
-		gObjectAlphaMaskNoColorWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectAlphaMaskNoColorWaterProgram.createShader(NULL, NULL);
-	}
-
 	if (success)
 	{
 		gImpostorProgram.mName = "Impostor Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index b0b9719d76fcc4cdb3c966c4f7025c4a35dd9ffe..04da7e48ae658a0eb620715c0b06b923f41496ce 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -175,7 +175,6 @@ extern LLGLSLShader        gSkinnedObjectFullbrightAlphaMaskProgram;
 extern LLGLSLShader		gObjectBumpProgram;
 extern LLGLSLShader        gSkinnedObjectBumpProgram;
 extern LLGLSLShader		gObjectAlphaMaskNoColorProgram;
-extern LLGLSLShader		gObjectAlphaMaskNoColorWaterProgram;
 
 //environment shaders
 extern LLGLSLShader			gWaterProgram;
@@ -211,7 +210,6 @@ extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
 extern LLGLSLShader			gDeferredBumpProgram;
 extern LLGLSLShader			gDeferredTerrainProgram;
-extern LLGLSLShader			gDeferredTerrainWaterProgram;
 extern LLGLSLShader			gDeferredTreeProgram;
 extern LLGLSLShader			gDeferredTreeShadowProgram;
 extern LLGLSLShader			gDeferredLightProgram;
@@ -219,10 +217,11 @@ extern LLGLSLShader			gDeferredMultiLightProgram[LL_DEFERRED_MULTI_LIGHT_COUNT];
 extern LLGLSLShader			gDeferredSpotLightProgram;
 extern LLGLSLShader			gDeferredMultiSpotLightProgram;
 extern LLGLSLShader			gDeferredSunProgram;
+extern LLGLSLShader         gHazeProgram;
+extern LLGLSLShader         gHazeWaterProgram;
 extern LLGLSLShader			gDeferredBlurLightProgram;
 extern LLGLSLShader			gDeferredAvatarProgram;
 extern LLGLSLShader			gDeferredSoftenProgram;
-extern LLGLSLShader			gDeferredSoftenWaterProgram;
 extern LLGLSLShader			gDeferredShadowProgram;
 extern LLGLSLShader			gDeferredShadowCubeProgram;
 extern LLGLSLShader			gDeferredShadowAlphaMaskProgram;
@@ -251,10 +250,6 @@ extern LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
 extern LLGLSLShader			gHUDFullbrightAlphaMaskProgram;
 extern LLGLSLShader			gDeferredFullbrightAlphaMaskAlphaProgram;
 extern LLGLSLShader			gHUDFullbrightAlphaMaskAlphaProgram;
-extern LLGLSLShader			gDeferredAlphaWaterProgram;
-extern LLGLSLShader			gDeferredFullbrightWaterProgram;
-extern LLGLSLShader			gDeferredFullbrightWaterAlphaProgram;
-extern LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
 extern LLGLSLShader			gDeferredEmissiveProgram;
 extern LLGLSLShader			gDeferredAvatarEyesProgram;
 extern LLGLSLShader			gDeferredAvatarAlphaProgram;
@@ -271,12 +266,10 @@ extern LLGLSLShader			gDeferredBufferVisualProgram;
 
 // Deferred materials shaders
 extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
-extern LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
 extern LLGLSLShader         gHUDPBROpaqueProgram;
 extern LLGLSLShader         gPBRGlowProgram;
 extern LLGLSLShader         gDeferredPBROpaqueProgram;
 extern LLGLSLShader         gDeferredPBRAlphaProgram;
-extern LLGLSLShader         gDeferredPBRAlphaWaterProgram;
 extern LLGLSLShader         gHUDPBRAlphaProgram;
 #endif
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 709a457862f447a5accd4b4ad594fcf96b71e888..9381211e9b77dc8ddd181d9179e6bad0b2410a57 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -883,58 +883,6 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh
 	}
 }
 
-void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water)
-{
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
-	if (!gAgent.getRegion())
-	{
-		return;
-	}
-
-	if (mRegionList.empty())
-	{
-		LL_WARNS() << "No regions!" << LL_ENDL;
-		return;
-	}
-
-	for (region_list_t::iterator iter = mRegionList.begin();
-		 iter != mRegionList.end(); ++iter)
-	{
-		LLViewerRegion* regionp = *iter;
-		LLVOWater* waterp = regionp->getLand().getWaterObj();
-		if (waterp && waterp->mDrawable)
-		{
-			waterp->mDrawable->setVisible(camera);
-		    cull->pushDrawable(waterp->mDrawable);
-		}
-	}
-
-    if (include_void_water)
-    {
-		for (std::list<LLPointer<LLVOWater> >::iterator iter = mHoleWaterObjects.begin();
-			 iter != mHoleWaterObjects.end(); ++ iter)
-		{
-			LLVOWater* waterp = (*iter).get();
-		    if (waterp && waterp->mDrawable)
-            {
-                waterp->mDrawable->setVisible(camera);
-		        cull->pushDrawable(waterp->mDrawable);
-            }
-	    }
-    }
-
-	S32 dir;
-	for (dir = 0; dir < EDGE_WATER_OBJECTS_COUNT; dir++)
-	{
-		LLVOWater* waterp = mEdgeWaterObjects[dir];
-		if (waterp && waterp->mDrawable)
-		{
-            waterp->mDrawable->setVisible(camera);
-		    cull->pushDrawable(waterp->mDrawable);
-		}
-	}
-}
-
 void LLWorld::clearHoleWaterObjects()
 {
     for (std::list<LLPointer<LLVOWater> >::iterator iter = mHoleWaterObjects.begin();
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index f78cbcaa4852e4390597d4e2ccf794bf34edc033..2878d10f5eede3a466f6dbf014fa87000c10e15b 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -140,8 +140,6 @@ class LLWorld : public LLSimpleton<LLWorld>
 	LLViewerTexture *getDefaultWaterTexture();
     void updateWaterObjects();
 
-    void precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water);
-
 	void waterHeightRegionInfo(std::string const& sim_name, F32 water_height);
 	void shiftRegions(const LLVector3& offset);
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 64d247a202768ed07ad285afad62b2639da77b15..50cd4adb7349d6261b32f7a5dd71c7d1b52e312f 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2311,13 +2311,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result)
         gSky.mVOWLSkyp->mDrawable->setVisible(camera);
         sCull->pushDrawable(gSky.mVOWLSkyp->mDrawable);
     }
-
-    bool render_water = !sReflectionRender && (hasRenderType(LLPipeline::RENDER_TYPE_WATER) || hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER));
-
-    if (render_water)
-    {
-        LLWorld::getInstance()->precullWaterObjects(camera, sCull, render_water);
-    }
 }
 
 void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
@@ -3878,6 +3871,20 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 
 	LLGLEnable cull(GL_CULL_FACE);
 
+    bool done_atmospherics = LLPipeline::sRenderingHUDs; //skip atmospherics on huds
+    bool done_water_haze = done_atmospherics;
+
+    // do atmospheric haze just before post water alpha
+    U32 atmospherics_pass = LLDrawPool::POOL_ALPHA_POST_WATER;
+
+    if (LLPipeline::sUnderWaterRender)
+    { // if under water, do atmospherics just before the water pass
+        atmospherics_pass = LLDrawPool::POOL_WATER;
+    }
+
+    // do water haze just before pre water alpha
+    U32 water_haze_pass = LLDrawPool::POOL_ALPHA_PRE_WATER;
+
 	calcNearbyLights(camera);
 	setupHWLights();
 
@@ -3897,6 +3904,18 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 		
 		cur_type = poolp->getType();
 
+        if (cur_type >= atmospherics_pass && !done_atmospherics)
+        { // do atmospherics against depth buffer before rendering alpha
+            doAtmospherics();
+            done_atmospherics = true;
+        }
+
+        if (cur_type >= water_haze_pass && !done_water_haze)
+        { // do water haze against depth buffer before rendering alpha
+            doWaterHaze();
+            done_water_haze = true;
+        }
+
 		pool_set_t::iterator iter2 = iter1;
 		if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
 		{
@@ -7877,7 +7896,7 @@ void LLPipeline::renderDeferredLighting()
 
         if (RenderDeferredAtmospheric)
         {  // apply sunlight contribution
-            LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram;
+            LLGLSLShader &soften_shader = gDeferredSoftenProgram;
 
             LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics");
             LL_PROFILE_GPU_ZONE("atmospherics");
@@ -7906,7 +7925,7 @@ void LLPipeline::renderDeferredLighting()
                 mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
             }
 
-            unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);
+            unbindDeferredShader(gDeferredSoftenProgram);
         }
 
         static LLCachedControl<S32> local_light_count(gSavedSettings, "RenderLocalLightCount", 256);
@@ -8058,7 +8077,7 @@ void LLPipeline::renderDeferredLighting()
 
                     LLVector4a center;
                     center.load3(drawablep->getPositionAgent().mV);
-                    const F32 *c = center.getF32ptr();
+                    const F32* c = center.getF32ptr();
                     F32        s = volume->getLightRadius() * 1.5f;
 
                     sVisibleLightCount++;
@@ -8107,8 +8126,8 @@ void LLPipeline::renderDeferredLighting()
                         U32 idx = count - 1;
                         bindDeferredShader(gDeferredMultiLightProgram[idx]);
                         gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
-                        gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat *) light);
-                        gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat *) col);
+                        gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*)light);
+                        gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*)col);
                         gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
                         far_z = 0.f;
                         count = 0;
@@ -8126,11 +8145,11 @@ void LLPipeline::renderDeferredLighting()
 
                 for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
                 {
-                    LLDrawable *drawablep           = *iter;
-                    LLVOVolume *volume              = drawablep->getVOVolume();
-                    LLVector3   center              = drawablep->getPositionAgent();
-                    F32 *       c                   = center.mV;
-                    F32         light_size_final    = volume->getLightRadius() * 1.5f;
+                    LLDrawable* drawablep = *iter;
+                    LLVOVolume* volume = drawablep->getVOVolume();
+                    LLVector3   center = drawablep->getPositionAgent();
+                    F32* c = center.mV;
+                    F32         light_size_final = volume->getLightRadius() * 1.5f;
                     F32         light_falloff_final = volume->getLightFalloff(DEFERRED_LIGHT_FALLOFF);
 
                     sVisibleLightCount++;
@@ -8155,13 +8174,11 @@ void LLPipeline::renderDeferredLighting()
             }
         }
 
-
         gGL.setColorMask(true, true);
     }
 
     {  // render non-deferred geometry (alpha, fullbright, glow)
         LLGLDisable blend(GL_BLEND);
-        //LLGLDisable stencil(GL_STENCIL_TEST);
 
         pushRenderTypeMask();
         andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
@@ -8212,6 +8229,90 @@ void LLPipeline::renderDeferredLighting()
     gGL.setColorMask(true, true);
 }
 
+void LLPipeline::doAtmospherics()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+
+    if (RenderDeferredAtmospheric)
+    {
+        LLGLEnable blend(GL_BLEND);
+        gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA);
+
+        gGL.setColorMask(true, true);
+
+        // apply haze
+        LLGLSLShader& haze_shader = gHazeProgram;
+
+        LL_PROFILE_GPU_ZONE("haze");
+        bindDeferredShader(haze_shader);
+
+        LLEnvironment& environment = LLEnvironment::instance();
+        haze_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
+        haze_shader.uniform3fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV);
+
+        haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
+
+        LLGLDepthTest depth(GL_FALSE);
+
+        // full screen blit
+        mScreenTriangleVB->setBuffer();
+        mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+    
+        unbindDeferredShader(haze_shader);
+
+        gGL.setSceneBlendType(LLRender::BT_ALPHA);
+    }
+}
+
+void LLPipeline::doWaterHaze()
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+
+    if (RenderDeferredAtmospheric)
+    {
+        LLGLEnable blend(GL_BLEND);
+        gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA);
+
+        gGL.setColorMask(true, true);
+
+        // apply haze
+        LLGLSLShader& haze_shader = gHazeWaterProgram;
+
+        LL_PROFILE_GPU_ZONE("haze");
+        bindDeferredShader(haze_shader);
+
+        haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
+
+        static LLStaticHashedString above_water_str("above_water");
+        haze_shader.uniform1i(above_water_str, sUnderWaterRender ? -1 : 1);
+
+        if (LLPipeline::sUnderWaterRender)
+        {
+            LLGLDepthTest depth(GL_FALSE);
+
+            // full screen blit
+            mScreenTriangleVB->setBuffer();
+            mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+        }
+        else
+        {
+            //render water patches like LLDrawPoolWater does
+            LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
+            LLGLDisable   cull(GL_CULL_FACE);
+
+            gGLLastMatrix = NULL;
+            gGL.loadMatrix(gGLModelView);
+
+            mWaterPool->pushFaceGeometry();
+        }
+
+        unbindDeferredShader(haze_shader);
+
+
+        gGL.setSceneBlendType(LLRender::BT_ALPHA);
+    }
+}
+
 void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
 {
 	//construct frustum
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 6e4c9c7a972211f20a51de067e1da7f11cb7618a..bbed7cad92a5e66176c871c71e88201ae1008dfe 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -318,6 +318,16 @@ class LLPipeline
     void unbindReflectionProbes(LLGLSLShader& shader);
 
 	void renderDeferredLighting();
+
+    // apply atmospheric haze based on contents of color and depth buffer
+    // should be called just before rendering water when camera is under water 
+    // and just before rendering alpha when camera is above water
+    void doAtmospherics();
+
+    // apply water haze based on contents of color and depth buffer
+    // should be called just before rendering pre-water alpha objects
+    void doWaterHaze();
+
 	void postDeferredGammaCorrect(LLRenderTarget* screen_target);
 
 	void generateSunShadow(LLCamera& camera);