Browse Source

Changed the SM2.0 tradeoffs to allow 4-sample shadow mapping and to verify that shaders again work on GPU's without hardware shadow compare (eg. Radeon 9800.) Removed unnecessary shader code & simplified the LitSolid & light volume shaders.

Lasse Öörni 11 năm trước cách đây
mục cha
commit
1418fb7e83

+ 3 - 9
Bin/CoreData/Shaders/GLSL/DeferredLight.glsl

@@ -62,14 +62,8 @@ void PS()
     vec4 projWorldPos = vec4(worldPos, 1.0);
     vec3 lightColor;
     vec3 lightDir;
-    float diff;
-
-    #ifdef DIRLIGHT
-        diff = GetDiffuse(normal, cLightDirPS, lightDir);
-    #else
-        vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
-        diff = GetDiffuse(normal, lightVec, lightDir);
-    #endif
+    
+    float diff = GetDiffuse(normal, worldPos, lightDir);
 
     #ifdef SHADOW
         diff *= GetShadowDeferred(projWorldPos, depth);
@@ -80,7 +74,7 @@ void PS()
         lightColor = spotPos.w > 0.0 ? texture2DProj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : vec3(0.0);
     #elif defined(CUBEMASK)
         mat3 lightVecRot = mat3(cLightMatricesPS[0][0].xyz, cLightMatricesPS[0][1].xyz, cLightMatricesPS[0][2].xyz);
-        lightColor = textureCube(sLightCubeMap, lightVecRot * -lightVec).rgb * cLightColor.rgb;
+        lightColor = textureCube(sLightCubeMap, lightVecRot * (worldPos - cLightPosPS.xyz)).rgb * cLightColor.rgb;
     #else
         lightColor = cLightColor.rgb;
     #endif

+ 5 - 9
Bin/CoreData/Shaders/GLSL/Lighting.glsl

@@ -81,29 +81,25 @@ vec4 GetShadowPos(int index, vec4 projWorldPos)
 #endif
 
 #ifdef COMPILEPS
-float GetDiffuse(vec3 normal, vec3 lightVec, out vec3 lightDir)
+float GetDiffuse(vec3 normal, vec3 worldPos, out vec3 lightDir)
 {
     #ifdef DIRLIGHT
-        #ifdef NORMALMAP
-            // In normal mapped forward lighting, the tangent space light vector needs renormalization
-            lightDir = normalize(lightVec);
-        #else
-            lightDir = lightVec;
-        #endif
-
+        lightDir = cLightDirPS;
         return max(dot(normal, lightDir), 0.0);
     #else
+        vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
         float lightDist = length(lightVec);
         lightDir = lightVec / lightDist;
         return max(dot(normal, lightDir), 0.0) * texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
     #endif
 }
 
-float GetDiffuseVolumetric(vec3 lightVec)
+float GetDiffuseVolumetric(vec3 worldPos)
 {
     #ifdef DIRLIGHT
         return 1.0;
     #else
+        vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
         float lightDist = length(lightVec);
         return texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
     #endif

+ 1 - 7
Bin/CoreData/Shaders/GLSL/LitParticle.glsl

@@ -94,14 +94,8 @@ void PS()
         vec3 lightColor;
         vec3 lightDir;
         vec3 finalColor;
-        float diff;
 
-        #ifdef DIRLIGHT
-            diff = GetDiffuseVolumetric(cLightDirPS);
-        #else
-            vec3 lightVec = (cLightPosPS.xyz - vWorldPos.xyz) * cLightPosPS.w;
-            diff = GetDiffuseVolumetric(lightVec);
-        #endif
+        float diff = GetDiffuseVolumetric(vWorldPos.xyz);
 
         #ifdef SHADOW
             diff *= GetShadow(vShadowPos, vWorldPos.w);

+ 1 - 7
Bin/CoreData/Shaders/GLSL/LitSolid.glsl

@@ -134,14 +134,8 @@ void PS()
         vec3 lightColor;
         vec3 lightDir;
         vec3 finalColor;
-        float diff;
 
-        #ifdef DIRLIGHT
-            diff = GetDiffuse(normal, cLightDirPS, lightDir);
-        #else
-            vec3 lightVec = (cLightPosPS.xyz - vWorldPos.xyz) * cLightPosPS.w;
-            diff = GetDiffuse(normal, lightVec, lightDir);
-        #endif
+        float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);
 
         #ifdef SHADOW
             diff *= GetShadow(vShadowPos, vWorldPos.w);

+ 2 - 8
Bin/CoreData/Shaders/GLSL/PrepassLight.glsl

@@ -59,15 +59,9 @@ void PS()
     vec4 projWorldPos = vec4(worldPos, 1.0);
     vec3 lightColor;
     vec3 lightDir;
-    float diff;
 
     // Accumulate light at half intensity to allow 2x "overburn"
-    #ifdef DIRLIGHT
-        diff = 0.5 * GetDiffuse(normal, cLightDirPS, lightDir);
-    #else
-        vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
-        diff = 0.5 * GetDiffuse(normal, lightVec, lightDir);
-    #endif
+    float diff = 0.5 * GetDiffuse(normal, worldPos, lightDir);
 
     #ifdef SHADOW
         diff *= GetShadowDeferred(projWorldPos, depth);
@@ -78,7 +72,7 @@ void PS()
         lightColor = spotPos.w > 0.0 ? texture2DProj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : vec3(0.0);
     #elif defined(CUBEMASK)
         mat3 lightVecRot = mat3(cLightMatricesPS[0][0].xyz, cLightMatricesPS[0][1].xyz, cLightMatricesPS[0][2].xyz);
-        lightColor = textureCube(sLightCubeMap, lightVecRot * -lightVec).rgb * cLightColor.rgb;
+        lightColor = textureCube(sLightCubeMap, lightVecRot * (worldPos - cLightPosPS.xyz)).rgb * cLightColor.rgb;
     #else
         lightColor = cLightColor.rgb;
     #endif

+ 2 - 8
Bin/CoreData/Shaders/GLSL/TerrainBlend.glsl

@@ -116,14 +116,8 @@ void PS()
         vec3 lightColor;
         vec3 lightDir;
         vec3 finalColor;
-        float diff;
-
-        #ifdef DIRLIGHT
-            diff = GetDiffuse(normal, cLightDirPS, lightDir);
-        #else
-            vec3 lightVec = (cLightPosPS.xyz - vWorldPos.xyz) * cLightPosPS.w;
-            diff = GetDiffuse(normal, lightVec, lightDir);
-        #endif
+        
+        float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);
 
         #ifdef SHADOW
             diff *= GetShadow(vShadowPos, vWorldPos.w);

+ 6 - 12
Bin/CoreData/Shaders/HLSL/DeferredLight.hlsl

@@ -49,14 +49,14 @@ void PS(
     // If rendering a directional light quad, optimize out the w divide
     #ifdef DIRLIGHT
         #ifdef ORTHO
-            float depth = tex2D(sDepthBuffer, iScreenPos).r;
+            float depth = Sample(sDepthBuffer, iScreenPos).r;
             float3 worldPos = lerp(iNearRay, iFarRay, depth);
         #else
-            float depth = tex2D(sDepthBuffer, iScreenPos).r;
+            float depth = Sample(sDepthBuffer, iScreenPos).r;
             float3 worldPos = iFarRay * depth;
         #endif
-        float4 albedoInput = tex2D(sAlbedoBuffer, iScreenPos);
-        float4 normalInput = tex2D(sNormalBuffer, iScreenPos);
+        float4 albedoInput = Sample(sAlbedoBuffer, iScreenPos);
+        float4 normalInput = Sample(sNormalBuffer, iScreenPos);
     #else
         #ifdef ORTHO
             float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;
@@ -73,14 +73,8 @@ void PS(
     float4 projWorldPos = float4(worldPos, 1.0);
     float3 lightColor;
     float3 lightDir;
-    float diff;
 
-    #ifdef DIRLIGHT
-        diff = GetDiffuse(normal, cLightDirPS, lightDir);
-    #else
-        float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
-        diff = GetDiffuse(normal, lightVec, lightDir);
-    #endif
+    float diff = GetDiffuse(normal, worldPos, lightDir);
 
     #ifdef SHADOW
         diff *= GetShadowDeferred(projWorldPos, depth);
@@ -90,7 +84,7 @@ void PS(
         float4 spotPos = mul(projWorldPos, cLightMatricesPS[0]);
         lightColor = spotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : 0.0;
     #elif defined(CUBEMASK)
-        lightColor = texCUBE(sLightCubeMap, mul(-lightVec, (float3x3)cLightMatricesPS[0])).rgb * cLightColor.rgb;
+        lightColor = texCUBE(sLightCubeMap, mul(worldPos - cLightPosPS.xyz, (float3x3)cLightMatricesPS[0])).rgb * cLightColor.rgb;
     #else
         lightColor = cLightColor.rgb;
     #endif

+ 5 - 9
Bin/CoreData/Shaders/HLSL/Lighting.hlsl

@@ -94,29 +94,25 @@ void GetShadowPos(float4 projWorldPos, out float4 shadowPos[NUMCASCADES])
 #endif
 
 #ifdef COMPILEPS
-float GetDiffuse(float3 normal, float3 lightVec, out float3 lightDir)
+float GetDiffuse(float3 normal, float3 worldPos, out float3 lightDir)
 {
     #ifdef DIRLIGHT
-        #ifdef NORMALMAP
-            // In normal mapped forward lighting, the tangent space light vector needs renormalization
-            lightDir = normalize(lightVec);
-        #else
-            lightDir = lightVec;
-        #endif
-
+        lightDir = cLightDirPS;
         return saturate(dot(normal, lightDir));
     #else
+        float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
         float lightDist = length(lightVec);
         lightDir = lightVec / lightDist;
         return saturate(dot(normal, lightDir)) * tex1D(sLightRampMap, lightDist).r;
     #endif
 }
 
-float GetDiffuseVolumetric(float3 lightVec)
+float GetDiffuseVolumetric(float3 worldPos)
 {
     #ifdef DIRLIGHT
         return 1.0;
     #else
+        float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
         float lightDist = length(lightVec);
         return tex1D(sLightRampMap, lightDist).r;
     #endif

+ 2 - 8
Bin/CoreData/Shaders/HLSL/LitParticle.hlsl

@@ -125,14 +125,8 @@ void PS(float2 iTexCoord : TEXCOORD0,
         // Per-pixel forward lighting
         float3 lightColor;
         float3 finalColor;
-        float diff;
-    
-        #ifdef DIRLIGHT
-            diff = GetDiffuseVolumetric(cLightDirPS);
-        #else
-            float3 lightVec = (cLightPosPS.xyz - iWorldPos.xyz) * cLightPosPS.w;
-            diff = GetDiffuseVolumetric(lightVec);
-        #endif
+        
+        float diff = GetDiffuseVolumetric(iWorldPos.xyz);
 
         #ifdef SHADOW
             diff *= GetShadow(iShadowPos, iWorldPos.w);

+ 11 - 17
Bin/CoreData/Shaders/HLSL/LitSolid.hlsl

@@ -5,11 +5,6 @@
 #include "Lighting.hlsl"
 #include "Fog.hlsl"
 
-// With SM2 alpha-masked point light shadows become too complex, so disable specular lighting
-#if !defined(SM3) && defined(POINTLIGHT) && defined(SHADOW) && defined(ALPHAMASK)
-    #undef SPECULAR
-#endif
-
 void VS(float4 iPos : POSITION,
     float3 iNormal : NORMAL,
     float2 iTexCoord : TEXCOORD0,
@@ -165,22 +160,27 @@ void PS(
     #else
         float4 diffColor = cMatDiffColor;
     #endif
-    
+
     // Get material specular albedo
     #ifdef SPECMAP
         float3 specColor = cMatSpecColor.rgb * tex2D(sSpecMap, iTexCoord.xy).rgb;
     #else
         float3 specColor = cMatSpecColor.rgb;
     #endif
-    
+
     // Get normal
     #ifdef NORMALMAP
         float3x3 tbn = float3x3(iTangent.xyz, float3(iTexCoord.zw, iTangent.w), iNormal);
-        float3 normal = normalize(mul(DecodeNormal(tex2D(sNormalMap, iTexCoord.xy)), tbn));
+        // We may be running low on instructions on Shader Model 2, so skip normalize if necessary
+        #if defined(SM3) || !defined(SHADOW) || !defined(SPECULAR)
+            float3 normal = normalize(mul(DecodeNormal(tex2D(sNormalMap, iTexCoord.xy)), tbn));
+        #else
+            float3 normal = mul(DecodeNormal(tex2D(sNormalMap, iTexCoord.xy)), tbn);
+        #endif
     #else
         float3 normal = normalize(iNormal);
     #endif
-    
+
     // Get fog factor
     #ifdef HEIGHTFOG
         float fogFactor = GetHeightFogFactor(iWorldPos.w, iWorldPos.y);
@@ -193,19 +193,13 @@ void PS(
         float3 lightDir;
         float3 lightColor;
         float3 finalColor;
-        float diff;
 
-        #ifdef DIRLIGHT
-            diff = GetDiffuse(normal, cLightDirPS, lightDir);
-        #else
-            float3 lightVec = (cLightPosPS.xyz - iWorldPos.xyz) * cLightPosPS.w;
-            diff = GetDiffuse(normal, lightVec, lightDir);
-        #endif
+        float diff = GetDiffuse(normal, iWorldPos.xyz, lightDir);
 
         #ifdef SHADOW
             diff *= GetShadow(iShadowPos, iWorldPos.w);
         #endif
-    
+
         #if defined(SPOTLIGHT)
             lightColor = iSpotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, iSpotPos).rgb * cLightColor.rgb : 0.0;
         #elif defined(CUBEMASK)

+ 5 - 11
Bin/CoreData/Shaders/HLSL/PrepassLight.hlsl

@@ -49,13 +49,13 @@ void PS(
     // If rendering a directional light quad, optimize out the w divide
     #ifdef DIRLIGHT
         #ifdef ORTHO
-            float depth = tex2D(sDepthBuffer, iScreenPos).r;
+            float depth = Sample(sDepthBuffer, iScreenPos).r;
             float3 worldPos = lerp(iNearRay, iFarRay, depth);
         #else
-            float depth = tex2D(sDepthBuffer, iScreenPos).r;
+            float depth = Sample(sDepthBuffer, iScreenPos).r;
             float3 worldPos = iFarRay * depth;
         #endif
-        float4 normalInput = tex2D(sNormalBuffer, iScreenPos);
+        float4 normalInput = Sample(sNormalBuffer, iScreenPos);
     #else
         #ifdef ORTHO
             float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;
@@ -71,15 +71,9 @@ void PS(
     float4 projWorldPos = float4(worldPos, 1.0);
     float3 lightColor;
     float3 lightDir;
-    float diff;
 
     // Accumulate light at half intensity to allow 2x "overburn"
-    #ifdef DIRLIGHT
-        diff = 0.5 * GetDiffuse(normal, cLightDirPS, lightDir);
-    #else
-        float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
-        diff = 0.5 * GetDiffuse(normal, lightVec, lightDir);
-    #endif
+    float diff = 0.5 * GetDiffuse(normal, worldPos, lightDir);
 
     #ifdef SHADOW
         diff *= GetShadowDeferred(projWorldPos, depth);
@@ -89,7 +83,7 @@ void PS(
         float4 spotPos = mul(projWorldPos, cLightMatricesPS[0]);
         lightColor = spotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : 0.0;
     #elif defined(CUBEMASK)
-        lightColor = texCUBE(sLightCubeMap, mul(-lightVec, (float3x3)cLightMatricesPS[0])).rgb * cLightColor.rgb;
+        lightColor = texCUBE(sLightCubeMap, mul(worldPos - cLightPosPS.xyz, (float3x3)cLightMatricesPS[0])).rgb * cLightColor.rgb;
     #else
         lightColor = cLightColor.rgb;
     #endif

+ 5 - 1
Bin/CoreData/Shaders/HLSL/Samplers.hlsl

@@ -33,7 +33,11 @@ float3 DecodeNormal(float4 normalInput)
     #ifdef PACKEDNORMAL
         float3 normal;
         normal.xy = normalInput.ag * 2.0 - 1.0;
-        normal.z = sqrt(max(1.0 - dot(normal.xy, normal.xy), 0.0));
+        #ifdef SM3
+            normal.z = sqrt(max(1.0 - dot(normal.xy, normal.xy), 0.0));
+        #else
+            normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+        #endif
         return normal;
     #else
         return normalInput.rgb * 2.0 - 1.0;

+ 2 - 8
Bin/CoreData/Shaders/HLSL/TerrainBlend.hlsl

@@ -142,14 +142,8 @@ void PS(float2 iTexCoord : TEXCOORD0,
         float3 lightDir;
         float3 lightColor;
         float3 finalColor;
-        float diff;
-
-        #ifdef DIRLIGHT
-            diff = GetDiffuse(normal, cLightDirPS, lightDir);
-        #else
-            float3 lightVec = (cLightPosPS.xyz - iWorldPos.xyz) * cLightPosPS.w;
-            diff = GetDiffuse(normal, lightVec, lightDir);
-        #endif
+        
+        float diff = GetDiffuse(normal, iWorldPos.xyz, lightDir);
 
         #ifdef SHADOW
             diff *= GetShadow(iShadowPos, iWorldPos.w);

+ 2 - 1
Docs/Reference.dox

@@ -695,7 +695,8 @@ When setting the initial screen mode, Graphics does a few checks:
 %Shader model 2 has the following limitations due to limited pixel shader instruction count:
 
 - Directional light shadows support a maximum of 3 cascade splits instead of 4.
-- High quality (4 samples) shadow mapping is not supported.
+- Combining the ambient pass with the first forward light (lit base pass optimization) is not supported with shadowed lights when 4 shadow samples are being used.
+- Shadowed point lights do not support specular calculations in forward rendering.
 - Height fog is not supported.
 
 \section Rendering_Renderer Renderer

+ 3 - 0
Source/Engine/Graphics/Batch.cpp

@@ -553,6 +553,7 @@ void Batch::Prepare(View* view, bool setModelTransform) const
         if (shadowMap)
         {
             {
+                // Calculate point light shadow sampling offsets (unrolled cube map)
                 unsigned faceWidth = shadowMap->GetWidth() / 2;
                 unsigned faceHeight = shadowMap->GetHeight() / 3;
                 float width = (float)shadowMap->GetWidth();
@@ -578,6 +579,8 @@ void Batch::Prepare(View* view, bool setModelTransform) const
             }
             
             {
+                // Calculate shadow camera depth parameters for point light shadows and shadow fade parameters for
+                //  directional light shadows, stored in the same uniform
                 Camera* shadowCamera = lightQueue_->shadowSplits_[0].shadowCamera_;
                 float nearClip = shadowCamera->GetNearClip();
                 float farClip = shadowCamera->GetFarClip();

+ 10 - 6
Source/Engine/Graphics/Renderer.cpp

@@ -179,8 +179,7 @@ static const char* shadowVariations[] =
     "",
     ""
     #else
-    // On Direct3D the quality is always "low" if not using hardware shadow compare
-    "SHADOWCMP",
+    "LQSHADOW SHADOWCMP",
     "LQSHADOW",
     "SHADOWCMP",
     ""
@@ -397,9 +396,6 @@ void Renderer::SetShadowQuality(int quality)
         quality |= SHADOWQUALITY_HIGH_16BIT;
     if (!graphics_->GetHiresShadowMapFormat())
         quality &= SHADOWQUALITY_HIGH_16BIT;
-    // Shader Model 2 can not reliably support four samples without exceeding pixel shader instruction count limit
-    if (!graphics_->GetSM3Support())
-        quality &= ~SHADOWQUALITY_HIGH_16BIT;
     
     if (quality != shadowQuality_)
     {
@@ -897,7 +893,9 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
         }
         else
         {
-            newShadowMap->SetFilterMode(FILTER_BILINEAR);
+            // When shadow compare must be done manually, use nearest filtering so that the filtering of point lights and other
+            // shadowed lights matches
+            newShadowMap->SetFilterMode(graphics_->GetHardwareShadowSupport() ? FILTER_BILINEAR : FILTER_NEAREST);
             // If no dummy color rendertarget for this size exists yet, create one now
             if (!colorShadowMaps_.Contains(searchKey))
             {
@@ -1469,6 +1467,7 @@ void Renderer::LoadPassShaders(Technique* tech, StringHash type)
     PROFILE(LoadPassShaders);
     
     unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
+    bool isSM3 = graphics_->GetSM3Support();
     
     Vector<SharedPtr<ShaderVariation> >& vertexShaders = pass->GetVertexShaders();
     Vector<SharedPtr<ShaderVariation> >& pixelShaders = pass->GetPixelShaders();
@@ -1495,6 +1494,11 @@ void Renderer::LoadPassShaders(Technique* tech, StringHash type)
         {
             unsigned l = j % MAX_LIGHT_PS_VARIATIONS;
             unsigned h = j / MAX_LIGHT_PS_VARIATIONS;
+            
+            // On Shader Model 2 specular calculations are not supported with shadowed point lights
+            if (!isSM3 && (l & LPS_SHADOW) && (l & 3) >= LPS_POINT)
+                l &= ~LPS_SPEC;
+            
             if (l & LPS_SHADOW)
             {
                 pixelShaders[j] = graphics_->GetShader(PS, pass->GetPixelShader(), pass->GetPixelShaderDefines() + " " +

+ 4 - 2
Source/Engine/Graphics/View.cpp

@@ -403,6 +403,7 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
     deferred_ = false;
     deferredAmbient_ = false;
     useLitBase_ = false;
+    useShadowLitBase_ = graphics_->GetSM3Support() || renderer_->GetShadowQuality() < SHADOWQUALITY_HIGH_16BIT;
     
     for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
     {
@@ -1167,8 +1168,9 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQ
     bool allowTransparentShadows = !renderer_->GetReuseShadowMaps();
     bool allowLitBase = useLitBase_ && !light->IsNegative() && light == drawable->GetFirstLight() &&
         drawable->GetVertexLights().Empty() && !hasAmbientGradient;
-    // Ambient + shadowed point light on Shader Model 2 may exceed the pixel shader instruction count
-    if (allowLitBase && !graphics_->GetSM3Support() && light->GetLightType() == LIGHT_POINT && light->GetCastShadows())
+    // On Shader Model 2 disable lit base optimization from shadowed lights when using high shadow quality due to the risk of
+    // exceeding pixel shader instruction count
+    if (allowLitBase && light->GetCastShadows() && !useShadowLitBase_)
         allowLitBase = false;
     
     for (unsigned i = 0; i < batches.Size(); ++i)

+ 2 - 0
Source/Engine/Graphics/View.h

@@ -304,6 +304,8 @@ private:
     bool deferredAmbient_;
     /// Forward light base pass optimization flag. If in use, combine the base pass and first light for all opaque objects.
     bool useLitBase_;
+    /// Forward light base pass optimization flag for shadowed lights. False on SM2 when using 4-sample shadow mapping.
+    bool useShadowLitBase_;
     /// Has scene passes flag. If no scene passes, view can be defined without a valid scene or camera to only perform quad rendering.
     bool hasScenePasses_;
     /// Renderpath.