From b6fa72d3c4d02527f6d118eadc9ba1ac48a297f5 Mon Sep 17 00:00:00 2001
From: Graham Linden <graham@lindenlab.com>
Date: Mon, 3 Dec 2018 15:33:15 -0800
Subject: [PATCH] SL-10055

Modify handling of directional light to prefer sun when it is up but use moon dir/color when it is alone in the sky.

Modify handling of shader in shaders to get some shadowing of ambient and nighttime shadowing.
---
 indra/llinventory/llsettingssky.cpp           |  17 +
 indra/llinventory/llsettingssky.h             |   2 +
 .../shaders/class1/deferred/alphaF.glsl       |  13 +-
 .../shaders/class1/deferred/deferredUtil.glsl | 332 +++++++++---------
 .../shaders/class1/deferred/materialF.glsl    |   8 +-
 .../shaders/class1/deferred/softenLightF.glsl |  12 +-
 .../shaders/class2/deferred/softenLightF.glsl | 192 +++++-----
 .../shaders/class2/deferred/sunLightF.glsl    |  14 +-
 .../class2/deferred/sunLightSSAOF.glsl        |  12 +-
 indra/newview/llvosky.cpp                     |  24 +-
 indra/newview/llvosky.h                       |   3 +-
 indra/newview/pipeline.cpp                    | 112 ++++--
 indra/newview/pipeline.h                      |   1 +
 13 files changed, 418 insertions(+), 324 deletions(-)

diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index ace530ae54a..bd407601939 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -968,6 +968,23 @@ LLVector3 LLSettingsSky::getLightDirection() const
     return LLVector3::z_axis;
 }
 
+LLColor3 LLSettingsSky::getLightDiffuse() const
+{
+    update();
+
+    // is the normal from the sun or the moon
+    if (getIsSunUp())
+    {
+        return getSunDiffuse();
+    }
+    else if (getIsMoonUp())
+    {
+        return getMoonDiffuse();
+    }
+
+    return LLColor3::white;
+}
+
 LLColor3 LLSettingsSky::getAmbientColor() const
 {
     // Todo: this causes complications, preferably to get rid of this duality
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
index 796120ba036..bac8b52e659 100644
--- a/indra/llinventory/llsettingssky.h
+++ b/indra/llinventory/llsettingssky.h
@@ -272,6 +272,8 @@ class LLSettingsSky: public LLSettingsBase
     bool getIsMoonUp() const;
 
     LLVector3 getLightDirection() const;
+    LLColor3  getLightDiffuse() const;
+
     LLVector3 getSunDirection() const;
     LLVector3 getMoonDirection() const;
     LLColor4U getFadeColor() const;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index f79fc012d10..07b0f2a98a8 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -43,6 +43,7 @@ uniform mat3 env_mat;
 uniform mat3 ssao_effect_mat;
 
 uniform vec3 sun_dir;
+uniform vec3 moon_dir;
 
 #if HAS_SHADOW
 uniform sampler2DShadow shadowMap0;
@@ -280,20 +281,20 @@ void main()
 	vec2 abnormal	= encode_normal(norm.xyz);
 		 norm.xyz   = decode_normal(abnormal.xy);
 
-	float da = dot(norm.xyz, sun_dir.xyz);
+	float sun_da  = dot(norm.xyz, sun_dir.xyz);
+	float moon_da = dot(norm.xyz, moon_dir.xyz);
 
-    float final_da = da;
+    float final_da = max(sun_da, moon_da);
           final_da = min(final_da, shadow);
-          final_da = max(final_da, 0.0f);
-		  final_da = min(final_da, 1.0f);
-		  final_da = pow(final_da, 1.0/1.3);
+          final_da = clamp(final_da, 0.0f, 1.0f);
+	  final_da = pow(final_da, 1.0/1.3);
 
 	vec4 color = vec4(0,0,0,0);
 
 	color.rgb = atmosFragAmbient(color.rgb, amblit);
 	color.a   = final_alpha;
 
-	float ambient = abs(da);
+	float ambient = abs(final_da);
 	ambient *= 0.5;
 	ambient *= ambient;
 	ambient = (1.0-ambient);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
index 43f00348747..ec05dab57ff 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
@@ -1,5 +1,5 @@
 /** 
- * @file shadowUtil.glsl
+ * @file class1/deferred/deferredUtil.glsl
  *
  * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -39,6 +39,7 @@ uniform float ssao_factor;
 uniform float ssao_factor_inv;
 
 uniform vec3 sun_dir;
+uniform vec3 moon_dir;
 uniform vec2 shadow_res;
 uniform vec2 proj_shadow_res;
 uniform mat4 shadow_matrix[6];
@@ -55,7 +56,7 @@ vec3 decode_normal(vec2 enc);
 
 vec2 getScreenCoordinate(vec2 screenpos)
 {
-	vec2 sc = screenpos.xy * 2.0;
+    vec2 sc = screenpos.xy * 2.0;
     if (screen_res.x > 0 && screen_res.y > 0)
     {
        sc /= screen_res;
@@ -72,41 +73,41 @@ vec3 getNorm(vec2 screenpos)
 float getDepth(vec2 pos_screen)
 {
     float depth = texture2DRect(depthMap, pos_screen).r;
-	return depth;
+    return depth;
 }
 
 vec4 getPosition(vec2 pos_screen)
 {
     float depth = getDepth(pos_screen);
-	vec2 sc = getScreenCoordinate(pos_screen);
-	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
-	vec4 pos = inv_proj * ndc;
-	pos /= pos.w;
-	pos.w = 1.0;
-	return pos;
+    vec2 sc = getScreenCoordinate(pos_screen);
+    vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+    vec4 pos = inv_proj * ndc;
+    pos /= pos.w;
+    pos.w = 1.0;
+    return pos;
 }
 
 #if USE_DEFERRED_SHADER_API
 
 vec4 getPositionWithDepth(vec2 pos_screen, float depth)
 {
-	vec2 sc = getScreenCoordinate(pos_screen);
-	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
-	vec4 pos = inv_proj * ndc;
-	pos /= pos.w;
-	pos.w = 1.0;
-	return pos;
+    vec2 sc = getScreenCoordinate(pos_screen);
+    vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+    vec4 pos = inv_proj * ndc;
+    pos /= pos.w;
+    pos.w = 1.0;
+    return pos;
 }
 
 float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2 pos_screen)
 {
-	stc.xyz /= stc.w;
-	stc.z += shadow_bias * bias_scale;
-		
-	stc.x = floor(stc.x*pos_screen.x + fract(stc.y*shadow_res.y*12345))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here
-	
-	float cs = shadow2D(shadowMap, stc.xyz).x;
-	float shadow = cs;
+    stc.xyz /= stc.w;
+    stc.z += shadow_bias * bias_scale;
+        
+    stc.x = floor(stc.x*pos_screen.x + fract(stc.y*shadow_res.y*12345))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here
+    
+    float cs = shadow2D(shadowMap, stc.xyz).x;
+    float shadow = cs;
     shadow += shadow2D(shadowMap, stc.xyz+vec3(2.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
     shadow += shadow2D(shadowMap, stc.xyz+vec3(1.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
     shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
@@ -116,85 +117,90 @@ float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2 pos_
 
 float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2 pos_screen)
 {
-	stc.xyz /= stc.w;
-	stc.z += spot_shadow_bias * bias_scale;
-	stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap
-
-	float cs = shadow2D(shadowMap, stc.xyz).x;
-	float shadow = cs;
-
-	vec2 off = 1.0/proj_shadow_res;
-	off.y *= 1.5;
-	
-	shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x;
-	shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x;
-	shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x;
-	shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x;
+    stc.xyz /= stc.w;
+    stc.z += spot_shadow_bias * bias_scale;
+    stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap
+
+    float cs = shadow2D(shadowMap, stc.xyz).x;
+    float shadow = cs;
+
+    vec2 off = 1.0/proj_shadow_res;
+    off.y *= 1.5;
+    
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x;
     return shadow*0.2;
 }
 
 float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen)
 {
-	float dp_directional_light = max(0.0, dot(sun_dir.xyz, norm));
-	vec3 offset = sun_dir.xyz * (1.0-dp_directional_light);
-	vec3 shadow_pos = pos.xyz + (offset * shadow_bias);
+    float dp_sun = max(0.0, dot(sun_dir.xyz, norm));
+    float dp_moon = max(0.0, dot(moon_dir.xyz, norm));
+    float dp_directional_light = max(dp_sun,dp_moon);
+          dp_directional_light = clamp(dp_directional_light, 0.0, 1.0);
+
+        vec3 light_dir = (dp_moon > dp_sun) ? moon_dir : sun_dir;
+    vec3 offset = light_dir * (1.0-dp_directional_light);
+    vec3 shadow_pos = pos.xyz + (offset * shadow_bias);
 
     float shadow = 0.0f;
-	vec4 spos = vec4(shadow_pos,1.0);
-	if (spos.z > -shadow_clip.w)
-	{	
-		vec4 lpos;
-		vec4 near_split = shadow_clip*-0.75;
-		vec4 far_split = shadow_clip*-1.25;
-		vec4 transition_domain = near_split-far_split;
-		float weight = 0.0;
-
-		if (spos.z < near_split.z)
-		{
-			lpos = shadow_matrix[3]*spos;
-			
-			float w = 1.0;
-			w -= max(spos.z-far_split.z, 0.0)/transition_domain.z;
-			shadow += pcfShadow(shadowMap3, lpos, 0.5, pos_screen)*w;
-			weight += w;
-			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
-		}
-
-		if (spos.z < near_split.y && spos.z > far_split.z)
-		{
-			lpos = shadow_matrix[2]*spos;
-			
-			float w = 1.0;
-			w -= max(spos.z-far_split.y, 0.0)/transition_domain.y;
-			w -= max(near_split.z-spos.z, 0.0)/transition_domain.z;
-			shadow += pcfShadow(shadowMap2, lpos, 0.75, pos_screen)*w;
-			weight += w;
-		}
-
-		if (spos.z < near_split.x && spos.z > far_split.y)
-		{
-			lpos = shadow_matrix[1]*spos;
-			
-			float w = 1.0;
-			w -= max(spos.z-far_split.x, 0.0)/transition_domain.x;
-			w -= max(near_split.y-spos.z, 0.0)/transition_domain.y;
-			shadow += pcfShadow(shadowMap1, lpos, 0.88, pos_screen)*w;
-			weight += w;
-		}
-
-		if (spos.z > far_split.x)
-		{
-			lpos = shadow_matrix[0]*spos;
-							
-			float w = 1.0;
-			w -= max(near_split.x-spos.z, 0.0)/transition_domain.x;
-				
-			shadow += pcfShadow(shadowMap0, lpos, 1.0, pos_screen)*w;
-			weight += w;
-		}
-
-		shadow /= weight;
-	}
+    vec4 spos = vec4(shadow_pos,1.0);
+    if (spos.z > -shadow_clip.w)
+    {   
+        vec4 lpos;
+        vec4 near_split = shadow_clip*-0.75;
+        vec4 far_split = shadow_clip*-1.25;
+        vec4 transition_domain = near_split-far_split;
+        float weight = 0.0;
+
+        if (spos.z < near_split.z)
+        {
+            lpos = shadow_matrix[3]*spos;
+            
+            float w = 1.0;
+            w -= max(spos.z-far_split.z, 0.0)/transition_domain.z;
+            shadow += pcfShadow(shadowMap3, lpos, 0.5, pos_screen)*w;
+            weight += w;
+            shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+        }
+
+        if (spos.z < near_split.y && spos.z > far_split.z)
+        {
+            lpos = shadow_matrix[2]*spos;
+            
+            float w = 1.0;
+            w -= max(spos.z-far_split.y, 0.0)/transition_domain.y;
+            w -= max(near_split.z-spos.z, 0.0)/transition_domain.z;
+            shadow += pcfShadow(shadowMap2, lpos, 0.75, pos_screen)*w;
+            weight += w;
+        }
+
+        if (spos.z < near_split.x && spos.z > far_split.y)
+        {
+            lpos = shadow_matrix[1]*spos;
+            
+            float w = 1.0;
+            w -= max(spos.z-far_split.x, 0.0)/transition_domain.x;
+            w -= max(near_split.y-spos.z, 0.0)/transition_domain.y;
+            shadow += pcfShadow(shadowMap1, lpos, 0.88, pos_screen)*w;
+            weight += w;
+        }
+
+        if (spos.z > far_split.x)
+        {
+            lpos = shadow_matrix[0]*spos;
+                            
+            float w = 1.0;
+            w -= max(near_split.x-spos.z, 0.0)/transition_domain.x;
+                
+            shadow += pcfShadow(shadowMap0, lpos, 1.0, pos_screen)*w;
+            weight += w;
+        }
+
+        shadow /= weight;
+    }
     return shadow;
 }
 
@@ -203,88 +209,88 @@ float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen)
     float shadow = 0.0f;
     pos += norm * spot_shadow_offset;
 
-	vec4 spos = vec4(pos,1.0);
-	if (spos.z > -shadow_clip.w)
-	{	
-		vec4 lpos;
-		
-		vec4 near_split = shadow_clip*-0.75;
-		vec4 far_split = shadow_clip*-1.25;
-		vec4 transition_domain = near_split-far_split;
-		float weight = 0.0;
+    vec4 spos = vec4(pos,1.0);
+    if (spos.z > -shadow_clip.w)
+    {   
+        vec4 lpos;
+        
+        vec4 near_split = shadow_clip*-0.75;
+        vec4 far_split = shadow_clip*-1.25;
+        vec4 transition_domain = near_split-far_split;
+        float weight = 0.0;
 
         {
-			lpos = shadow_matrix[4 + index]*spos;
-			float w = 1.0;
-			w -= max(spos.z-far_split.z, 0.0)/transition_domain.z;
-		
-			shadow += pcfSpotShadow((index == 0) ? shadowMap4 : shadowMap5, lpos, 0.8, spos.xy)*w;
-			weight += w;
-			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
-		}
-
-		shadow /= weight;
-	}
+            lpos = shadow_matrix[4 + index]*spos;
+            float w = 1.0;
+            w -= max(spos.z-far_split.z, 0.0)/transition_domain.z;
+        
+            shadow += pcfSpotShadow((index == 0) ? shadowMap4 : shadowMap5, lpos, 0.8, spos.xy)*w;
+            weight += w;
+            shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+        }
+
+        shadow /= weight;
+    }
     return shadow;
 }
 
 vec2 getKern(int i)
 {
-	vec2 kern[8];
-	// exponentially (^2) distant occlusion samples spread around origin
-	kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
-	kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
-	kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
-	kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
-	kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
-	kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
-	kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
-	kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+    vec2 kern[8];
+    // exponentially (^2) distant occlusion samples spread around origin
+    kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+    kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+    kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+    kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+    kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+    kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+    kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+    kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
        
-	return kern[i];
+    return kern[i];
 }
 
 //calculate decreases in ambient lighting when crowded out (SSAO)
 float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen)
 {
-	float ret = 1.0;
-	vec3 pos_world = pos.xyz;
-	vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy;
-		
-	float angle_hidden = 0.0;
-	float points = 0;
-		
-	float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
-	
-	// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
-	for (int i = 0; i < 8; i++)
-	{
-		vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect);
-		vec3 samppos_world = getPosition(samppos_screen).xyz; 
-		
-		vec3 diff = pos_world - samppos_world;
-		float dist2 = dot(diff, diff);
-			
-		// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
-		// --> solid angle shrinking by the square of distance
-		//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
-		//(k should vary inversely with # of samples, but this is taken care of later)
-		
-		float funky_val = (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) ? 1.0 : 0.0;
-		angle_hidden = angle_hidden + funky_val * min(1.0/dist2, ssao_factor_inv);
-			
-		// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
-		float diffz_val = (diff.z > -1.0) ? 1.0 : 0.0;
-		points = points + diffz_val;
-	}
-		
-	angle_hidden = min(ssao_factor*angle_hidden/points, 1.0);
-	
-	float points_val = (points > 0.0) ? 1.0 : 0.0;
-	ret = (1.0 - (points_val * angle_hidden));
-
-	ret = max(ret, 0.0);
-	return min(ret, 1.0);
+    float ret = 1.0;
+    vec3 pos_world = pos.xyz;
+    vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy;
+        
+    float angle_hidden = 0.0;
+    float points = 0;
+        
+    float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+    
+    // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+    for (int i = 0; i < 8; i++)
+    {
+        vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect);
+        vec3 samppos_world = getPosition(samppos_screen).xyz; 
+        
+        vec3 diff = pos_world - samppos_world;
+        float dist2 = dot(diff, diff);
+            
+        // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+        // --> solid angle shrinking by the square of distance
+        //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+        //(k should vary inversely with # of samples, but this is taken care of later)
+        
+        float funky_val = (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) ? 1.0 : 0.0;
+        angle_hidden = angle_hidden + funky_val * min(1.0/dist2, ssao_factor_inv);
+            
+        // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
+        float diffz_val = (diff.z > -1.0) ? 1.0 : 0.0;
+        points = points + diffz_val;
+    }
+        
+    angle_hidden = min(ssao_factor*angle_hidden/points, 1.0);
+    
+    float points_val = (points > 0.0) ? 1.0 : 0.0;
+    ret = (1.0 - (points_val * angle_hidden));
+
+    ret = max(ret, 0.0);
+    return min(ret, 1.0);
 }
 
 #endif
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index c1c17532b8d..7d5ae7c2e74 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -98,6 +98,7 @@ uniform mat3 env_mat;
 uniform mat3 ssao_effect_mat;
 
 uniform vec3 sun_dir;
+uniform vec3 moon_dir;
 VARYING vec2 vary_fragcoord;
 
 VARYING vec3 vary_position;
@@ -381,9 +382,10 @@ void main()
 	
 	vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
 
-	float da =dot(norm.xyz, sun_dir.xyz);
+	float sun_da  = dot(norm.xyz, sun_dir.xyz);
+	float moon_da = dot(norm.xyz, moon_dir.xyz);
 
-    float final_da = da;
+    float final_da = max(sun_da,moon_da);
           final_da = min(final_da, shadow);
           //final_da = max(final_da, diffuse.a);
           final_da = max(final_da, 0.0f);
@@ -392,7 +394,7 @@ void main()
 
 	col.rgb = atmosFragAmbient(col, amblit);
 	
-	float ambient = min(abs(da), 1.0);
+	float ambient = min(abs(final_da), 1.0);
 	ambient *= 0.5;
 	ambient *= ambient;
 	ambient = (1.0-ambient);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 5813dd84eeb..41eb06126b2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -56,6 +56,7 @@ uniform mat3 env_mat;
 uniform mat3 ssao_effect_mat;
 
 uniform vec3 sun_dir;
+uniform vec3 moon_dir;
 VARYING vec2 vary_fragcoord;
 
 uniform mat4 inv_proj;
@@ -104,15 +105,17 @@ void main()
     float envIntensity = norm.z;
     norm.xyz = decode_normal(norm.xy); // unpack norm
         
-    float da = dot(norm.xyz, sun_dir.xyz);
+    float da_sun  = dot(norm.xyz, normalize(sun_dir.xyz));
+    float da_moon = dot(norm.xyz, normalize(moon_dir.xyz));
+    float da = max(da_sun, da_moon);
 
     float final_da = clamp(da, 0.0, 1.0);
-          final_da = pow(final_da, 1.0/1.3);
+          final_da = pow(final_da, global_gamma);
 
     vec4 diffuse = texture2DRect(diffuseRect, tc);
 
     //convert to gamma space
-    diffuse.rgb = linear_to_srgb(diffuse.rgb);
+    //diffuse.rgb = linear_to_srgb(diffuse.rgb);
 
     vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
     vec3 col;
@@ -171,8 +174,7 @@ void main()
             bloom = fogged.a;
         #endif
 
-        col = srgb_to_linear(col);
-
+        //col = srgb_to_linear(col);
         //col = vec3(1,0,1);
         //col.g = envIntensity;
     }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 541122fb182..184ac13b275 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -39,7 +39,7 @@ uniform sampler2DRect normalMap;
 uniform sampler2DRect lightMap;
 uniform sampler2DRect depthMap;
 uniform samplerCube environmentMap;
-uniform sampler2D	  lightFunc;
+uniform sampler2D     lightFunc;
 
 uniform float blur_size;
 uniform float blur_fidelity;
@@ -68,13 +68,12 @@ uniform vec4 shadow_clip;
 uniform mat3 ssao_effect_mat;
 
 uniform vec3 sun_dir;
+uniform vec3 moon_dir;
 VARYING vec2 vary_fragcoord;
 
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
-uniform int no_atmo;
-
 vec3 srgb_to_linear(vec3 cs);
 vec3 linear_to_srgb(vec3 cl);
 vec3 decode_normal (vec2 enc);
@@ -90,20 +89,20 @@ vec3 fullbrightShinyAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten);
 
 vec4 getPosition_d(vec2 pos_screen, float depth)
 {
-	vec2 sc = pos_screen.xy*2.0;
-	sc /= screen_res;
-	sc -= vec2(1.0,1.0);
-	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
-	vec4 pos = inv_proj * ndc;
-	pos /= pos.w;
-	pos.w = 1.0;
-	return pos;
+    vec2 sc = pos_screen.xy*2.0;
+    sc /= screen_res;
+    sc -= vec2(1.0,1.0);
+    vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+    vec4 pos = inv_proj * ndc;
+    pos /= pos.w;
+    pos.w = 1.0;
+    return pos;
 }
 
 vec4 getPosition(vec2 pos_screen)
 { //get position in screen space (world units) given window coordinate and depth map
-	float depth = texture2DRect(depthMap, pos_screen.xy).r;
-	return getPosition_d(pos_screen, depth);
+    float depth = texture2DRect(depthMap, pos_screen.xy).r;
+    return getPosition_d(pos_screen, depth);
 }
 
 
@@ -113,92 +112,93 @@ vec4 applyWaterFogView(vec3 pos, vec4 color);
 
 void main() 
 {
-	vec2 tc = vary_fragcoord.xy;
-	float depth = texture2DRect(depthMap, tc.xy).r;
-	vec3 pos = getPosition_d(tc, depth).xyz;
-	vec4 norm = texture2DRect(normalMap, tc);
-	float envIntensity = norm.z;
-	norm.xyz = decode_normal(norm.xy); // unpack norm
-		
-	float da = max(dot(norm.xyz, sun_dir.xyz), 0.0);
-
-	float light_gamma = 1.0/1.3;
-	da = pow(da, light_gamma);
-
-	vec4 diffuse = texture2DRect(diffuseRect, tc);
-
-	//convert to gamma space
-	diffuse.rgb = linear_to_srgb(diffuse.rgb);
-	
-	vec3 col;
-	float bloom = 0.0;
-	{
-		vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
-		
-		vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
-		scol_ambocc = pow(scol_ambocc, vec2(light_gamma));
-
-		float scol = max(scol_ambocc.r, diffuse.a); 
-		float ambocc = scol_ambocc.g;
+    vec2 tc = vary_fragcoord.xy;
+    float depth = texture2DRect(depthMap, tc.xy).r;
+    vec3 pos = getPosition_d(tc, depth).xyz;
+    vec4 norm = texture2DRect(normalMap, tc);
+    float envIntensity = norm.z;
+    norm.xyz = decode_normal(norm.xy); // unpack norm
+        
+    float da_sun  = dot(norm.xyz, normalize(sun_dir.xyz));
+    float da_moon = dot(norm.xyz, normalize(moon_dir.xyz));
+    float da = max(da_sun, da_moon);
+          da = clamp(da, 0.0, 1.0);
+
+    da = pow(da, global_gamma);
+
+    vec4 diffuse = texture2DRect(diffuseRect, tc);
+
+    //convert to gamma space
+	//diffuse.rgb = linear_to_srgb(diffuse.rgb);
+
+    vec3 col;
+    float bloom = 0.0;
+    {
+        vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
+        
+        vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+        scol_ambocc = pow(scol_ambocc, vec2(global_gamma));
+
+        float scol = max(scol_ambocc.r, diffuse.a); 
+        float ambocc = scol_ambocc.g;
 
         vec3 sunlit;
         vec3 amblit;
         vec3 additive;
         vec3 atten;
-	
-		calcFragAtmospherics(pos.xyz, ambocc, sunlit, amblit, additive, atten);
-
-		float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
-		ambient *= 0.5;
-		ambient *= ambient;
-		ambient = (1.0-ambient);
-
-		col.rgb = amblit;
-		col.rgb *= ambient;
-		col += sunlit * min(da, scol);
-		col *= diffuse.rgb;
-	
-		vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
-
-		if (spec.a > 0.0) // specular reflection
-		{
-			// the old infinite-sky shiny reflection
-			float sa = dot(refnormpersp, sun_dir.xyz);
-			vec3 dumbshiny = sunlit*scol_ambocc.r*(texture2D(lightFunc, vec2(sa, spec.a)).r);
-			
-			// add the two types of shiny together
-			vec3 spec_contrib = dumbshiny * spec.rgb;
-			bloom = dot(spec_contrib, spec_contrib) / 6;
-			col += spec_contrib;
-		}
-		
-		col = mix(col, diffuse.rgb, diffuse.a);
-
-		if (envIntensity > 0.0)
-		{ //add environmentmap
-			vec3 env_vec = env_mat * refnormpersp;
-			vec3 refcol = textureCube(environmentMap, env_vec).rgb;
-			col = mix(col.rgb, refcol, envIntensity); 
-		}
-						
-		if (norm.w < 0.5)
-		{
-			col = mix(atmosFragLighting(col, additive, atten), fullbrightAtmosTransportFrag(col, additive, atten), diffuse.a);
-			col = mix(scaleSoftClipFrag(col), fullbrightScaleSoftClipFrag(col), diffuse.a);
-		}
-
-		#ifdef WATER_FOG
-			vec4 fogged = applyWaterFogView(pos.xyz,vec4(col, bloom));
-			col = fogged.rgb;
-			bloom = fogged.a;
-		#endif
-
-		col = srgb_to_linear(col);
-
-		//col = vec3(1,0,1);
-		//col.g = envIntensity;
-	}
-	
-	frag_color.rgb = col;
-	frag_color.a = bloom;
+    
+        calcFragAtmospherics(pos.xyz, ambocc, sunlit, amblit, additive, atten);
+
+        float ambient = dot(norm.xyz, sun_dir.xyz);
+        ambient *= 0.5;
+        ambient *= ambient;
+        ambient = (1.0-ambient);
+
+        col.rgb = amblit;
+        col.rgb *= min(ambient, max(scol, 0.5));
+
+        col += (sunlit * da) * scol;
+
+        col *= diffuse.rgb;
+
+        vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+
+        if (spec.a > 0.0) // specular reflection
+        {
+            // the old infinite-sky shiny reflection
+            float sa = dot(refnormpersp, sun_dir.xyz);
+            vec3 dumbshiny = sunlit*scol_ambocc.r*(texture2D(lightFunc, vec2(sa, spec.a)).r);
+            
+            // add the two types of shiny together
+            vec3 spec_contrib = dumbshiny * spec.rgb;
+            bloom = dot(spec_contrib, spec_contrib) / 6;
+            col += spec_contrib;
+        }
+        
+        col = mix(col, diffuse.rgb, diffuse.a);
+
+        if (envIntensity > 0.0)
+        { //add environmentmap
+            vec3 env_vec = env_mat * refnormpersp;
+            vec3 refcol = textureCube(environmentMap, env_vec).rgb;
+            col = mix(col.rgb, refcol, envIntensity); 
+        }
+                        
+        if (norm.w < 0.5)
+        {
+            col = mix(atmosFragLighting(col, additive, atten), fullbrightAtmosTransportFrag(col, additive, atten), diffuse.a);
+            col = mix(scaleSoftClipFrag(col), fullbrightScaleSoftClipFrag(col), diffuse.a);
+        }
+
+        #ifdef WATER_FOG
+            vec4 fogged = applyWaterFogView(pos.xyz,vec4(col, bloom));
+            col = fogged.rgb;
+            bloom = fogged.a;
+        #endif
+
+        //col = srgb_to_linear(col);
+
+    }
+    frag_color.rgb = col;
+    frag_color.a = bloom;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index aa5e99a2f7b..f2d04c95fef 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -59,6 +59,7 @@ uniform mat4 inv_proj;
 uniform vec2 screen_res;
 uniform vec2 proj_shadow_res;
 uniform vec3 sun_dir;
+uniform vec3 moon_dir;
 
 uniform vec2 shadow_res;
 uniform float shadow_bias;
@@ -138,11 +139,16 @@ void main()
 		return;
 	}*/
 	
-	float shadow = 0.0;
-	float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz));
-	
+	float shadow  = 0.0;
+	float dp_sun  = dot(norm, normalize(sun_dir.xyz));
+	float dp_moon = dot(norm, normalize(moon_dir.xyz));
+	float dp_directional_light = max(dp_sun, dp_moon);
+        dp_directional_light = clamp(dp_directional_light, 0.0, 1.0);
+
+        vec3 light_direction = (dp_moon > dp_sun) ? moon_dir : sun_dir;	
+
 	vec3 shadow_pos = pos.xyz;
-	vec3 offset = sun_dir.xyz * (1.0-dp_directional_light);
+	vec3 offset = light_direction.xyz * (1.0-dp_directional_light);
 	
 	vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0);
 	
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
index 58f3f2f91ee..fd3256e9c84 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
@@ -59,6 +59,7 @@ uniform mat4 inv_proj;
 uniform vec2 screen_res;
 uniform vec2 proj_shadow_res;
 uniform vec3 sun_dir;
+uniform vec3 moon_dir;
 
 uniform vec2 shadow_res;
 
@@ -200,10 +201,15 @@ void main()
 	}*/
 	
 	float shadow = 0.0;
-	float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz));
-	
+	float dp_sun = dot(norm, normalize(sun_dir.xyz));
+	float dp_moon = dot(norm, normalize(moon_dir.xyz));
+	float dp_directional_light = max(dp_sun, dp_moon);
+	dp_directional_light = max(0.0, dp_directional_light);
+
+        vec3 light_direction = (dp_moon > dp_sun) ? moon_dir : sun_dir;	
+
 	vec3 shadow_pos = pos.xyz;
-	vec3 offset = sun_dir.xyz * (1.0-dp_directional_light);
+	vec3 offset = light_direction.xyz * (1.0-dp_directional_light);
 	
 	vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0);
 	
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index f5aa0034176..d30bb260e1a 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -732,8 +732,14 @@ void LLVOSky::updateDirections(void)
 {
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
+    mLastSunLightingDirection  = mSun.getDirection();
+    mLastMoonLightingDirection = mMoon.getDirection();
+
+    mSun.setDirection(psky->getSunDirection());
+	mMoon.setDirection(psky->getMoonDirection());
+
     mSun.setColor(psky->getSunlightColor());
-	mMoon.setColor(LLColor3(1.0f, 1.0f, 1.0f));
+	mMoon.setColor(psky->getMoonDiffuse());
 
 	mSun.renewDirection();
 	mSun.renewColor();
@@ -788,17 +794,20 @@ bool LLVOSky::updateSky()
 
         LLVector3 direction = mSun.getDirection();
 		direction.normalize();
-		const F32 dot_lighting = direction * mLastLightingDirection;
+		const F32 dot_sun  = direction * mLastSunLightingDirection;
+        const F32 dot_moon = direction * mLastMoonLightingDirection;
 
 		LLColor3 delta_color;
 		delta_color.setVec(mLastTotalAmbient.mV[0] - total_ambient.mV[0],
 							mLastTotalAmbient.mV[1] - total_ambient.mV[1],
                             mLastTotalAmbient.mV[2] - total_ambient.mV[2]);
 
-        bool light_direction_changed = (dot_lighting < LIGHT_DIRECTION_THRESHOLD);
-        bool color_changed = (delta_color.length() >= COLOR_CHANGE_THRESHOLD);
+        bool sun_direction_changed  = (dot_sun < LIGHT_DIRECTION_THRESHOLD);
+        bool moon_direction_changed = (dot_moon < LIGHT_DIRECTION_THRESHOLD);
+        bool color_changed          = (delta_color.length() >= COLOR_CHANGE_THRESHOLD);
 
-        mForceUpdate = mForceUpdate || light_direction_changed;
+        mForceUpdate = mForceUpdate || sun_direction_changed;
+        mForceUpdate = mForceUpdate || moon_direction_changed;
         mForceUpdate = mForceUpdate || color_changed;
         mForceUpdate = mForceUpdate || !mInitialized;
 
@@ -816,7 +825,6 @@ bool LLVOSky::updateSky()
 		
 			if (!direction.isExactlyZero())
 			{
-				mLastLightingDirection = direction;
                 mLastTotalAmbient = total_ambient;
 				mInitialized = TRUE;
 
@@ -1623,8 +1631,6 @@ void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLV
     mSun.setDirection(sun_dir_cfr);	
 	mMoon.setDirection(moon_dir_cfr);
 
-	mLastLightingDirection = mSun.getDirection();
-
 	// Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
 	// on the upward facing faces of cubes.
     {
@@ -1650,8 +1656,6 @@ void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr)
 {
     mSun.setDirection(sun_dir_cfr);	
 
-	mLastLightingDirection = mSun.getDirection();
-
 	// Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
 	// on the upward facing faces of cubes.
     {
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 20d0135c211..0713661295b 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -334,7 +334,8 @@ class LLVOSky : public LLStaticViewerObject
 	
 	bool				mInitialized;
 	bool				mForceUpdate;				//flag to force instantaneous update of cubemap
-	LLVector3			mLastLightingDirection;
+	LLVector3			mLastSunLightingDirection;
+    LLVector3			mLastMoonLightingDirection;
 	LLColor3			mLastTotalAmbient;
 	F32					mAmbientScale;
 	LLColor3			mNightColorShift;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 21b70e9c604..cd2146ab4e0 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -6008,6 +6008,13 @@ void LLPipeline::setupAvatarLights(bool for_edit)
 {
 	assertInitialized();
 
+    LLEnvironment& environment = LLEnvironment::instance();
+    LLSettingsSky::ptr_t psky = environment.getCurrentSky();
+
+    bool sun_up         = environment.getIsSunUp();
+    bool moon_up        = environment.getIsMoonUp();
+    bool sun_is_primary = sun_up || !moon_up;
+
 	if (for_edit)
 	{
 		LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
@@ -6042,13 +6049,14 @@ void LLPipeline::setupAvatarLights(bool for_edit)
 	}
 	else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
 	{
-        LLVector3 sun_dir = LLVector3(mSunDir);
-		LLVector3 opposite_pos = -sun_dir;
-		LLVector3 orthog_light_pos = sun_dir % LLVector3::z_axis;
+        LLVector3 light_dir = sun_is_primary ? LLVector3(mSunDir) : LLVector3(mMoonDir);
+		LLVector3 opposite_pos = -light_dir;
+		LLVector3 orthog_light_pos = light_dir % LLVector3::z_axis;
 		LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
 		backlight_pos.normalize();
-			
-		LLColor4 light_diffuse = mSunDiffuse;
+
+		LLColor4 light_diffuse = sun_is_primary ? mSunDiffuse : mMoonDiffuse;
+
 		LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
 		F32 max_component = 0.001f;
 		for (S32 i = 0; i < 3; i++)
@@ -6279,6 +6287,10 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 		gGL.setAmbientLightColor(ambient);
 	}
 
+    bool sun_up         = environment.getIsSunUp();
+    bool moon_up        = environment.getIsMoonUp();
+    bool sun_is_primary = sun_up || !moon_up;
+
 	// Light 0 = Sun or Moon (All objects)
 	{
         LLVector4 sun_dir(environment.getSunDirection(), 0.0f);
@@ -6286,15 +6298,8 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 
         mSunDir.setVec(sun_dir);
         mMoonDir.setVec(moon_dir);
-
-		if (environment.getIsSunUp())
-		{			
-			mSunDiffuse.setVec(psky->getSunDiffuse());
-		}
-		else
-		{
-			mSunDiffuse.setVec(psky->getMoonDiffuse());
-		}
+        mSunDiffuse.setVec(psky->getSunDiffuse());
+        mMoonDiffuse.setVec(psky->getMoonDiffuse());
 
 		F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
 		if (max_color > 1.f)
@@ -6303,19 +6308,21 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 		}
 		mSunDiffuse.clamp();
 
-		LLColor4 light_diffuse = mSunDiffuse;
+        max_color = llmax(mMoonDiffuse.mV[0], mMoonDiffuse.mV[1], mMoonDiffuse.mV[2]);
+		if (max_color > 1.f)
+		{
+			mMoonDiffuse *= 1.f/max_color;
+		}
+		mMoonDiffuse.clamp();
+
+		LLColor4  light_diffuse = sun_is_primary ? mSunDiffuse : mMoonDiffuse;
+        LLVector4 light_dir     = sun_is_primary ? mSunDir     : mMoonDir;
 
 		mHWLightColors[0] = light_diffuse;
 
 		LLLightState* light = gGL.getLight(0);
-        if (environment.getIsSunUp())
-		{
-		    light->setPosition(mSunDir);
-        }
-        else
-        {
-            light->setPosition(mMoonDir);
-        }
+        light->setPosition(light_dir);
+
 		light->setDiffuse(light_diffuse);
 		light->setAmbient(LLColor4::black);
 		light->setSpecular(LLColor4::black);
@@ -8491,17 +8498,32 @@ void LLPipeline::renderDeferredLighting()
 		vert[0].set(-1,1,0);
 		vert[1].set(-1,-3,0);
 		vert[2].set(3,1,0);
+
+        const LLEnvironment& environment = LLEnvironment::instance();
+
+        bool sun_up  = environment.getIsSunUp();
+        bool moon_up = environment.getIsMoonUp();
 		
 		{
 			setupHWLights(NULL); //to set mSun/MoonDir;
 			glh::vec4f tc(mSunDir.mV);
 			mat.mult_matrix_vec(tc);
-			mTransformedSunDir.set(tc.v);
-            mTransformedSunDir.normalize();
 
             glh::vec4f tc_moon(mMoonDir.mV);
             mTransformedMoonDir.set(tc_moon.v);
             mTransformedMoonDir.normalize();
+
+            bool sun_is_primary = sun_up || !moon_up;            
+            if (sun_is_primary)
+            {
+                mTransformedSunDir.set(tc.v);
+                mTransformedSunDir.normalize();
+            }
+            else
+            {
+                mTransformedSunDir.set(tc_moon.v);
+                mTransformedSunDir.normalize();
+            }            
 		}
 
 		gGL.pushMatrix();
@@ -9110,16 +9132,31 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target)
 		vert[1].set(-1,-3,0);
 		vert[2].set(3,1,0);
 		
+        const LLEnvironment& environment = LLEnvironment::instance();
+
+        bool sun_up  = environment.getIsSunUp();
+        bool moon_up = environment.getIsMoonUp();
+
 		{
 			setupHWLights(NULL); //to set mSun/MoonDir;
 			glh::vec4f tc(mSunDir.mV);
 			mat.mult_matrix_vec(tc);
-			mTransformedSunDir.set(tc.v);
-            mTransformedSunDir.normalize();
 
             glh::vec4f tc_moon(mMoonDir.mV);
             mTransformedMoonDir.set(tc_moon.v);
             mTransformedMoonDir.normalize();
+
+            bool sun_is_primary = sun_up || !moon_up;            
+            if (sun_is_primary)
+            {
+                mTransformedSunDir.set(tc.v);
+                mTransformedSunDir.normalize();
+            }
+            else
+            {
+                mTransformedSunDir.set(tc_moon.v);
+                mTransformedSunDir.normalize();
+            }
 		}
 
 		gGL.pushMatrix();
@@ -10697,17 +10734,20 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	//LLVector3 n = RenderShadowNearDist;
 	//F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
 
-    LLVector3 sun_dir(mSunDir);
+    LLEnvironment& environment = LLEnvironment::instance();
+    LLSettingsSky::ptr_t psky = environment.getCurrentSky();
+
+    LLVector3 caster_dir(environment.getIsSunUp() ? mSunDir : mMoonDir);
 
 	//put together a universal "near clip" plane for shadow frusta
 	LLPlane shadow_near_clip;
 	{        
 		LLVector3 p = gAgent.getPositionAgent();
-		p += sun_dir * RenderFarClip*2.f;
-		shadow_near_clip.setVec(p, sun_dir);
+		p += caster_dir * RenderFarClip*2.f;
+		shadow_near_clip.setVec(p, caster_dir);
 	}
 
-	LLVector3 lightDir = -sun_dir;
+	LLVector3 lightDir = -caster_dir;
 	lightDir.normVec();
 
 	glh::vec3f light_dir(lightDir.mV);
@@ -10810,9 +10850,15 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
 	// convenience array of 4 near clip plane distances
 	F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
-	
 
-	if (mSunDiffuse == LLColor4::black)
+    bool sun_up         = environment.getIsSunUp();
+    bool moon_up        = environment.getIsMoonUp();
+    bool sun_is_primary = sun_up || !moon_up;
+    bool ignore_shadows = (sun_is_primary && (mSunDiffuse == LLColor4::black))
+                       || (moon_up        && (mMoonDiffuse == LLColor4::black))
+                       || !(sun_up || moon_up);
+
+	if (ignore_shadows)
 	{ //sun diffuse is totally black, shadows don't matter
 		LLGLDepthTest depth(GL_TRUE);
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 57d23312227..99777810653 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -663,6 +663,7 @@ class LLPipeline
 	U32					mLightFunc;
 
 	LLColor4			mSunDiffuse;
+    LLColor4			mMoonDiffuse;
 	LLVector4			mSunDir;
     LLVector4			mMoonDir;
 
-- 
GitLab