Browse Source

Re-enabled lit base pass optimization, with more careful checks to ensure proper rendering order.
Fixed temporal AA shader GLSL syntax for ATI GPUs.
Code cleanup.

Lasse Öörni 14 years ago
parent
commit
80aee649df

+ 1 - 0
Bin/CoreData/Techniques/Diff.xml

@@ -1,6 +1,7 @@
 <technique>
     <pass name="gbuffer" vs="GBuffer" ps="GBuffer_Diff" />
     <pass name="base" vs="Forward" ps="Forward_DiffAmbient" />
+    <pass name="litbase" vs="Forward" ps="Forward_DiffAmbient" />
     <pass name="light" vs="Forward" ps="Forward_Diff" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>

+ 1 - 0
Bin/CoreData/Techniques/DiffAlphaMask.xml

@@ -1,6 +1,7 @@
 <technique>
     <pass name="gbuffer" vs="GBuffer" ps="GBuffer_DiffMask" alphamask="true" />
     <pass name="base" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
+    <pass name="litbase" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
     <pass name="light" vs="Forward" ps="Forward_Diff" alphatest="true" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow_Mask" ps="Shadow_Mask" alphamask="true" />
 </technique>

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

@@ -1,6 +1,7 @@
 <technique>
     <pass name="gbuffer" vs="GBuffer_Normal" ps="GBuffer_DiffNormal" />
     <pass name="base" vs="Forward" ps="Forward_DiffAmbient" />
+    <pass name="litbase" vs="Forward_Normal" ps="Forward_DiffNormalAmbient" />
     <pass name="light" vs="Forward_Normal" ps="Forward_DiffNormal" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>

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

@@ -1,5 +1,6 @@
 <technique>
     <pass name="base" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
+    <pass name="litbase" vs="Forward_Normal" ps="Forward_DiffNormalAmbient" alphatest="true" />
     <pass name="light" vs="Forward_Normal" ps="Forward_DiffNormal" alphatest="true" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow_Mask" ps="Shadow_Mask" alphamask="true" />
 </technique>

+ 1 - 0
Bin/CoreData/Techniques/NoTexture.xml

@@ -1,6 +1,7 @@
 <technique>
     <pass name="gbuffer" vs="GBuffer" ps="GBuffer" />
     <pass name="base" vs="Forward" ps="Forward_Ambient" />
+    <pass name="litbase" vs="Forward" ps="Forward_Ambient" />
     <pass name="light" vs="Forward" ps="Forward" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>

+ 1 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -274,6 +274,7 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterEnum("PassType");
     engine->RegisterEnumValue("PassType", "PASS_GBUFFER", PASS_GBUFFER);
     engine->RegisterEnumValue("PassType", "PASS_BASE", PASS_BASE);
+    engine->RegisterEnumValue("PassType", "PASS_LITBASE", PASS_LITBASE);
     engine->RegisterEnumValue("PassType", "PASS_LIGHT", PASS_LIGHT);
     engine->RegisterEnumValue("PassType", "PASS_EXTRA", PASS_EXTRA);
     engine->RegisterEnumValue("PassType", "PASS_SHADOW", PASS_SHADOW);

+ 3 - 3
Engine/Graphics/Batch.cpp

@@ -410,10 +410,10 @@ void BatchGroup::Draw(Graphics* graphics, VertexBuffer* instanceBuffer, const Ha
         Vector<SharedPtr<ShaderVariation> >& vertexShaders = pass_->GetVertexShaders();
         Vector<SharedPtr<ShaderVariation> >& pixelShaders = pass_->GetPixelShaders();
         PassType type = pass_->GetType();
-        if (type != PASS_LIGHT)
-            batch.vertexShader_ = vertexShaders[vertexShaderIndex_ + GEOM_INSTANCED];
-        else
+        if (type == PASS_LIGHT || type == PASS_LITBASE)
             batch.vertexShader_ = vertexShaders[vertexShaderIndex_ + GEOM_INSTANCED * MAX_LIGHT_VS_VARIATIONS];
+        else
+            batch.vertexShader_ = vertexShaders[vertexShaderIndex_ + GEOM_INSTANCED];
         
         batch.Prepare(graphics, shaderParameters, false);
         

+ 3 - 7
Engine/Graphics/Direct3D9/D3D9Shader.cpp

@@ -151,12 +151,8 @@ ShaderVariation* Shader::GetVariation(const String& name)
 {
     StringHash nameHash(name);
     Map<StringHash, SharedPtr<ShaderVariation> >::Iterator i = variations_.Find(nameHash);
-    if (i == variations_.End())
-    {
-        LOGERROR("Could not find shader variation " + GetFileName(GetName()) + "_" + name);
-        variations_[nameHash] = 0; // Store a null pointer so that the error is printed only once
-        return 0;
-    }
-    else
+    if (i != variations_.End())
         return i->second_;
+    else
+        return 0;
 }

+ 9 - 2
Engine/Graphics/Drawable.cpp

@@ -55,6 +55,7 @@ Drawable::Drawable(Context* context) :
     lodDistance_(0.0f),
     sortValue_(0.0f),
     viewFrameNumber_(0),
+    basePassFlags_(0),
     viewCamera_(0),
     worldBoundingBoxDirty_(true),
     lodLevelsDirty_(true)
@@ -184,11 +185,17 @@ void Drawable::SetSortValue(float value)
     sortValue_ = value;
 }
 
-void Drawable::ClearLights()
+void Drawable::ClearBasePass()
 {
+    basePassFlags_ = 0;
     lights_.Clear();
 }
 
+void Drawable::SetBasePass(unsigned batchIndex)
+{
+    basePassFlags_ |= (1 << batchIndex);
+}
+
 void Drawable::AddLight(Light* light)
 {
     lights_.Push(light);
@@ -200,7 +207,7 @@ void Drawable::LimitLights()
     
     const Vector3& worldPos = GetWorldPosition();
     for (unsigned i = 0; i < lights_.Size(); ++i)
-        lights_[i]->SetIntensitySortValue(worldPos);
+        lights_[i]->SetIntensitySortValue(worldPos, true);
     
     Sort(lights_.Begin(), lights_.End(), CompareDrawables);
     

+ 8 - 2
Engine/Graphics/Drawable.h

@@ -142,8 +142,10 @@ public:
     void MarkInView(const FrameInfo& frame);
     /// Mark in a shadow camera view this frame. If an actual view is already set, does not override it. Called by View.
     void MarkInShadowView(const FrameInfo& frame);
-    /// Clear light vector.
-    void ClearLights();
+    /// Clear base pass flags. Also resets light vector.
+    void ClearBasePass();
+    /// %Set base pass flag for a batch.
+    void SetBasePass(unsigned batchIndex);
     /// Add a light, for drawables that limit the maximum light count.
     void AddLight(Light* light);
     /// Sort and limit lights to maximum allowed.
@@ -158,6 +160,8 @@ public:
     bool IsInView(unsigned frameNumber) const;
     /// Return whether is visible in a specific view this frame.
     bool IsInView(const FrameInfo& frame) const;
+    /// Return whether has a base pass.
+    bool HasBasePass(unsigned batchIndex) const { return (basePassFlags_ & (1 << batchIndex)) != 0; }
     /// Return lights.
     const PODVector<Light*>& GetLights() const { return lights_; }
     
@@ -207,6 +211,8 @@ protected:
     float sortValue_;
     /// Last visible frame number.
     unsigned viewFrameNumber_;
+    /// Base pass flags per batch index.
+    unsigned basePassFlags_;
     /// Last camera rendered from. Not safe to dereference.
     Camera* viewCamera_;
     /// Lights affecting this drawable, when light count is limited.

+ 1 - 0
Engine/Graphics/GraphicsDefs.h

@@ -174,6 +174,7 @@ enum PassType
 {
     PASS_GBUFFER,
     PASS_BASE,
+    PASS_LITBASE,
     PASS_LIGHT,
     PASS_EXTRA,
     PASS_SHADOW,

+ 5 - 2
Engine/Graphics/Light.cpp

@@ -480,12 +480,15 @@ void Light::SetShadowMap(Texture2D* shadowMap)
     shadowMap_ = shadowMap;
 }
 
-void Light::SetIntensitySortValue(const Vector3& position)
+void Light::SetIntensitySortValue(const Vector3& position, bool forDrawable)
 {
     // Directional lights are always assumed to be "infinitely" close, while point and spot lights take distance into account
     float invIntensity = 1.0f / color_.Intensity();
     if (lightType_ == LIGHT_DIRECTIONAL)
-        sortValue_ = invIntensity;
+        // If sorting lights for a drawable's maximum lights sorting, use the actual intensity
+        // Else (when sorting lights globally for the view) ensure directional lights always have a fixed first priority
+        // so that the combined ambient + first light optimization works as expected
+        sortValue_ = forDrawable ? invIntensity : 0.0f;
     else
         sortValue_ = invIntensity * (1.0f + (GetWorldPosition() - position).LengthFast() / range_);
 }

+ 1 - 1
Engine/Graphics/Light.h

@@ -234,7 +234,7 @@ public:
     /// %Set shadow map depth texture.
     void SetShadowMap(Texture2D* shadowMap);
     /// %Set sort value based on intensity at given world position.
-    void SetIntensitySortValue(const Vector3& position);
+    void SetIntensitySortValue(const Vector3& position, bool forDrawable = false);
     /// Copy values from another light.
     void CopyFrom(Light* original);
     /// Return near split distance.

+ 3 - 7
Engine/Graphics/OpenGL/OGLShader.cpp

@@ -99,13 +99,9 @@ ShaderVariation* Shader::GetVariation(const String& name)
 {
     StringHash nameHash(name);
     Map<StringHash, SharedPtr<ShaderVariation> >::Iterator i = variations_.Find(nameHash);
-    if (i == variations_.End())
-    {
-        LOGERROR("Could not find shader variation " + GetFileName(GetName()) + "_" + name);
-        variations_[nameHash] = 0; // Store a null pointer so that the error is printed only once
-        return 0;
-    }
-    else
+    if (i != variations_.End())
         return i->second_;
+    else
+        return 0;
 }
 

+ 33 - 39
Engine/Graphics/Renderer.cpp

@@ -222,34 +222,34 @@ static const String lightPSVariations[] =
 {
     "Dir",
     "DirSpec",
-    "DirShadow",
-    "DirShadowSpec",
     "Spot",
     "SpotSpec",
-    "SpotShadow",
-    "SpotShadowSpec",
     "Point",
     "PointSpec",
-    "PointShadow",
-    "PointShadowSpec",
     "PointMask",
     "PointMaskSpec",
+    "DirShadow",
+    "DirShadowSpec",
+    "SpotShadow",
+    "SpotShadowSpec",
+    "PointShadow",
+    "PointShadowSpec",
     "PointMaskShadow",
     "PointMaskShadowSpec",
     "OrthoDir",
     "OrthoDirSpec",
-    "OrthoDirShadow",
-    "OrthoDirShadowSpec",
     "OrthoSpot",
     "OrthoSpotSpec",
-    "OrthoSpotShadow",
-    "OrthoSpotShadowSpec",
     "OrthoPoint",
     "OrthoPointSpec",
-    "OrthoPointShadow",
-    "OrthoPointShadowSpec",
     "OrthoPointMask",
     "OrthoPointMaskSpec",
+    "OrthoDirShadow",
+    "OrthoDirShadowSpec",
+    "OrthoSpotShadow",
+    "OrthoSpotShadowSpec",
+    "OrthoPointShadow",
+    "OrthoPointShadowSpec",
     "OrthoPointMaskShadow",
     "OrthoPointMaskShadowSpec"
 };
@@ -623,11 +623,6 @@ void Renderer::Render()
     for (unsigned i = numViews_ - 1; i < numViews_; --i)
         views_[i]->Render();
     
-    // Disable scissor/stencil tests if left on by lights, and reset stream frequencies
-    graphics_->SetScissorTest(false);
-    graphics_->SetStencilTest(false);
-    graphics_->ResetStreamFrequencies();
-    
     // Copy the number of batches & primitives from Graphics so that we can account for 3D geometry only
     numPrimitives_ = graphics_->GetNumPrimitives();
     numBatches_ = graphics_->GetNumBatches();
@@ -886,14 +881,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, b
     {
         //  Check whether is a forward lit pass. If not, there is only one pixel shader
         PassType type = pass->GetType();
-        if (type != PASS_LIGHT)
-        {
-            unsigned vsi = batch.geometryType_;
-            batch.vertexShader_ = vertexShaders[vsi];
-            batch.pixelShader_ = pixelShaders[0];
-            batch.vertexShaderIndex_ = vsi;
-        }
-        else
+        if (type == PASS_LIGHT || type == PASS_LITBASE)
         {
             Light* light = batch.light_;
             if (!light)
@@ -937,6 +925,13 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, b
             batch.pixelShader_ = pixelShaders[psi];
             batch.vertexShaderIndex_ = vsi;
         }
+        else
+        {
+            unsigned vsi = batch.geometryType_;
+            batch.vertexShader_ = vertexShaders[vsi];
+            batch.pixelShader_ = pixelShaders[0];
+            batch.vertexShaderIndex_ = vsi;
+        }
     }
     
     batch.CalculateSortKey();
@@ -1024,10 +1019,9 @@ void Renderer::LoadShaders()
         
         for (unsigned i = 0; i < MAX_DEFERRED_LIGHT_PS_VARIATIONS; ++i)
         {
-            unsigned variation = i % DLPS_SPOT;
             unsigned linear = !graphics_->GetHardwareDepthSupport() && i < DLPS_ORTHO ? 1 : 0;
             
-            if (variation == DLPS_SHADOW || variation == DLPS_SHADOWSPEC)
+            if (i & DLPS_SHADOW)
                 lightPS_[i] = GetPixelShader("Light_" + linearVariations[linear] + lightPSVariations[i] + hwVariations[hwShadows]);
             else
                 lightPS_[i] = GetPixelShader("Light_" + linearVariations[linear] + lightPSVariations[i]);
@@ -1049,6 +1043,7 @@ void Renderer::LoadMaterialShaders(Technique* technique)
     if (mode == RENDER_FORWARD)
     {
         LoadPassShaders(technique, PASS_BASE);
+        LoadPassShaders(technique, PASS_LITBASE);
         LoadPassShaders(technique, PASS_LIGHT);
     }
     else
@@ -1059,6 +1054,7 @@ void Renderer::LoadMaterialShaders(Technique* technique)
         {
             LoadPassShaders(technique, PASS_BASE);
             // If shadow maps are not reused, forward lighting in deferred mode can render shadows
+            LoadPassShaders(technique, PASS_LITBASE, !reuseShadowMaps_);
             LoadPassShaders(technique, PASS_LIGHT, !reuseShadowMaps_);
         }
     }
@@ -1080,20 +1076,12 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
         pixelShaderName += "_";
     
     // If INTZ depth is used, do not write depth into a rendertarget in the G-buffer pass
-    // Also check for fallback G-buffer (different layout)
     if (type == PASS_GBUFFER)
     {
         unsigned depth = graphics_->GetHardwareDepthSupport() ? 0 : 1;
         pixelShaderName += depthVariations[depth];
     }
 
-    // If ambient pass is transparent, and shadow maps are reused, do not load shadow variations
-    if (reuseShadowMaps_ && type == PASS_LIGHT)
-    {
-        if (!technique->HasPass(PASS_BASE) || technique->GetPass(PASS_BASE)->GetBlendMode() != BLEND_REPLACE)
-            allowShadows = false;
-    }
-    
     unsigned hwShadows = graphics_->GetHardwareShadowSupport() ? 1 : 0;
     
     Vector<SharedPtr<ShaderVariation> >& vertexShaders = pass->GetVertexShaders();
@@ -1103,11 +1091,18 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
     vertexShaders.Clear();
     pixelShaders.Clear();
     
-    if (type == PASS_LIGHT)
+    if (type == PASS_LIGHT || type == PASS_LITBASE)
     {
+        // If ambient pass is transparent, and shadow maps are reused, do not load shadow variations
+        if (reuseShadowMaps_)
+        {
+            if (!technique->HasPass(PASS_BASE) || technique->GetPass(PASS_BASE)->GetBlendMode() != BLEND_REPLACE)
+                allowShadows = false;
+        }
+        
         vertexShaders.Resize(MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS);
         pixelShaders.Resize(MAX_LIGHT_PS_VARIATIONS);
-            
+        
         for (unsigned j = 0; j < MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS; ++j)
         {
             unsigned g = j / MAX_LIGHT_VS_VARIATIONS;
@@ -1119,8 +1114,7 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
         }
         for (unsigned j = 0; j < MAX_LIGHT_PS_VARIATIONS; ++j)
         {
-            unsigned variation = j % LPS_SPOT;
-            if (variation == LPS_SHADOW || variation == LPS_SHADOWSPEC)
+            if (j & LPS_SHADOW)
             {
                 if (allowShadows)
                     pixelShaders[j] = GetPixelShader(pixelShaderName + lightPSVariations[j] + hwVariations[hwShadows]);

+ 18 - 18
Engine/Graphics/Renderer.h

@@ -66,18 +66,18 @@ enum LightPSVariation
 {
     LPS_NONE = 0,
     LPS_SPEC,
-    LPS_SHADOW,
-    LPS_SHADOWSPEC,
     LPS_SPOT,
     LPS_SPOTSPEC,
-    LPS_SPOTSHADOW,
-    LPS_SPOTSHADOWSPEC,
     LPS_POINT,
     LPS_POINTSPEC,
-    LPS_POINTSHADOW,
-    LPS_POINTSHADOWSPEC,
     LPS_POINTMASK,
     LPS_POINTMASKSPEC,
+    LPS_SHADOW,
+    LPS_SHADOWSPEC,
+    LPS_SPOTSHADOW,
+    LPS_SPOTSHADOWSPEC,
+    LPS_POINTSHADOW,
+    LPS_POINTSHADOWSPEC,
     LPS_POINTMASKSHADOW,
     LPS_POINTMASKSHADOWSPEC,
     MAX_LIGHT_PS_VARIATIONS
@@ -98,34 +98,34 @@ enum DeferredLightPSVariation
 {
     DLPS_NONE = 0,
     DLPS_SPEC,
-    DLPS_SHADOW,
-    DLPS_SHADOWSPEC,
     DLPS_SPOT,
     DLPS_SPOTSPEC,
-    DLPS_SPOTSHADOW,
-    DLPS_SPOTSHADOWSPEC,
     DLPS_POINT,
     DLPS_POINTSPEC,
-    DLPS_POINTSHADOW,
-    DLPS_POINTSHADOWSPEC,
     DLPS_POINTMASK,
     DLPS_POINTMASKSPEC,
+    DLPS_SHADOW,
+    DLPS_SHADOWSPEC,
+    DLPS_SPOTSHADOW,
+    DLPS_SPOTSHADOWSPEC,
+    DLPS_POINTSHADOW,
+    DLPS_POINTSHADOWSPEC,
     DLPS_POINTMASKSHADOW,
     DLPS_POINTMASKSHADOWSPEC,
     DLPS_ORTHO,
     DLPS_ORTHOSPEC,
-    DLPS_ORTHOSHADOW,
-    DLPS_ORTHOSHADOWSPEC,
     DLPS_ORTHOSPOT,
     DLPS_ORTHOSPOTSPEC,
-    DLPS_ORTHOSPOTSHADOW,
-    DLPS_ORTHOSPOTSHADOWSPEC,
     DLPS_ORTHOPOINT,
     DLPS_ORTHOPOINTSPEC,
-    DLPS_ORTHOPOINTSHADOW,
-    DLPS_ORTHOPOINTSHADOWSPEC,
     DLPS_ORTHOPOINTMASK,
     DLPS_ORTHOPOINTMASKSPEC,
+    DLPS_ORTHOSHADOW,
+    DLPS_ORTHOSHADOWSPEC,
+    DLPS_ORTHOSPOTSHADOW,
+    DLPS_ORTHOSPOTSHADOWSPEC,
+    DLPS_ORTHOPOINTSHADOW,
+    DLPS_ORTHOPOINTSHADOWSPEC,
     DLPS_ORTHOPOINTMASKSHADOW,
     DLPS_ORTHOPOINTMASKSHADOWSPEC,
     MAX_DEFERRED_LIGHT_PS_VARIATIONS

+ 1 - 0
Engine/Graphics/Technique.cpp

@@ -35,6 +35,7 @@ static const String passNames[] =
 {
     "gbuffer",
     "base",
+    "litbase",
     "light",
     "extra",
     "shadow",

+ 126 - 106
Engine/Graphics/View.cpp

@@ -227,6 +227,8 @@ void View::Render()
         graphics_->SetViewTexture(0);
     
     graphics_->SetFillMode(FILL_SOLID);
+    graphics_->SetScissorTest(false);
+    graphics_->SetStencilTest(false);
     
     // Calculate view-global shader parameters
     CalculateShaderParameters();
@@ -248,6 +250,9 @@ void View::Render()
         RenderBatchesDeferred();
     
     graphics_->SetViewTexture(0);
+    graphics_->SetScissorTest(false);
+    graphics_->SetStencilTest(false);
+    graphics_->ResetStreamFrequencies();
     
     // If this is a main view, draw the associated debug geometry now
     if (!renderTarget_)
@@ -348,7 +353,7 @@ void View::GetDrawables()
         unsigned flags = drawable->GetDrawableFlags();
         if (flags & DRAWABLE_GEOMETRY)
         {
-            drawable->ClearLights();
+            drawable->ClearBasePass();
             drawable->MarkInView(frame_);
             drawable->UpdateGeometry(frame_);
             
@@ -392,87 +397,6 @@ void View::GetBatches()
     HashSet<Drawable*> maxLightsDrawables;
     Map<Light*, unsigned> lightQueueIndex;
     
-    // Go through geometries for base pass batches
-    {
-        PROFILE(GetBaseBatches);
-        for (unsigned i = 0; i < geometries_.Size(); ++i)
-        {
-            Drawable* drawable = geometries_[i];
-            unsigned numBatches = drawable->GetNumBatches();
-            
-            for (unsigned j = 0; j < numBatches; ++j)
-            {
-                Batch baseBatch;
-                drawable->GetBatch(frame_, j, baseBatch);
-                
-                Technique* tech = GetTechnique(drawable, baseBatch.material_);
-                if (!baseBatch.geometry_ || !tech)
-                    continue;
-                
-                // Check here if the material technique refers to a render target texture with camera(s) attached
-                // Only check this for the main view (null rendertarget)
-                if (!renderTarget_ && baseBatch.material_ && baseBatch.material_->GetAuxViewFrameNumber() != frame_.frameNumber_)
-                    CheckMaterialForAuxView(baseBatch.material_);
-                
-                // Fill the rest of the batch
-                baseBatch.camera_ = camera_;
-                baseBatch.distance_ = drawable->GetDistance();
-                
-                Pass* pass = 0;
-                // In deferred mode, check for a G-buffer batch first
-                if (mode_ != RENDER_FORWARD)
-                {
-                    pass = tech->GetPass(PASS_GBUFFER);
-                    if (pass)
-                    {
-                        renderer_->SetBatchShaders(baseBatch, tech, pass);
-                        baseBatch.hasPriority_ = !pass->GetAlphaTest() && !pass->GetAlphaMask();
-                        gBufferQueue_.AddBatch(baseBatch);
-                        
-                        // Check also for an additional pass (possibly for emissive)
-                        pass = tech->GetPass(PASS_EXTRA);
-                        if (pass)
-                        {
-                            renderer_->SetBatchShaders(baseBatch, tech, pass);
-                            baseQueue_.AddBatch(baseBatch);
-                        }
-                        
-                        continue;
-                    }
-                }
-                
-                // Then check for forward rendering base pass
-                pass = tech->GetPass(PASS_BASE);
-                if (pass)
-                {
-                    renderer_->SetBatchShaders(baseBatch, tech, pass);
-                    if (pass->GetBlendMode() == BLEND_REPLACE)
-                    {
-                        baseBatch.hasPriority_ = !pass->GetAlphaTest() && !pass->GetAlphaMask();
-                        baseQueue_.AddBatch(baseBatch);
-                    }
-                    else
-                    {
-                        baseBatch.hasPriority_ = true;
-                        transparentQueue_.AddBatch(baseBatch, true);
-                    }
-                    continue;
-                }
-                else
-                {
-                    // If no base pass, finally check for extra / custom pass
-                    pass = tech->GetPass(PASS_EXTRA);
-                    if (pass)
-                    {
-                        baseBatch.hasPriority_ = false;
-                        renderer_->SetBatchShaders(baseBatch, tech, pass);
-                        extraQueue_.AddBatch(baseBatch);
-                    }
-                }
-            }
-        }
-    }
-    
     // Go through lights
     {
         PROFILE_MULTIPLE(GetLightBatches, lights_.Size());
@@ -618,6 +542,91 @@ void View::GetBatches()
         }
     }
     
+    // Go through geometries for base pass batches
+    {
+        PROFILE(GetBaseBatches);
+        for (unsigned i = 0; i < geometries_.Size(); ++i)
+        {
+            Drawable* drawable = geometries_[i];
+            unsigned numBatches = drawable->GetNumBatches();
+            
+            for (unsigned j = 0; j < numBatches; ++j)
+            {
+                Batch baseBatch;
+                drawable->GetBatch(frame_, j, baseBatch);
+                
+                Technique* tech = GetTechnique(drawable, baseBatch.material_);
+                if (!baseBatch.geometry_ || !tech)
+                    continue;
+                
+                // Check here if the material technique refers to a render target texture with camera(s) attached
+                // Only check this for the main view (null rendertarget)
+                if (!renderTarget_ && baseBatch.material_ && baseBatch.material_->GetAuxViewFrameNumber() != frame_.frameNumber_)
+                    CheckMaterialForAuxView(baseBatch.material_);
+                
+                // If object already has a lit base pass, can skip the unlit base pass
+                if (drawable->HasBasePass(j))
+                    continue;
+                
+                // Fill the rest of the batch
+                baseBatch.camera_ = camera_;
+                baseBatch.distance_ = drawable->GetDistance();
+                
+                Pass* pass = 0;
+                // In deferred mode, check for a G-buffer batch first
+                if (mode_ != RENDER_FORWARD)
+                {
+                    pass = tech->GetPass(PASS_GBUFFER);
+                    if (pass)
+                    {
+                        renderer_->SetBatchShaders(baseBatch, tech, pass);
+                        baseBatch.hasPriority_ = !pass->GetAlphaTest() && !pass->GetAlphaMask();
+                        gBufferQueue_.AddBatch(baseBatch);
+                        
+                        // Check also for an additional pass (possibly for emissive)
+                        pass = tech->GetPass(PASS_EXTRA);
+                        if (pass)
+                        {
+                            renderer_->SetBatchShaders(baseBatch, tech, pass);
+                            baseQueue_.AddBatch(baseBatch);
+                        }
+                        
+                        continue;
+                    }
+                }
+                
+                // Then check for forward rendering base pass
+                pass = tech->GetPass(PASS_BASE);
+                if (pass)
+                {
+                    renderer_->SetBatchShaders(baseBatch, tech, pass);
+                    if (pass->GetBlendMode() == BLEND_REPLACE)
+                    {
+                        baseBatch.hasPriority_ = !pass->GetAlphaTest() && !pass->GetAlphaMask();
+                        baseQueue_.AddBatch(baseBatch);
+                    }
+                    else
+                    {
+                        baseBatch.hasPriority_ = true;
+                        transparentQueue_.AddBatch(baseBatch, true);
+                    }
+                    continue;
+                }
+                else
+                {
+                    // If no base pass, finally check for extra / custom pass
+                    pass = tech->GetPass(PASS_EXTRA);
+                    if (pass)
+                    {
+                        baseBatch.hasPriority_ = false;
+                        renderer_->SetBatchShaders(baseBatch, tech, pass);
+                        extraQueue_.AddBatch(baseBatch);
+                    }
+                }
+            }
+        }
+    }
+    
     // All batches have been collected. Sort them now
     SortBatches();
 }
@@ -645,8 +654,22 @@ void View::GetLitBatches(Drawable* drawable, Light* light, Light* splitLight, Li
         
         Pass* pass = 0;
         bool priority = false;
-         
-        // Get lit pass
+        
+        // For the (first) directional light, check for lit base pass
+        if (light == lights_[0] && splitLight->GetLightType() == LIGHT_DIRECTIONAL)
+        {
+            if (!drawable->HasBasePass(i))
+            {
+                pass = tech->GetPass(PASS_LITBASE);
+                if (pass)
+                {
+                    priority = true;
+                    drawable->SetBasePass(i);
+                }
+            }
+        }
+        
+        // If no lit base pass, get ordinary light pass
         if (!pass)
             pass = tech->GetPass(PASS_LIGHT);
         // Skip if material does not receive light at all
@@ -703,7 +726,6 @@ void View::RenderBatchesForward()
         PROFILE(RenderBasePass);
         
         graphics_->SetColorWrite(true);
-        graphics_->SetStencilTest(false);
         graphics_->SetRenderTarget(0, renderTarget_);
         graphics_->SetDepthStencil(depthStencil_);
         graphics_->SetViewport(screenRect_);
@@ -732,6 +754,8 @@ void View::RenderBatchesForward()
         }
     }
     
+    graphics_->SetScissorTest(false);
+    graphics_->SetStencilTest(false);
     graphics_->SetRenderTarget(0, renderTarget_);
     graphics_->SetDepthStencil(depthStencil_);
     graphics_->SetViewport(screenRect_);
@@ -783,8 +807,6 @@ void View::RenderBatchesDeferred()
         PROFILE(RenderGBuffer);
         
         graphics_->SetColorWrite(true);
-        graphics_->SetScissorTest(false);
-        graphics_->SetStencilTest(false);
         #ifdef USE_OPENGL
         // On OpenGL, clear the diffuse and depth buffers normally
         graphics_->SetRenderTarget(0, diffBuffer);
@@ -915,7 +937,6 @@ void View::RenderBatchesDeferred()
         // Render base passes
         PROFILE(RenderBasePass);
         
-        graphics_->SetStencilTest(false);
         graphics_->SetTexture(TU_DIFFBUFFER, 0);
         graphics_->SetTexture(TU_NORMALBUFFER, 0);
         graphics_->SetTexture(TU_DEPTHBUFFER, 0);
@@ -964,8 +985,6 @@ void View::RenderBatchesDeferred()
         graphics_->SetBlendMode(BLEND_REPLACE);
         graphics_->SetDepthTest(CMP_ALWAYS);
         graphics_->SetDepthWrite(false);
-        graphics_->SetScissorTest(false);
-        graphics_->SetStencilTest(false);
         graphics_->SetRenderTarget(0, renderTarget_);
         graphics_->SetDepthStencil(depthStencil_);
         graphics_->SetViewport(screenRect_);
@@ -1300,16 +1319,16 @@ unsigned View::ProcessLight(Light* light)
         if (numSplits > 1)
         {
             // Make sure there are no duplicates
-            HashSet<Drawable*> allLitGeometries;
+            allLitGeometries_.Clear();
             for (unsigned i = 0; i < numSplits; ++i)
             {
                 for (Vector<Drawable*>::Iterator j = litGeometries_[i].Begin(); j != litGeometries_[i].End(); ++j)
-                    allLitGeometries.Insert(*j);
+                    allLitGeometries_.Insert(*j);
             }
             
-            litGeometries_[0].Resize(allLitGeometries.Size());
+            litGeometries_[0].Resize(allLitGeometries_.Size());
             unsigned index = 0;
-            for (HashSet<Drawable*>::Iterator i = allLitGeometries.Begin(); i != allLitGeometries.End(); ++i)
+            for (HashSet<Drawable*>::Iterator i = allLitGeometries_.Begin(); i != allLitGeometries_.End(); ++i)
                 litGeometries_[0][index++] = *i;
         }
         
@@ -1669,7 +1688,7 @@ void View::OptimizeLightByScissor(Light* light)
 
 const Rect& View::GetLightScissor(Light* light)
 {
-    Map<Light*, Rect>::Iterator i = lightScissorCache_.Find(light);
+    HashMap<Light*, Rect>::Iterator i = lightScissorCache_.Find(light);
     if (i != lightScissorCache_.End())
         return i->second_;
     
@@ -2233,13 +2252,13 @@ void View::DrawFullScreenQuad(Camera& camera, ShaderVariation* vs, ShaderVariati
     renderer_->dirLightGeometry_->Draw(graphics_);
 }
 
-void View::RenderBatchQueue(const BatchQueue& queue, bool useScissor, bool disableScissor)
+void View::RenderBatchQueue(const BatchQueue& queue, bool useScissor)
 {
     VertexBuffer* instancingBuffer = 0;
     if (renderer_->GetDynamicInstancing())
         instancingBuffer = renderer_->instancingBuffer_;
     
-    if (disableScissor)
+    if (useScissor)
         graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     
@@ -2262,10 +2281,8 @@ void View::RenderBatchQueue(const BatchQueue& queue, bool useScissor, bool disab
         queue.batchGroups_.End(); ++i)
     {
         const BatchGroup& group = i->second_;
-        if (useScissor && group.light_)
+        if (useScissor)
             OptimizeLightByScissor(group.light_);
-        else
-            graphics_->SetScissorTest(false);
         group.Draw(graphics_, instancingBuffer, shaderParameters_);
     }
     // Non-priority non-instanced
@@ -2273,10 +2290,13 @@ void View::RenderBatchQueue(const BatchQueue& queue, bool useScissor, bool disab
     {
         Batch* batch = *i;
         // For the transparent queue, both priority and non-priority batches are copied here, so check the flag
-        if (useScissor && batch->light_ && !batch->hasPriority_)
-            OptimizeLightByScissor(batch->light_);
-        else
-            graphics_->SetScissorTest(false);
+        if (useScissor)
+        {
+            if (!batch->hasPriority_)
+                OptimizeLightByScissor(batch->light_);
+            else
+                graphics_->SetScissorTest(false);
+        }
         batch->Draw(graphics_, shaderParameters_);
     }
 }
@@ -2335,7 +2355,6 @@ void View::RenderShadowMap(const LightBatchQueue& queue)
     Texture2D* shadowMap = queue.light_->GetShadowMap();
     
     graphics_->SetColorWrite(false);
-    graphics_->SetStencilTest(false);
     graphics_->SetTexture(TU_SHADOWMAP, 0);
     graphics_->SetRenderTarget(0, shadowMap->GetRenderSurface()->GetLinkedRenderTarget());
     graphics_->SetDepthStencil(shadowMap);
@@ -2363,8 +2382,9 @@ void View::RenderShadowMap(const LightBatchQueue& queue)
         graphics_->SetScissorTest(false);
     
     // Draw instanced and non-instanced shadow casters
-    RenderBatchQueue(queue.shadowBatches_, false, false);
+    RenderBatchQueue(queue.shadowBatches_);
     
     graphics_->SetColorWrite(true);
     graphics_->SetDepthBias(0.0f, 0.0f);
+    graphics_->SetScissorTest(false);
 }

+ 5 - 4
Engine/Graphics/View.h

@@ -182,7 +182,7 @@ private:
     /// Draw a full screen quad (either near or far.)
     void DrawFullScreenQuad(Camera& camera, ShaderVariation* vs, ShaderVariation* ps, bool nearQuad, const HashMap<StringHash, Vector4>& shaderParameters);
     /// Draw everything in a batch queue, priority batches first.
-    void RenderBatchQueue(const BatchQueue& queue, bool useScissor = false, bool disableScissor = true);
+    void RenderBatchQueue(const BatchQueue& queue, bool useScissor = false);
     /// Draw a forward (shadowed) light batch queue.
     void RenderForwardLightBatchQueue(const BatchQueue& queue, Light* forwardQueueLight, bool firstSplit);
     /// Render a shadow map.
@@ -226,8 +226,6 @@ private:
     BoundingBox sceneBox_;
     /// Combined bounding box of visible geometries in view space.
     BoundingBox sceneViewBox_;
-    /// Cache for light scissor queries.
-    Map<Light*, Rect> lightScissorCache_;
     /// Current split lights being processed.
     Light* splitLights_[MAX_LIGHT_SPLITS];
     /// Current lit geometries being processed.
@@ -248,9 +246,12 @@ private:
     PODVector<Light*> lights_;
     /// Render surfaces for which a G-buffer size error has already been logged, to prevent log spam.
     HashSet<RenderSurface*> gBufferErrorDisplayed_;
+    /// Helper set for combining lit geometries of a split light.
+    HashSet<Drawable*> allLitGeometries_;
     /// View-global shader parameters.
     HashMap<StringHash, Vector4> shaderParameters_;
-    
+    /// Cache for light scissor queries.
+    HashMap<Light*, Rect> lightScissorCache_;
     /// G-buffer batches.
     BatchQueue gBufferQueue_;
     /// Base pass batches.

+ 5 - 0
SourceAssets/GLSLShaders/Forward.xml

@@ -41,6 +41,11 @@
             <exclude name="Spec" />
             <exclude name="SpecMap" />
         </variation>
+        <variation name="AmbientDir">
+            <define name="AMBIENT" />
+            <define name="DIRLIGHT" />
+            <define name="LIGHT" />
+        </variation>
         <variation name="Dir">
             <define name="DIRLIGHT" />
             <define name="LIGHT" />

+ 1 - 1
SourceAssets/GLSLShaders/TemporalAA.frag

@@ -44,7 +44,7 @@ void main()
 
     // To eliminate ghosting, clamp RGB values to the pixel's neighbours
     // This is rather expensive, so only do it if there is a large color difference
-    if (dot(abs(current - last), 1.0) > 0.25)
+    if (dot(abs(current - last), vec3(1.0, 1.0, 1.0)) > 0.25)
     {
         vec3 left = texture2D(sDiffBuffer, vScreenPos - hOffset).rgb;
         vec3 right = texture2D(sDiffBuffer, vScreenPos + hOffset).rgb;

+ 5 - 0
SourceAssets/HLSLShaders/Forward.xml

@@ -39,6 +39,11 @@
             <exclude name="Spec" />
             <exclude name="SpecMap" />
         </variation>
+        <variation name="AmbientDir">
+            <define name="AMBIENT" />
+            <define name="DIRLIGHT" />
+            <define name="LIGHT" />
+        </variation>
         <variation name="Dir">
             <define name="DIRLIGHT" />
             <define name="LIGHT" />