Browse Source

Allow a pass to be marked as SM3-only, so that rendering limitations can be defined as data-driven instead of hardcoding in the engine. Moved specular disable for SM2 shadowed pointlight from code to shaders. Mention in the documentation that some materials may be too complex for SM2 and dynamic shadows.

Lasse Öörni 11 years ago
parent
commit
6bfcc28010

+ 5 - 0
Bin/CoreData/Shaders/HLSL/LitSolid.hlsl

@@ -5,6 +5,11 @@
 #include "Lighting.hlsl"
 #include "Lighting.hlsl"
 #include "Fog.hlsl"
 #include "Fog.hlsl"
 
 
+// When rendering a shadowed point light, disable specular calculations on Shader Model 2 to avoid exceeding the instruction limit
+#if !defined(SM3) && defined(SHADOW) && defined(POINTLIGHT)
+    #undef SPECULAR
+#endif
+
 void VS(float4 iPos : POSITION,
 void VS(float4 iPos : POSITION,
     float3 iNormal : NORMAL,
     float3 iNormal : NORMAL,
     float2 iTexCoord : TEXCOORD0,
     float2 iTexCoord : TEXCOORD0,

+ 5 - 0
Bin/CoreData/Shaders/HLSL/TerrainBlend.hlsl

@@ -5,6 +5,11 @@
 #include "Lighting.hlsl"
 #include "Lighting.hlsl"
 #include "Fog.hlsl"
 #include "Fog.hlsl"
 
 
+// When rendering a shadowed point light, disable specular calculations on Shader Model 2 to avoid exceeding the instruction limit
+#if !defined(SM3) && defined(SHADOW) && defined(POINTLIGHT)
+    #undef SPECULAR
+#endif
+
 sampler2D sWeightMap0 : register(S0);
 sampler2D sWeightMap0 : register(S0);
 sampler2D sDetailMap1 : register(S1);
 sampler2D sDetailMap1 : register(S1);
 sampler2D sDetailMap2 : register(S2);
 sampler2D sDetailMap2 : register(S2);

+ 1 - 1
Bin/CoreData/Techniques/DiffNormal.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/DiffNormalAlphaMask.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/DiffNormalPacked.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/DiffNormalPackedAlphaMask.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/DiffNormalPackedSpec.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL SPECMAP" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL SPECMAP" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/DiffNormalPackedSpecAlphaMask.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL SPECMAP" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL SPECMAP" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/DiffNormalSpec.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP SPECMAP" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP SPECMAP" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/DiffNormalSpecAlphaMask.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP SPECMAP" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP SPECMAP" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/NoTextureNormal.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid">
 <technique vs="LitSolid" ps="LitSolid">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />

+ 1 - 1
Bin/CoreData/Techniques/NoTextureNormalPacked.xml

@@ -1,6 +1,6 @@
 <technique vs="LitSolid" ps="LitSolid">
 <technique vs="LitSolid" ps="LitSolid">
     <pass name="base" />
     <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" />
+    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" sm3="true" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />

+ 4 - 4
Docs/Reference.dox

@@ -695,9 +695,9 @@ 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:
 %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.
 - Directional light shadows support a maximum of 3 cascade splits instead of 4.
-- 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.
 - Shadowed point lights do not support specular calculations in forward rendering.
-- Height fog is not supported.
+- Complex materials do not combine the ambient pass with the first forward light (lit base pass optimization.)
+- Complex forward rendered materials (eg. normal + specular map + alpha masking) combined with shadow mapping or height fog may not work.
 
 
 \section Rendering_Renderer Renderer
 \section Rendering_Renderer Renderer
 
 
@@ -939,7 +939,7 @@ A technique definition looks like this:
 
 
 \code
 \code
 <technique vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" sm3="false|true" >
 <technique vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" sm3="false|true" >
-    <pass name="base|litbase|light|alpha|litalpha|postopaque|refract|postalpha|prepass|material|deferred|depth|shadow"
+    <pass name="base|litbase|light|alpha|litalpha|postopaque|refract|postalpha|prepass|material|deferred|depth|shadow" sm3="false|true"
         vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4"
         vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4"
         lighting="unlit|pervertex|perpixel"
         lighting="unlit|pervertex|perpixel"
         blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha|subtract|subtractalpha"
         blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha|subtract|subtractalpha"
@@ -951,7 +951,7 @@ A technique definition looks like this:
 </technique>
 </technique>
 \endcode
 \endcode
 
 
-The sm3 attribute in the technique root element allows the technique to specify it requires %Shader %Model 3 hardware. Omitting it is same as specifying false (works on both SM2 & 3.)
+The sm3 attribute in the technique root element allows the technique to specify it requires %Shader %Model 3 hardware. Omitting it is same as specifying false (works on both SM2 & 3.) The sm3 attribute can also be specified per pass, to disable for example a too complex lit base optimization pass on SM2.
 
 
 Shaders are referred to by giving the name of a shader without path and file extension. For example "Basic" or "LitSolid". The engine will add the correct path and file extension (Shaders/HLSL/LitSolid.hlsl for Direct3D9, and Shaders/GLSL/LitSolid.glsl for OpenGL) automatically. The same shader source file contains both the vertex and pixel shader. In addition, compilation defines can be specified, which are passed to the shader compiler. For example the define "DIFFMAP" typically enables diffuse mapping in the pixel shader.
 Shaders are referred to by giving the name of a shader without path and file extension. For example "Basic" or "LitSolid". The engine will add the correct path and file extension (Shaders/HLSL/LitSolid.hlsl for Direct3D9, and Shaders/GLSL/LitSolid.glsl for OpenGL) automatically. The same shader source file contains both the vertex and pixel shader. In addition, compilation defines can be specified, which are passed to the shader compiler. For example the define "DIFFMAP" typically enables diffuse mapping in the pixel shader.
 
 

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

@@ -1046,8 +1046,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
     // Make sure shaders are loaded now
     // Make sure shaders are loaded now
     if (vertexShaders.Size() && pixelShaders.Size())
     if (vertexShaders.Size() && pixelShaders.Size())
     {
     {
-        // Height fog is not supported on Shader Model 2 due to possibly exceeding pixel shader instruction limit
-        bool heightFog = batch.zone_ && batch.zone_->GetHeightFog() && graphics_->GetSM3Support();
+        bool heightFog = batch.zone_ && batch.zone_->GetHeightFog();
         
         
         // If instancing is not supported, but was requested, or the object is too large to be instanced,
         // If instancing is not supported, but was requested, or the object is too large to be instanced,
         // choose static geometry vertex shader instead
         // choose static geometry vertex shader instead
@@ -1495,10 +1494,6 @@ void Renderer::LoadPassShaders(Technique* tech, StringHash type)
             unsigned l = j % MAX_LIGHT_PS_VARIATIONS;
             unsigned l = j % MAX_LIGHT_PS_VARIATIONS;
             unsigned h = 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)
             if (l & LPS_SHADOW)
             {
             {
                 pixelShaders[j] = graphics_->GetShader(PS, pass->GetPixelShader(), pass->GetPixelShaderDefines() + " " +
                 pixelShaders[j] = graphics_->GetShader(PS, pass->GetPixelShader(), pass->GetPixelShaderDefines() + " " +

+ 14 - 1
Source/Engine/Graphics/Technique.cpp

@@ -22,6 +22,7 @@
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "Context.h"
 #include "Context.h"
+#include "Graphics.h"
 #include "Log.h"
 #include "Log.h"
 #include "Technique.h"
 #include "Technique.h"
 #include "Profiler.h"
 #include "Profiler.h"
@@ -75,7 +76,8 @@ Pass::Pass(StringHash type) :
     lightingMode_(LIGHTING_UNLIT),
     lightingMode_(LIGHTING_UNLIT),
     shadersLoadedFrameNumber_(0),
     shadersLoadedFrameNumber_(0),
     depthWrite_(true),
     depthWrite_(true),
-    alphaMask_(false)
+    alphaMask_(false),
+    isSM3_(false)
 {
 {
     // Guess default lighting mode from pass name
     // Guess default lighting mode from pass name
     if (type == PASS_BASE || type == PASS_ALPHA || type == PASS_MATERIAL || type == PASS_DEFERRED)
     if (type == PASS_BASE || type == PASS_ALPHA || type == PASS_MATERIAL || type == PASS_DEFERRED)
@@ -113,6 +115,11 @@ void Pass::SetAlphaMask(bool enable)
     alphaMask_ = enable;
     alphaMask_ = enable;
 }
 }
 
 
+void Pass::SetIsSM3(bool enable)
+{
+    isSM3_ = enable;
+}
+
 void Pass::SetVertexShader(const String& name)
 void Pass::SetVertexShader(const String& name)
 {
 {
     vertexShaderName_ = name;
     vertexShaderName_ = name;
@@ -152,6 +159,8 @@ Technique::Technique(Context* context) :
     Resource(context),
     Resource(context),
     isSM3_(false)
     isSM3_(false)
 {
 {
+    Graphics* graphics = GetSubsystem<Graphics>();
+    sm3Support_ = graphics ? graphics->GetSM3Support() : true;
 }
 }
 
 
 Technique::~Technique()
 Technique::~Technique()
@@ -199,9 +208,13 @@ bool Technique::Load(Deserializer& source)
         if (passElem.HasAttribute("name"))
         if (passElem.HasAttribute("name"))
         {
         {
             StringHash nameHash(passElem.GetAttribute("name"));
             StringHash nameHash(passElem.GetAttribute("name"));
+            
             Pass* newPass = CreatePass(nameHash);
             Pass* newPass = CreatePass(nameHash);
             ++numPasses;
             ++numPasses;
             
             
+            if (passElem.HasAttribute("sm3"))
+                newPass->SetIsSM3(passElem.GetBool("sm3"));
+            
             // Append global defines only when pass does not redefine the shader
             // Append global defines only when pass does not redefine the shader
             if (passElem.HasAttribute("vs"))
             if (passElem.HasAttribute("vs"))
             {
             {

+ 16 - 0
Source/Engine/Graphics/Technique.h

@@ -58,6 +58,8 @@ public:
     void SetDepthWrite(bool enable);
     void SetDepthWrite(bool enable);
     /// Set alpha masking hint. Completely opaque draw calls will be performed before alpha masked.
     /// Set alpha masking hint. Completely opaque draw calls will be performed before alpha masked.
     void SetAlphaMask(bool enable);
     void SetAlphaMask(bool enable);
+    /// Set whether requires %Shader %Model 3.
+    void SetIsSM3(bool enable);
     /// Set vertex shader name.
     /// Set vertex shader name.
     void SetVertexShader(const String& name);
     void SetVertexShader(const String& name);
     /// Set pixel shader name.
     /// Set pixel shader name.
@@ -85,6 +87,8 @@ public:
     bool GetDepthWrite() const { return depthWrite_; }
     bool GetDepthWrite() const { return depthWrite_; }
     /// Return alpha masking hint.
     /// Return alpha masking hint.
     bool GetAlphaMask() const { return alphaMask_; }
     bool GetAlphaMask() const { return alphaMask_; }
+    /// Return whether requires %Shader %Model 3.
+    bool IsSM3() const { return isSM3_; }
     /// Return vertex shader name.
     /// Return vertex shader name.
     const String& GetVertexShader() const { return vertexShaderName_; }
     const String& GetVertexShader() const { return vertexShaderName_; }
     /// Return pixel shader name.
     /// Return pixel shader name.
@@ -113,6 +117,8 @@ private:
     bool depthWrite_;
     bool depthWrite_;
     /// Alpha masking hint.
     /// Alpha masking hint.
     bool alphaMask_;
     bool alphaMask_;
+    /// Require %Shader %Model 3 flag.
+    bool isSM3_;
     /// Vertex shader name.
     /// Vertex shader name.
     String vertexShaderName_;
     String vertexShaderName_;
     /// Pixel shader name.
     /// Pixel shader name.
@@ -166,9 +172,19 @@ public:
         return passPtr ? passPtr->Get() : 0;
         return passPtr ? passPtr->Get() : 0;
     }
     }
     
     
+    /// Return a pass that is supported for rendering, or null if not found.
+    Pass* GetSupportedPass(StringHash type) const
+    {
+        SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
+        Pass* pass = passPtr ? passPtr->Get() : 0;
+        return pass && (!pass->IsSM3() || sm3Support_) ? pass : 0;
+    }
+    
 private:
 private:
     /// Require %Shader %Model 3 flag.
     /// Require %Shader %Model 3 flag.
     bool isSM3_;
     bool isSM3_;
+    /// Cached %Shader %Model 3 support flag.
+    bool sm3Support_;
     /// Passes.
     /// Passes.
     HashTable<SharedPtr<Pass>, 16> passes_;
     HashTable<SharedPtr<Pass>, 16> passes_;
 };
 };

+ 7 - 12
Source/Engine/Graphics/View.cpp

@@ -403,8 +403,7 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
     deferred_ = false;
     deferred_ = false;
     deferredAmbient_ = false;
     deferredAmbient_ = false;
     useLitBase_ = false;
     useLitBase_ = false;
-    useShadowLitBase_ = graphics_->GetSM3Support() || renderer_->GetShadowQuality() < SHADOWQUALITY_HIGH_16BIT;
-    
+
     for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
     for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
     {
     {
         const RenderPathCommand& command = renderPath_->commands_[i];
         const RenderPathCommand& command = renderPath_->commands_[i];
@@ -881,7 +880,7 @@ void View::GetBatches()
                             if (!srcBatch.geometry_ || !srcBatch.numWorldTransforms_ || !tech)
                             if (!srcBatch.geometry_ || !srcBatch.numWorldTransforms_ || !tech)
                                 continue;
                                 continue;
                             
                             
-                            Pass* pass = tech->GetPass(PASS_SHADOW);
+                            Pass* pass = tech->GetSupportedPass(PASS_SHADOW);
                             // Skip if material has no shadow pass
                             // Skip if material has no shadow pass
                             if (!pass)
                             if (!pass)
                                 continue;
                                 continue;
@@ -1002,7 +1001,7 @@ void View::GetBatches()
                 for (unsigned k = 0; k < scenePasses_.Size(); ++k)
                 for (unsigned k = 0; k < scenePasses_.Size(); ++k)
                 {
                 {
                     ScenePassInfo& info = scenePasses_[k];
                     ScenePassInfo& info = scenePasses_[k];
-                    destBatch.pass_ = tech->GetPass(info.pass_);
+                    destBatch.pass_ = tech->GetSupportedPass(info.pass_);
                     if (!destBatch.pass_)
                     if (!destBatch.pass_)
                         continue;
                         continue;
                     
                     
@@ -1168,10 +1167,6 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQ
     bool allowTransparentShadows = !renderer_->GetReuseShadowMaps();
     bool allowTransparentShadows = !renderer_->GetReuseShadowMaps();
     bool allowLitBase = useLitBase_ && !light->IsNegative() && light == drawable->GetFirstLight() &&
     bool allowLitBase = useLitBase_ && !light->IsNegative() && light == drawable->GetFirstLight() &&
         drawable->GetVertexLights().Empty() && !hasAmbientGradient;
         drawable->GetVertexLights().Empty() && !hasAmbientGradient;
-    // 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)
     for (unsigned i = 0; i < batches.Size(); ++i)
     {
     {
@@ -1192,22 +1187,22 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQ
         // Also vertex lighting or ambient gradient require the non-lit base pass, so skip in those cases
         // Also vertex lighting or ambient gradient require the non-lit base pass, so skip in those cases
         if (i < 32 && allowLitBase)
         if (i < 32 && allowLitBase)
         {
         {
-            destBatch.pass_ = tech->GetPass(litBasePassName_);
+            destBatch.pass_ = tech->GetSupportedPass(litBasePassName_);
             if (destBatch.pass_)
             if (destBatch.pass_)
             {
             {
                 destBatch.isBase_ = true;
                 destBatch.isBase_ = true;
                 drawable->SetBasePass(i);
                 drawable->SetBasePass(i);
             }
             }
             else
             else
-                destBatch.pass_ = tech->GetPass(lightPassName_);
+                destBatch.pass_ = tech->GetSupportedPass(lightPassName_);
         }
         }
         else
         else
-            destBatch.pass_ = tech->GetPass(lightPassName_);
+            destBatch.pass_ = tech->GetSupportedPass(lightPassName_);
         
         
         // If no lit pass, check for lit alpha
         // If no lit pass, check for lit alpha
         if (!destBatch.pass_)
         if (!destBatch.pass_)
         {
         {
-            destBatch.pass_ = tech->GetPass(litAlphaPassName_);
+            destBatch.pass_ = tech->GetSupportedPass(litAlphaPassName_);
             isLitAlpha = true;
             isLitAlpha = true;
         }
         }
         
         

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

@@ -304,8 +304,6 @@ private:
     bool deferredAmbient_;
     bool deferredAmbient_;
     /// Forward light base pass optimization flag. If in use, combine the base pass and first light for all opaque objects.
     /// Forward light base pass optimization flag. If in use, combine the base pass and first light for all opaque objects.
     bool useLitBase_;
     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.
     /// 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_;
     bool hasScenePasses_;
     /// Renderpath.
     /// Renderpath.

+ 2 - 0
Source/Engine/LuaScript/pkgs/Graphics/Technique.pkg

@@ -9,6 +9,8 @@ enum PassLightingMode
 
 
 class Pass : public RefCounted
 class Pass : public RefCounted
 {
 {
+    bool IsSM3() const;
+    tolua_readonly tolua_property__is_set bool SM3;
 };
 };
 
 
 class Technique : public Resource
 class Technique : public Resource

+ 2 - 0
Source/Engine/Script/GraphicsAPI.cpp

@@ -607,6 +607,8 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Pass", "bool get_depthWrite() const", asMETHOD(Pass, GetDepthWrite), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_depthWrite() const", asMETHOD(Pass, GetDepthWrite), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_alphaMask(bool)", asMETHOD(Pass, SetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_alphaMask(bool)", asMETHOD(Pass, SetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_alphaMask() const", asMETHOD(Pass, GetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_alphaMask() const", asMETHOD(Pass, GetAlphaMask), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pass", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pass", "bool get_sm3() const", asMETHOD(Technique, IsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_vertexShader(const String&in)", asMETHOD(Pass, SetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_vertexShader(const String&in)", asMETHOD(Pass, SetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "const String& get_vertexShader() const", asMETHOD(Pass, GetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "const String& get_vertexShader() const", asMETHOD(Pass, GetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_pixelShader(const String&in)", asMETHOD(Pass, SetPixelShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_pixelShader(const String&in)", asMETHOD(Pass, SetPixelShader), asCALL_THISCALL);