Browse Source

Shader refactoring.
Removed ambient + lit pass combining for less shader permutations, and to prime the Z-buffer with a lightweight pass in case there is a large amount of overdraw.
Moved ambient light calculation to the ambient pass vertex shader.
Added render mode toggle to the editor settings.
Note: OpenGL rendering is currently broken.

Lasse Öörni 14 years ago
parent
commit
f9bfd4948f
45 changed files with 299 additions and 306 deletions
  1. 1 2
      Bin/CoreData/Techniques/Diff.xml
  2. 1 1
      Bin/CoreData/Techniques/DiffAlpha.xml
  3. 3 2
      Bin/CoreData/Techniques/DiffAlphaMask.xml
  4. 1 1
      Bin/CoreData/Techniques/DiffLitParticleAlpha.xml
  5. 1 2
      Bin/CoreData/Techniques/DiffNormal.xml
  6. 1 1
      Bin/CoreData/Techniques/DiffNormalAlpha.xml
  7. 3 2
      Bin/CoreData/Techniques/DiffNormalAlphaMask.xml
  8. 1 2
      Bin/CoreData/Techniques/NoTexture.xml
  9. 1 1
      Bin/CoreData/Techniques/NoTextureAlpha.xml
  10. 1 1
      Bin/Data/Materials/LitSmoke.xml
  11. 2 0
      Bin/Data/Scripts/Editor.as
  12. 10 0
      Bin/Data/Scripts/Editor/EditorSettings.as
  13. 18 0
      Bin/Data/UI/EditorSettingsDialog.xml
  14. 1 1
      CMakeLists.txt
  15. 23 9
      Docs/Reference.dox
  16. 3 0
      Docs/ScriptAPI.dox
  17. 4 1
      Engine/Engine/GraphicsAPI.cpp
  18. 46 37
      Engine/Graphics/Batch.cpp
  19. 5 0
      Engine/Graphics/Direct3D9/D3D9Graphics.cpp
  20. 2 0
      Engine/Graphics/Direct3D9/D3D9Graphics.h
  21. 0 28
      Engine/Graphics/Drawable.cpp
  22. 0 8
      Engine/Graphics/Drawable.h
  23. 4 6
      Engine/Graphics/GraphicsDefs.cpp
  24. 6 9
      Engine/Graphics/GraphicsDefs.h
  25. 11 13
      Engine/Graphics/Light.cpp
  26. 2 2
      Engine/Graphics/Light.h
  27. 6 0
      Engine/Graphics/OpenGL/OGLGraphics.cpp
  28. 2 0
      Engine/Graphics/OpenGL/OGLGraphics.h
  29. 14 13
      Engine/Graphics/Renderer.cpp
  30. 1 1
      Engine/Graphics/Renderer.h
  31. 1 2
      Engine/Graphics/Technique.cpp
  32. 30 47
      Engine/Graphics/View.cpp
  33. 2 2
      Engine/Graphics/View.h
  34. 6 6
      SourceAssets/HLSLShaders/Ambient.hlsl
  35. 3 3
      SourceAssets/HLSLShaders/CMakeLists.txt
  36. 4 4
      SourceAssets/HLSLShaders/DeferredLight.hlsl
  37. 2 2
      SourceAssets/HLSLShaders/DeferredLight.xml
  38. 13 18
      SourceAssets/HLSLShaders/ForwardLit.hlsl
  39. 2 3
      SourceAssets/HLSLShaders/ForwardLit.xml
  40. 1 1
      SourceAssets/HLSLShaders/GBuffer.xml
  41. 8 8
      SourceAssets/HLSLShaders/Lighting.hlsl
  42. 11 21
      SourceAssets/HLSLShaders/LitParticle.hlsl
  43. 2 3
      SourceAssets/HLSLShaders/LitParticle.xml
  44. 6 7
      SourceAssets/HLSLShaders/Material.hlsl
  45. 34 36
      SourceAssets/HLSLShaders/Uniforms.hlsl

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

@@ -1,7 +1,6 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient_Diff" />
-    <pass name="litbase" vs="BlinnPhong" ps="BlinnPhong_DiffAmbient" />
-    <pass name="light" vs="BlinnPhong" ps="BlinnPhong_Diff" depthtest="equal" depthwrite="false" blend="add" />
+    <pass name="light" vs="ForwardLit" ps="ForwardLit_Diff" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="gbuffer" vs="GBuffer" ps="GBuffer" />
     <pass name="material" vs="Material" ps="Material_Diff" depthtest="equal" depthwrite="false" />

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

@@ -1,5 +1,5 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="BlinnPhong" ps="BlinnPhong_Diff" depthwrite="false" blend="addalpha" />
+    <pass name="light" vs="ForwardLit" ps="ForwardLit_Diff" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>

+ 3 - 2
Bin/CoreData/Techniques/DiffAlphaMask.xml

@@ -1,6 +1,7 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient_Diff" alphatest="true" />
-    <pass name="litbase" vs="BlinnPhong" ps="BlinnPhong_DiffAmbient" alphatest="true" />
-    <pass name="light" vs="BlinnPhong" ps="BlinnPhong_Diff"  alphatest="true" depthtest="equal" depthwrite="false" blend="add" />
+    <pass name="light" vs="ForwardLit" ps="ForwardLit_Diff"  alphatest="true" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow_Mask" ps="Shadow_Mask" alphatest="true" />
+    <pass name="gbuffer" vs="GBuffer" ps="GBuffer_Mask" />
+    <pass name="material" vs="Material" ps="Material_DiffMask" depthtest="equal" depthwrite="false" />
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/DiffVolumeAlpha.xml → Bin/CoreData/Techniques/DiffLitParticleAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="Volumetric" ps="Volumetric_Diff" depthwrite="false" blend="addalpha" />
+    <pass name="light" vs="LitParticle" ps="LitParticle_Diff" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>

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

@@ -1,7 +1,6 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient_Diff" />
-    <pass name="litbase" vs="BlinnPhong_Normal" ps="BlinnPhong_DiffNormalAmbient" />
-    <pass name="light" vs="BlinnPhong_Normal" ps="BlinnPhong_DiffNormal" depthtest="equal" depthwrite="false" blend="add" />
+    <pass name="light" vs="ForwardLit_Normal" ps="ForwardLit_DiffNormal" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="gbuffer" vs="GBuffer_Normal" ps="GBuffer_Normal" />
     <pass name="material" vs="Material" ps="Material_Diff" depthtest="equal" depthwrite="false" />

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

@@ -1,5 +1,5 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="BlinnPhong_Normal" ps="BlinnPhong_DiffNormal" depthwrite="false" blend="addalpha" />
+    <pass name="light" vs="ForwardLit_Normal" ps="ForwardLit_DiffNormal" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>

+ 3 - 2
Bin/CoreData/Techniques/DiffNormalAlphaMask.xml

@@ -1,6 +1,7 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient_Diff" alphatest="true" />
-    <pass name="litbase" vs="BlinnPhong_Normal" ps="BlinnPhong_DiffNormalAmbient" alphatest="true" />
-    <pass name="light" vs="BlinnPhong_Normal" ps="BlinnPhong_DiffNormal" alphatest="true" depthtest="equal" depthwrite="false" blend="add" />
+    <pass name="light" vs="ForwardLit_Normal" ps="ForwardLit_DiffNormal" alphatest="true" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow_Mask" ps="Shadow_Mask" alphatest="true" />
+    <pass name="gbuffer" vs="GBuffer_Normal" ps="GBuffer_NormalMask" />
+    <pass name="material" vs="Material" ps="Material_DiffMask" depthtest="equal" depthwrite="false" />
 </technique>

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

@@ -1,7 +1,6 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient" />
-    <pass name="litbase" vs="BlinnPhong" ps="BlinnPhong_Ambient" />
-    <pass name="light" vs="BlinnPhong" ps="BlinnPhong" depthtest="equal" depthwrite="false" blend="add" />
+    <pass name="light" vs="ForwardLit" ps="ForwardLit" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="gbuffer" vs="GBuffer" ps="GBuffer" />
     <pass name="material" vs="Material" ps="Material" depthtest="equal" depthwrite="false" />

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

@@ -1,4 +1,4 @@
 <technique>
     <pass name="base" vs="Ambient" ps="Ambient" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="BlinnPhong" ps="BlinnPhong" depthwrite="false" blend="addalpha" />
+    <pass name="light" vs="ForwardLit" ps="ForwardLit" depthwrite="false" blend="addalpha" />
 </technique>

+ 1 - 1
Bin/Data/Materials/LitSmoke.xml

@@ -1,5 +1,5 @@
 <material>
-    <technique name="Techniques/DiffVolumeAlpha.xml" />
+    <technique name="Techniques/DiffLitParticleAlpha.xml" />
     <parameter name="MatDiffColor" value="0.5 0.5 0.5 0.5" />    
     <texture unit="diffuse" name="Textures/Smoke.dds" />
 </material>

+ 2 - 0
Bin/Data/Scripts/Editor.as

@@ -98,6 +98,7 @@ void LoadConfig()
 
     if (!renderingElem.isNull)
     {
+        renderer.lightPrepass = renderingElem.GetInt("rendermode") == 1;
         renderer.textureQuality = renderingElem.GetInt("texturequality");
         renderer.materialQuality = renderingElem.GetInt("materialquality");
         SetShadowResolution(renderingElem.GetInt("shadowresolution"));
@@ -136,6 +137,7 @@ void SaveConfig()
     objectElem.SetBool("uselocalids", useLocalIDs);
     objectElem.SetInt("pickmode", pickMode);
 
+    renderingElem.SetInt("rendermode", renderer.lightPrepass ? 1 : 0);
     renderingElem.SetInt("texturequality", renderer.textureQuality);
     renderingElem.SetInt("materialquality", renderer.materialQuality);
     renderingElem.SetInt("shadowresolution", GetShadowResolution());

+ 10 - 0
Bin/Data/Scripts/Editor/EditorSettings.as

@@ -55,6 +55,9 @@ void UpdateEditorSettingsDialog()
     DropDownList@ pickModeEdit = settingsDialog.GetChild("PickModeEdit", true);
     pickModeEdit.selection = pickMode;
 
+    DropDownList@ renderModeEdit = settingsDialog.GetChild("RenderModeEdit", true);
+    renderModeEdit.selection = renderer.lightPrepass ? 1 : 0;
+
     DropDownList@ textureQualityEdit = settingsDialog.GetChild("TextureQualityEdit", true);
     textureQualityEdit.selection = renderer.textureQuality;
 
@@ -105,6 +108,7 @@ void UpdateEditorSettingsDialog()
         SubscribeToEvent(scaleSnapToggle, "Toggled", "EditScaleSnap");
         SubscribeToEvent(localIDToggle, "Toggled", "EditUseLocalIDs");
         SubscribeToEvent(pickModeEdit, "ItemSelected", "EditPickMode");
+        SubscribeToEvent(renderModeEdit, "ItemSelected", "EditRenderMode");
         SubscribeToEvent(textureQualityEdit, "ItemSelected", "EditTextureQuality");
         SubscribeToEvent(materialQualityEdit, "ItemSelected", "EditMaterialQuality");
         SubscribeToEvent(shadowResolutionEdit, "ItemSelected", "EditShadowResolution");
@@ -226,6 +230,12 @@ void EditPickMode(StringHash eventType, VariantMap& eventData)
     pickMode = edit.selection;
 }
 
+void EditRenderMode(StringHash eventType, VariantMap& eventData)
+{
+    DropDownList@ edit = eventData["Element"].GetUIElement();
+    renderer.lightPrepass = edit.selection == 1;
+}
+
 void EditTextureQuality(StringHash eventType, VariantMap& eventData)
 {
     DropDownList@ edit = eventData["Element"].GetUIElement();

+ 18 - 0
Bin/Data/UI/EditorSettingsDialog.xml

@@ -156,6 +156,24 @@
     <element type="BorderImage" style="EditorDivider">
         <fixedheight value="4" />
     </element>
+    <element>
+        <fixedheight value="17" />
+        <layout mode="horizontal" spacing="8" />
+        <element type="Text">
+            <text value="Rendering mode" />
+        </element>
+        <element type="Text" style="FileSelectorFilterText" name="RenderForward">
+            <text value="Forward" />
+        </element>
+        <element type="Text" style="FileSelectorFilterText" name="RenderPrepass">
+            <text value="Pre-pass" />
+        </element>
+        <element type="DropDownList" name="RenderModeEdit">
+            <fixedwidth value="100" />
+            <popupitem name="RenderForward" />
+            <popupitem name="RenderPrepass" />
+        </element>
+    </element>
     <element>
         <fixedheight value="17" />
         <layout mode="horizontal" spacing="8" />

+ 1 - 1
CMakeLists.txt

@@ -113,7 +113,7 @@ else()
         add_custom_command (
             OUTPUT ../../Bin/CoreData/Shaders/SM3/${NAME}.vs3
             COMMAND ../../Bin/ShaderCompiler ${NAME}.xml ../../Bin/CoreData/Shaders/SM3 SM3
-            DEPENDS ShaderCompiler Uniforms.hlsl Samplers.hlsl Transform.hlsl Lighting.hlsl Fog.hlsl ${NAME}.hlsl ${NAME}.xml
+            DEPENDS ShaderCompiler Uniforms.hlsl Samplers.hlsl Transform.hlsl Lighting.hlsl ScreenPos.hlsl Fog.hlsl ${NAME}.hlsl ${NAME}.xml
         )
 
         set (ALL_SHADERS ${ALL_SHADERS} ../../Bin/CoreData/Shaders/SM2/${NAME}.vs2 ../../Bin/CoreData/Shaders/SM3/${NAME}.vs3)

+ 23 - 9
Docs/Reference.dox

@@ -375,6 +375,7 @@ When setting the initial screen mode, Graphics does a few checks:
 - For Direct3D9, the supported shader model is checked. 2.0 is minimum, but 3.0 will be used if available. %Shader model 2.0 can be forced by calling \ref Graphics::SetForceSM2() "SetForceSM2()".
 - For OpenGL, version 2.0 with EXT_framebuffer_object and EXT_packed_depth_stencil extensions is checked for.
 - Are hardware shadow maps supported? Both ATI & NVIDIA style shadow maps can be used. If neither are available, a fallback mode using a color texture and minimal shadow filtering will be chosen instead.
+- Is light pre-pass rendering supported? This requires either readable hardware depth support, or multiple render target and R32F texture format support.
 
 \section Rendering_Renderer Renderer
 
@@ -384,6 +385,8 @@ To render, it needs a Scene with an Octree component, and a Camera that does not
 
 By default there is one viewport, but the amount can be increased with the function \ref Renderer::SetNumViewports "SetNumViewports()". The viewport(s) should cover the entire screen or otherwise hall-of-mirrors artifacts may occur. By specifying a zero screen rectangle the whole window will be used automatically. The viewports will be rendered in ascending order, so if you want for example to have a small overlay window on top of the main viewport, use viewport index 0 for the main view, and 1 for the overlay.
 
+Either forward or light pre-pass rendering can be chosen, see \ref Renderer::SetLightPrepass "SetLightPrepass()". Light pre-pass will be advantageous once there is a large number of per-pixel lights affecting each object, but its disadvantages are the lack of hardware antialiasing and inability to choose the lighting model per object.
+
 The steps for rendering each viewport on each frame are roughly the following:
 
 - Query the octree for visible objects and lights in the camera's view frustum.
@@ -391,12 +394,20 @@ The steps for rendering each viewport on each frame are roughly the following:
 - Construct render operations (batches) for the visible objects.
 - Perform these render operations during the rendering step at the end of the frame.
 
-The rendering operations are divided into passes in the following order:
+When using forward rendering, the rendering operations proceed in the following order:
 
-- Opaque geometry ambient pass.
-- Opaque geometry lighting passes. For shadow casting lights, the shadow map is rendered first.
-- Post-opaque or "extra" rendering pass for materials that define that.
+- Opaque geometry ambient and per-vertex lighting pass.
+- Opaque geometry per-pixel lighting passes. For shadow casting lights, the shadow map is rendered first.
+- Pre-alpha rendering pass for custom render ordering such as the skybox.
 - Transparent geometry rendering pass. Transparent, alpha-blended objects are sorted according to distance and rendered back-to-front to ensure correct blending.
+- Post-alpha rendering pass.
+
+When using light pre-pass rendering, the following order is used instead:
+
+- Opaque geometry G-buffer pass. Normals, specular power and depth are rendered.
+- Lighting accumulation pass. Per-pixel lighting for opaque geometry is generated by rendering light volumes. For shadow casting lights, the shadow map is rendered first.
+- Opaque geometry material pass. Ambient and vertex lighting, and per-pixel lighting from the light accumulation buffer are combined.
+- The rest of the passes happen like in forward rendering.
 
 \section Rendering_Drawable Rendering components
 
@@ -504,7 +515,7 @@ A technique definition looks like this:
 
 \code
 <technique>
-    <pass name="base|litbase|light|prealpha|postalpha|shadow" vs="VertexShaderName" ps="PixelShaderName"
+    <pass name="base|light|prealpha|postalpha|gbuffer|material|shadow" vs="VertexShaderName" ps="PixelShaderName"
         alphatest="true|false" blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha"
         depthtest="always|equal|less|lessequal|greater|greaterequal" depthwrite="true|false" />
     <pass ... />
@@ -514,16 +525,17 @@ A technique definition looks like this:
 
 The passes are:
 
-- base: renders the ambient light and fog.
-- litbase: renders both the ambient light and the first light affecting the object for optimization.
-- light: renders one light's contribution additively.
+- base: renders the ambient light, per-vertex lights and fog.
+- light: renders one per-pixel light's contribution additively.
 - prealpha: custom rendering pass after opaque geometry. Can be used for example to render the skybox.
 - postalpha: custom rendering pass after transparent geometry.
+- gbuffer: (light pre-pass only) renders normals, specular power and depth to prepare for opaque geometry light accumulation.
+- material: (light pre-pass only) renders the opaque geometry final color by combining ambient light, per-vertex lights and per-pixel light accumulation.
 - shadow: shadow map rendering pass. Renders depth only.
 
 By default draw calls within passes are sorted by render state, but transparent base and light passes, as well as the postalpha pass, are sorted by distance back to front.
 
-Note that the technique does not need to enumerate shaders used for different geometry types (non-skinned, skinned, instanced, billboard) and light types (directional, point and spot, specular and no specular, shadowed and non-shadowed.) Instead specific hardcoded shader variations are assumed to exist. See the file Forward.xml in either SourceAssets/HLSLShaders or SourceAssets/GLSLShaders for all the shader variations.
+Note that the technique does not need to enumerate shaders used for different geometry types (non-skinned, skinned, instanced, billboard) and different per-vertex and per-pixel light combinations. Instead specific hardcoded shader variations are assumed to exist. See the files Ambient.xml and ForwardLit.xml in either SourceAssets/HLSLShaders or SourceAssets/GLSLShaders to see which variations are required.
 
 
 \page Lights Lights and shadows
@@ -548,6 +560,8 @@ It is possible to limit which objects are affected by each light, by calling \re
 
 Care must be utilized when doing light culling with lightmasks, because they easily create situations where a light's influence is cut off unnaturally. However, they can be helpful in preventing light spill into undesired areas, for example lights inside one room bleeding into another, without having to resort into shadow-casting lights.
 
+In light pre-pass rendering, light culling happens by writing the objects' light masks to the stencil buffer during G-buffer rendering, and comparing the stencil buffer to the light's light mask when rendering light volumes. In this case light masks are limited to the low 8 bits only.
+
 \section Lights_ShadowedLights Shadowed lights
 
 Shadow rendering is easily the most complex aspect of using lights, and therefore a wide range of per-light parameters exists for controlling the shadows:

+ 3 - 0
Docs/ScriptAPI.dox

@@ -2093,6 +2093,8 @@ Properties:<br>
 - uint numBatches (readonly)
 - bool fallback (readonly)
 - bool sm3Support (readonly)
+- bool lightPrepassSupport (readonly)
+- bool hardwareDepthSupport (readonly)
 - bool hardwareShadowSupport (readonly)
 - bool hiresShadowSupport (readonly)
 - bool forceSM2
@@ -2111,6 +2113,7 @@ Properties:<br>
 - String& typeName (readonly)
 - uint numViewports
 - Viewport&[] viewports
+- bool lightPrepass
 - bool specularLighting
 - int textureAnisotropy
 - TextureFilterMode textureFilterMode

+ 4 - 1
Engine/Engine/GraphicsAPI.cpp

@@ -285,10 +285,11 @@ static void RegisterMaterial(asIScriptEngine* engine)
     
     engine->RegisterEnum("PassType");
     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_PREALPHA", PASS_PREALPHA);
     engine->RegisterEnumValue("PassType", "PASS_POSTALPHA", PASS_POSTALPHA);
+    engine->RegisterEnumValue("PassType", "PASS_GBUFFER", PASS_GBUFFER);
+    engine->RegisterEnumValue("PassType", "PASS_MATERIAL", PASS_MATERIAL);
     engine->RegisterEnumValue("PassType", "PASS_SHADOW", PASS_SHADOW);
     
     engine->RegisterEnum("BlendMode");
@@ -732,6 +733,8 @@ static void RegisterGraphics(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Graphics", "uint get_numBatches() const", asMETHOD(Graphics, GetNumBatches), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_fallback() const", asMETHOD(Graphics, GetFallback), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_sm3Support() const", asMETHOD(Graphics, GetSM3Support), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Graphics", "bool get_lightPrepassSupport() const", asMETHOD(Graphics, GetLightPrepassSupport), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Graphics", "bool get_hardwareDepthSupport() const", asMETHOD(Graphics, GetHardwareDepthSupport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_hardwareShadowSupport() const", asMETHOD(Graphics, GetHardwareShadowSupport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_hiresShadowSupport() const", asMETHOD(Graphics, GetHiresShadowSupport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "void set_forceSM2(bool)", asMETHOD(Graphics, SetForceSM2), asCALL_THISCALL);

+ 46 - 37
Engine/Graphics/Batch.cpp

@@ -272,6 +272,11 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
     // Set zone-related shader parameters
     if (zone_)
     {
+        if (graphics->NeedParameterUpdate(VSP_AMBIENTSTARTCOLOR, zone_))
+            graphics->SetShaderParameter(VSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor().ToVector4());
+        if (graphics->NeedParameterUpdate(VSP_AMBIENTENDCOLOR, zone_))
+            graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
+        
         if (graphics->NeedParameterUpdate(VSP_ZONE, zone_))
         {
             const BoundingBox& box = zone_->GetBoundingBox();
@@ -284,11 +289,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             graphics->SetShaderParameter(VSP_ZONE, zoneTransform);
         }
         
-        if (graphics->NeedParameterUpdate(PSP_AMBIENTSTARTCOLOR, zone_))
-            graphics->SetShaderParameter(PSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor().ToVector4());
-        if (graphics->NeedParameterUpdate(PSP_AMBIENTENDCOLOR, zone_))
-            graphics->SetShaderParameter(PSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
-        
         // If the pass is additive, override fog color to black so that shaders do not need a separate additive path
         BlendMode blend = pass_->GetBlendMode();
         Zone* fogColorZone = (blend == BLEND_ADD || blend == BLEND_ADDALPHA) ? renderer->GetDefaultZone() : zone_;
@@ -336,20 +336,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(light->GetWorldPosition(), atten));
         }
         
-        if (graphics->NeedParameterUpdate(VSP_LIGHTVECROT, light))
-        {
-            Matrix3x4 lightVecRot(Vector3::ZERO, light->GetWorldRotation(), Vector3::ONE);
-            graphics->SetShaderParameter(VSP_LIGHTVECROT, lightVecRot);
-        }
-        
-        if (graphics->NeedParameterUpdate(VSP_SPOTPROJ, light))
-        {
-            Matrix4 spotProj;
-            CalculateSpotMatrix(spotProj, light, Vector3::ZERO);
-            
-            graphics->SetShaderParameter(VSP_SPOTPROJ, spotProj);
-        }
-        
         if (graphics->NeedParameterUpdate(VSP_VERTEXLIGHTS, lightQueue_))
         {
             Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
@@ -426,20 +412,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         // Set shadow mapping shader parameters
         if (shadowMap)
         {
-            if (graphics->NeedParameterUpdate(VSP_SHADOWPROJ, light))
-            {
-                Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
-                
-                unsigned numSplits = 1;
-                if (light->GetLightType() == LIGHT_DIRECTIONAL)
-                    numSplits = lightQueue_->shadowSplits_.Size();
-                
-                for (unsigned i = 0; i < numSplits; ++i)
-                    CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, graphics, renderer, Vector3::ZERO);
-                
-                graphics->SetShaderParameter(VSP_SHADOWPROJ, shadowMatrices[0].GetData(), 16 * numSplits);
-            }
-            
             if (graphics->NeedParameterUpdate(PSP_SAMPLEOFFSETS, shadowMap))
             {
                 float addX = 1.0f / (float)shadowMap->GetWidth();
@@ -530,7 +502,44 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             }
         }
         
-        if (graphics->NeedParameterUpdate(PSP_SHADOWPROJ, light))
+        if (graphics->NeedParameterUpdate(VSP_LIGHTMATRICES, light))
+        {
+            switch (light->GetLightType())
+            {
+            case LIGHT_DIRECTIONAL:
+                {
+                    Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
+                    unsigned numSplits = lightQueue_->shadowSplits_.Size();
+                    for (unsigned i = 0; i < numSplits; ++i)
+                        CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, graphics, renderer, Vector3::ZERO);
+                    
+                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].GetData(), 16 * numSplits);
+                }
+                break;
+                
+            case LIGHT_SPOT:
+                {
+                    Matrix4 shadowMatrices[2];
+                    
+                    CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
+                    bool isShadowed = lightQueue_->shadowMap_ != 0;
+                    if (isShadowed)
+                        CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, graphics, renderer, Vector3::ZERO);
+                    
+                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].GetData(), isShadowed ? 32 : 16);
+                }
+                break;
+                
+            case LIGHT_POINT:
+                {
+                    Matrix4 lightVecRot(light->GetWorldRotation().RotationMatrix());
+                    graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.GetData(), 16);
+                }
+                break;
+            }
+        }
+        
+        if (graphics->NeedParameterUpdate(PSP_LIGHTMATRICES, light))
         {
             switch (light->GetLightType())
             {
@@ -541,7 +550,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                     for (unsigned i = 0; i < numSplits; ++i)
                         CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, graphics, renderer, camera_->GetWorldPosition());
                     
-                    graphics->SetShaderParameter(PSP_SHADOWPROJ, shadowMatrices[0].GetData(), 16 * numSplits);
+                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].GetData(), 16 * numSplits);
                 }
                 break;
                 
@@ -554,14 +563,14 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                     if (isShadowed)
                         CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, graphics, renderer, camera_->GetWorldPosition());
                     
-                    graphics->SetShaderParameter(PSP_SHADOWPROJ, shadowMatrices[0].GetData(), isShadowed ? 32 : 16);
+                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].GetData(), isShadowed ? 32 : 16);
                 }
                 break;
                 
             case LIGHT_POINT:
                 {
                     Matrix4 lightVecRot(light->GetWorldRotation().RotationMatrix());
-                    graphics->SetShaderParameter(VSP_LIGHTVECROT, lightVecRot.GetData(), 16);
+                    graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.GetData(), 16);
                 }
                 break;
             }

+ 5 - 0
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -1184,6 +1184,11 @@ bool Graphics::NeedTextureUnit(TextureUnit unit)
     return pixelShader_ && pixelShader_->HasTextureUnit(unit);
 }
 
+void Graphics::ClearParameterSource(StringHash param)
+{
+    shaderParameters_[param].lastSource_ = (const void*)M_MAX_UNSIGNED;
+}
+
 void Graphics::ClearParameterSources()
 {
     for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)

+ 2 - 0
Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -120,6 +120,8 @@ public:
     bool NeedParameterUpdate(StringHash param, const void* source);
     /// Check whether the current pixel shader uses a texture unit.
     bool NeedTextureUnit(TextureUnit unit);
+    /// Clear remembered shader parameter source.
+    void ClearParameterSource(StringHash param);
     /// Clear remembered shader parameter sources.
     void ClearParameterSources();
     /// Clear remembered transform shader parameter sources.

+ 0 - 28
Engine/Graphics/Drawable.cpp

@@ -42,7 +42,6 @@ Drawable::Drawable(Context* context) :
     octant_(0),
     viewFrame_(0),
     viewCamera_(0),
-    firstLight_(0),
     drawDistance_(0.0f),
     shadowDistance_(0.0f),
     lodBias_(1.0f),
@@ -215,17 +214,12 @@ void Drawable::MarkInView(const FrameInfo& frame, bool mainView)
 
 void Drawable::ClearLights()
 {
-    for (unsigned i = 0; i < basePassFlags_.Size(); ++i)
-        basePassFlags_[i] = 0;
-    firstLight_ = 0;
     lights_.Clear();
     vertexLights_.Clear();
 }
 
 void Drawable::AddLight(Light* light)
 {
-    if (lights_.Empty())
-        firstLight_ = light;
     lights_.Push(light);
 }
 
@@ -266,19 +260,6 @@ void Drawable::LimitVertexLights()
         vertexLights_.Resize(MAX_VERTEX_LIGHTS);
 }
 
-void Drawable::SetBasePass(unsigned batchIndex)
-{
-    unsigned index = batchIndex >> 5;
-    if (basePassFlags_.Size() <= index)
-    {
-        unsigned oldSize = basePassFlags_.Size();
-        basePassFlags_.Resize(index + 1);
-        for (unsigned i = oldSize; i <= index; ++i)
-            basePassFlags_[i] = 0;
-    }
-    basePassFlags_[index] |= (1 << (batchIndex & 31));
-}
-
 Zone* Drawable::GetZone() const
 {
     return zone_;
@@ -289,15 +270,6 @@ Zone* Drawable::GetLastZone() const
     return lastZone_;
 }
 
-bool Drawable::HasBasePass(unsigned batchIndex) const
-{
-    unsigned index = batchIndex >> 5;
-    if (index < basePassFlags_.Size())
-        return (basePassFlags_[index] & (1 << (batchIndex & 31))) != 0;
-    else
-        return false;
-}
-
 void Drawable::OnNodeSet(Node* node)
 {
     // Insert initially into the root octant

+ 0 - 8
Engine/Graphics/Drawable.h

@@ -197,14 +197,10 @@ public:
     bool IsInView(unsigned frameNumber) const { return viewFrameNumber_ == frameNumber; }
     /// Return whether is visible in a specific view this frame.
     bool IsInView(const FrameInfo& frame, bool mainView = true) const { return viewFrameNumber_ == frame.frameNumber_ && viewFrame_ == &frame && (!mainView || viewCamera_ == frame.camera_); }
-    /// Return whether has a base pass.
-    bool HasBasePass(unsigned batchIndex) const;
     /// Return per-pixel lights.
     const PODVector<Light*>& GetLights() const { return lights_; }
     /// Return per-vertex lights.
     const PODVector<Light*>& GetVertexLights() const { return vertexLights_; }
-    /// Return the first added per-pixel light.
-    Light* GetFirstLight() const { return firstLight_; }
     
 protected:
     /// Handle node being assigned.
@@ -224,8 +220,6 @@ protected:
     Octant* octant_;
     /// World bounding box.
     BoundingBox worldBoundingBox_;
-    /// Base pass flags per batch index.
-    PODVector<unsigned> basePassFlags_;
     /// Last view's frameinfo. Not safe to dereference.
     const FrameInfo* viewFrame_;
     /// Last view's camera. Not safe to dereference.
@@ -234,8 +228,6 @@ protected:
     PODVector<Light*> lights_;
     /// Per-vertex lights affecting this drawable.
     PODVector<Light*> vertexLights_;
-    /// First per-pixel light added this frame.
-    Light* firstLight_;
     /// Current zone.
     WeakPtr<Zone> zone_;
     /// Previous zone.

+ 4 - 6
Engine/Graphics/GraphicsDefs.cpp

@@ -26,6 +26,8 @@
 
 #include "DebugNew.h"
 
+StringHash VSP_AMBIENTSTARTCOLOR("AmbientStartColor");
+StringHash VSP_AMBIENTENDCOLOR("AmbientEndColor");
 StringHash VSP_CAMERAPOS("CameraPos");
 StringHash VSP_CAMERAROT("CameraRot");
 StringHash VSP_DEPTHMODE("DepthMode");
@@ -33,20 +35,16 @@ StringHash VSP_FRUSTUMSIZE("FrustumSize");
 StringHash VSP_GBUFFEROFFSETS("GBufferOffsets");
 StringHash VSP_LIGHTDIR("LightDir");
 StringHash VSP_LIGHTPOS("LightPos");
-StringHash VSP_LIGHTVECROT("LightVecRot");
 StringHash VSP_MODEL("Model");
-StringHash VSP_SHADOWPROJ("ShadowProj");
-StringHash VSP_SPOTPROJ("SpotProj");
 StringHash VSP_VIEWPROJ("ViewProj");
 StringHash VSP_UOFFSET("UOffset");
 StringHash VSP_VOFFSET("VOffset");
 StringHash VSP_VIEWRIGHTVECTOR("ViewRightVector");
 StringHash VSP_VIEWUPVECTOR("ViewUpVector");
 StringHash VSP_ZONE("Zone");
+StringHash VSP_LIGHTMATRICES("LightMatrices");
 StringHash VSP_SKINMATRICES("SkinMatrices");
 StringHash VSP_VERTEXLIGHTS("VertexLights");
-StringHash PSP_AMBIENTSTARTCOLOR("AmbientStartColor");
-StringHash PSP_AMBIENTENDCOLOR("AmbientEndColor");
 StringHash PSP_DEPTHRECONSTRUCT("DepthReconstruct");
 StringHash PSP_FOGCOLOR("FogColor");
 StringHash PSP_FOGPARAMS("FogParams");
@@ -61,4 +59,4 @@ StringHash PSP_SHADOWCUBEADJUST("ShadowCubeAdjust");
 StringHash PSP_SHADOWDEPTHFADE("ShadowDepthFade");
 StringHash PSP_SHADOWINTENSITY("ShadowIntensity");
 StringHash PSP_SHADOWSPLITS("ShadowSplits");
-StringHash PSP_SHADOWPROJ("ShadowProjPS");
+StringHash PSP_LIGHTMATRICES("LightMatricesPS");

+ 6 - 9
Engine/Graphics/GraphicsDefs.h

@@ -166,13 +166,12 @@ enum TextureUsage
 enum PassType
 {
     PASS_BASE,
-    PASS_LITBASE,
     PASS_LIGHT,
     PASS_PREALPHA,
     PASS_POSTALPHA,
-    PASS_SHADOW,
     PASS_GBUFFER,
     PASS_MATERIAL,
+    PASS_SHADOW,
     MAX_PASSES
 };
 
@@ -195,7 +194,9 @@ enum ShaderType
     PS,
 };
 
-// Inbuilt shader parameters
+// Inbuilt shader parameters.
+extern StringHash VSP_AMBIENTSTARTCOLOR;
+extern StringHash VSP_AMBIENTENDCOLOR;
 extern StringHash VSP_CAMERAPOS;
 extern StringHash VSP_CAMERAROT;
 extern StringHash VSP_DEPTHMODE;
@@ -203,20 +204,16 @@ extern StringHash VSP_FRUSTUMSIZE;
 extern StringHash VSP_GBUFFEROFFSETS;
 extern StringHash VSP_LIGHTDIR;
 extern StringHash VSP_LIGHTPOS;
-extern StringHash VSP_LIGHTVECROT;
 extern StringHash VSP_MODEL;
-extern StringHash VSP_SHADOWPROJ;
-extern StringHash VSP_SPOTPROJ;
 extern StringHash VSP_VIEWPROJ;
 extern StringHash VSP_UOFFSET;
 extern StringHash VSP_VOFFSET;
 extern StringHash VSP_VIEWRIGHTVECTOR;
 extern StringHash VSP_VIEWUPVECTOR;
 extern StringHash VSP_ZONE;
+extern StringHash VSP_LIGHTMATRICES;
 extern StringHash VSP_SKINMATRICES;
 extern StringHash VSP_VERTEXLIGHTS;
-extern StringHash PSP_AMBIENTSTARTCOLOR;
-extern StringHash PSP_AMBIENTENDCOLOR;
 extern StringHash PSP_DEPTHRECONSTRUCT;
 extern StringHash PSP_FOGCOLOR;
 extern StringHash PSP_FOGPARAMS;
@@ -231,7 +228,7 @@ extern StringHash PSP_SHADOWCUBEADJUST;
 extern StringHash PSP_SHADOWDEPTHFADE;
 extern StringHash PSP_SHADOWINTENSITY;
 extern StringHash PSP_SHADOWSPLITS;
-extern StringHash PSP_SHADOWPROJ;
+extern StringHash PSP_LIGHTMATRICES;
 
 /// Texture units.
 enum TextureUnit

+ 11 - 13
Engine/Graphics/Light.cpp

@@ -359,15 +359,18 @@ Frustum Light::GetFrustum() const
 }
 
 
-Matrix3x4 Light::GetDirLightTransform(const Camera& camera, bool getNearQuad)
+Matrix3x4 Light::GetDirLightTransform(Camera* camera, bool getNearQuad)
 {
+    if (!camera)
+        return Matrix3x4::IDENTITY;
+    
     Vector3 nearVector, farVector;
-    camera.GetFrustumSize(nearVector, farVector);
-    float nearClip = camera.GetNearClip();
-    float farClip = camera.GetFarClip();
+    camera->GetFrustumSize(nearVector, farVector);
+    float nearClip = camera->GetNearClip();
+    float farClip = camera->GetFarClip();
     
     float distance = getNearQuad ? nearClip : farClip;
-    if (!camera.IsOrthographic())
+    if (!camera->IsOrthographic())
         farVector *= (distance / farClip);
     else
         farVector.z_ *= (distance / farClip);
@@ -379,7 +382,7 @@ Matrix3x4 Light::GetDirLightTransform(const Camera& camera, bool getNearQuad)
     return  Matrix3x4(Vector3(0.0f, 0.0f, farVector.z_), Quaternion::IDENTITY, Vector3(farVector.x_, farVector.y_, 1.0f));
 }
 
-const Matrix3x4& Light::GetVolumeTransform(const Camera& camera)
+const Matrix3x4& Light::GetVolumeTransform(Camera* camera)
 {
     const Matrix3x4& transform = GetWorldTransform();
     
@@ -453,15 +456,10 @@ void Light::OnWorldBoundingBoxUpdate()
 
 void Light::SetIntensitySortValue(float distance)
 {
-    // When sorting lights globally, give priority to directional lights so that they will be combined into the ambient pass
     if (lightType_ != LIGHT_DIRECTIONAL)
-        sortValue_ = Max(distance, M_MIN_NEARCLIP) / (color_.Intensity() + M_EPSILON);
-    else
         sortValue_ = M_EPSILON / (color_.Intensity() + M_EPSILON);
-    
-    // Additionally, give priority to vertex lights so that vertex light base passes can be determined before per pixel lights
-    if (perVertex_)
-        sortValue_ -= M_LARGE_VALUE;
+    else
+        sortValue_ = distance / (color_.Intensity() + M_EPSILON);
 }
 
 void Light::SetIntensitySortValue(const BoundingBox& box)

+ 2 - 2
Engine/Graphics/Light.h

@@ -242,9 +242,9 @@ public:
     /// %Set sort value based on overall intensity over a bounding box.
     void SetIntensitySortValue(const BoundingBox& box);
     /// Return directional light quad transform for either near or far split.
-    Matrix3x4 GetDirLightTransform(const Camera& camera, bool getNearQuad = false);
+    Matrix3x4 GetDirLightTransform(Camera* camera, bool getNearQuad = false);
     /// Return light volume model transform.
-    const Matrix3x4& GetVolumeTransform(const Camera& camera);
+    const Matrix3x4& GetVolumeTransform(Camera* camera);
     
     /// %Set ramp texture attribute.
     void SetRampTextureAttr(ResourceRef value);

+ 6 - 0
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -975,6 +975,12 @@ bool Graphics::NeedTextureUnit(TextureUnit unit)
     return false;
 }
 
+void Graphics::ClearParameterSource(StringHash param)
+{
+    if (shaderProgram_)
+        shaderProgram_->ClearParameterSource(param);
+}
+
 void Graphics::ClearParameterSources()
 {
     ++shaderParameterFrame_;

+ 2 - 0
Engine/Graphics/OpenGL/OGLGraphics.h

@@ -136,6 +136,8 @@ public:
     bool NeedParameterUpdate(StringHash param, const void* source);
     /// Check whether the current pixel shader uses a texture unit.
     bool NeedTextureUnit(TextureUnit unit);
+    /// Clear remembered shader parameter source.
+    void ClearParameterSource(StringHash param);
     /// Clear remembered shader parameter sources.
     void ClearParameterSources();
     /// Clear remembered transform shader parameter sources.

+ 14 - 13
Engine/Graphics/Renderer.cpp

@@ -1013,9 +1013,9 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, b
             (unsigned)maxInstanceTriangles_ * 3))
             geomType = GEOM_STATIC;
         
-        //  Check whether is a lit pass. If not, there is only one pixel shader
+        //  Check whether is a pixel lit forward pass. If not, there is only one pixel shader
         PassType type = pass->GetType();
-        if (type == PASS_LIGHT || type == PASS_LITBASE)
+        if (type == PASS_LIGHT)
         {
             LightBatchQueue* lightQueue = batch.lightQueue_;
             if (!lightQueue)
@@ -1120,7 +1120,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, b
     }
 }
 
-void Renderer::SetLightVolumeShaders(Batch& batch)
+void Renderer::SetLightVolumeBatchShaders(Batch& batch)
 {
     unsigned vsi = DLVS_NONE;
     unsigned psi = DLPS_NONE;
@@ -1272,7 +1272,7 @@ void Renderer::LoadShaders()
         unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
         
         for (unsigned i = 0; i < MAX_DEFERRED_LIGHT_VS_VARIATIONS; ++i)
-            lightVS_[i] = GetVertexShader("LightVolume_" + deferredLightVSVariations[i]);
+            lightVS_[i] = GetVertexShader("DeferredLight_" + deferredLightVSVariations[i]);
         
         for (unsigned i = 0; i < lightPS_.Size(); ++i)
         {
@@ -1280,12 +1280,12 @@ void Renderer::LoadShaders()
             String linearDepth = linearVariations[(!graphics_->GetHardwareDepthSupport() && i < DLPS_ORTHO) ? 1 : 0];
             if (i & DLPS_SHADOW)
             {
-                lightPS_[i] = GetPixelShader("LightVolume_" + linearDepth + lightPSVariations[i % DLPS_ORTHO] +
+                lightPS_[i] = GetPixelShader("DeferredLight_" + linearDepth + lightPSVariations[i % DLPS_ORTHO] +
                     shadowVariations[shadows]);
             }
             else
             {
-                lightPS_[i] = GetPixelShader("LightVolume_" + linearDepth + lightPSVariations[i % DLPS_ORTHO]);
+                lightPS_[i] = GetPixelShader("DeferredLight_" + linearDepth + lightPSVariations[i % DLPS_ORTHO]);
             }
         }
     }
@@ -1303,7 +1303,6 @@ void Renderer::LoadMaterialShaders(Technique* technique)
     else
     {
         LoadPassShaders(technique, PASS_BASE);
-        LoadPassShaders(technique, PASS_LITBASE);
         LoadPassShaders(technique, PASS_LIGHT);
     }
     
@@ -1332,16 +1331,15 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
     if (pixelShaderName.Find('_') == String::NPOS)
         pixelShaderName += "_";
     
-    // If hardware depth is used, do not write depth into a rendertarget in the G-buffer pass
-    // Also check for fallback G-buffer (different layout)
+    // If hardware depth is used, choose a G-buffer shader that does not write depth manually
     if (type == PASS_GBUFFER)
     {
         unsigned hwDepth = graphics_->GetHardwareDepthSupport() ? 1 : 0;
         vertexShaderName += hwVariations[hwDepth];
         pixelShaderName += hwVariations[hwDepth];
-        pixelShaderName += fallbackVariations[fallback];
     }
     
+    // Check for fallback shadow rendering mode (write depth into an RGBA render target)
     if (type == PASS_SHADOW)
     {
         vertexShaderName += fallbackVariations[fallback];
@@ -1355,9 +1353,10 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
     vertexShaders.Clear();
     pixelShaders.Clear();
     
-    if (type == PASS_LIGHT || type == PASS_LITBASE)
+    if (type == PASS_LIGHT)
     {
-        // If ambient pass is transparent, and shadow maps are reused, do not load shadow variations
+        // Load forward pixel lit variations. If material is transparent, and shadow maps are reused,
+        // do not load shadowed variations
         if (reuseShadowMaps_)
         {
             if (!technique->HasPass(PASS_BASE) || technique->GetPass(PASS_BASE)->GetBlendMode() != BLEND_REPLACE)
@@ -1394,6 +1393,7 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
     }
     else
     {
+        // Load vertex light variations for forward ambient pass and pre-pass material pass
         if (type == PASS_BASE || type == PASS_MATERIAL)
         {
             vertexShaders.Resize(MAX_VERTEXLIGHT_VS_VARIATIONS * MAX_GEOMETRYTYPES);
@@ -1401,7 +1401,8 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
             {
                 unsigned g = j / MAX_VERTEXLIGHT_VS_VARIATIONS;
                 unsigned l = j % MAX_VERTEXLIGHT_VS_VARIATIONS;
-                vertexShaders[j] = GetVertexShader(vertexShaderName + vertexLightVSVariations[l] + geometryVSVariations[g], g != 0 || l != 0);
+                vertexShaders[j] = GetVertexShader(vertexShaderName + vertexLightVSVariations[l] + geometryVSVariations[g],
+                    g != 0 || l != 0);
             }
         }
         else

+ 1 - 1
Engine/Graphics/Renderer.h

@@ -338,7 +338,7 @@ public:
     /// Choose shaders for a forward rendering batch.
     void SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows = true);
     /// Choose shaders for a light volume batch.
-    void SetLightVolumeShaders(Batch& batch);
+    void SetLightVolumeBatchShaders(Batch& batch);
     /// Ensure sufficient size of the instancing vertex buffer. Return true if successful.
     bool ResizeInstancingBuffer(unsigned numInstances);
     /// Reset shadow map allocation counts.

+ 1 - 2
Engine/Graphics/Technique.cpp

@@ -34,13 +34,12 @@
 static const String passNames[] =
 {
     "base",
-    "litbase",
     "light",
     "prealpha",
     "postalpha",
-    "shadow",
     "gbuffer",
     "material",
+    "shadow",
     ""
 };
 

+ 30 - 47
Engine/Graphics/View.cpp

@@ -632,7 +632,7 @@ void View::GetBatches()
                 {
                     Batch volumeBatch;
                     volumeBatch.geometry_ = renderer_->GetLightGeometry(light);
-                    volumeBatch.worldTransform_ = &light->GetVolumeTransform(*camera_);
+                    volumeBatch.worldTransform_ = &light->GetVolumeTransform(camera_);
                     volumeBatch.overrideView_ = light->GetLightType() == LIGHT_DIRECTIONAL;
                     volumeBatch.camera_ = camera_;
                     volumeBatch.lightQueue_ = &lightQueue;
@@ -640,7 +640,7 @@ void View::GetBatches()
                     volumeBatch.material_ = 0;
                     volumeBatch.pass_ = 0;
                     volumeBatch.zone_ = 0;
-                    renderer_->SetLightVolumeShaders(volumeBatch);
+                    renderer_->SetLightVolumeBatchShaders(volumeBatch);
                     lightQueue.volumeBatches_.Push(volumeBatch);
                 }
             }
@@ -717,24 +717,17 @@ void View::GetBatches()
                         FinalizeBatch(baseBatch, tech, pass);
                         gbufferQueue_.AddBatch(baseBatch);
                         
-                        // Use PASS_MATERIAL instead of PASS_BASE to distinguish between light pre-pass forward pass (which
-                        // uses the light accumulation result) and actual forward unlit base pass
                         pass = tech->GetPass(PASS_MATERIAL);
                     }
                 }
                 
-                // If object already has a pixel lit base pass, can skip the unlit base pass
+                // Next check for forward base pass
                 if (!pass)
-                {
-                    if (drawable->HasBasePass(j))
-                        continue;
-                    // Check for unlit or vertex lit base pass
                     pass = tech->GetPass(PASS_BASE);
-                }
                 
                 if (pass)
                 {
-                    // Check for vertex lights now
+                    // Check for vertex lights (both forward unlit and light pre-pass material pass)
                     const PODVector<Light*>& vertexLights = drawable->GetVertexLights();
                     if (!vertexLights.Empty())
                     {
@@ -869,11 +862,10 @@ void View::UpdateGeometries()
 void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue)
 {
     Light* light = lightQueue.light_;
-    Light* firstLight = drawable->GetFirstLight();
-    bool prepass = renderer_->GetLightPrepass();
     // Shadows on transparencies can only be rendered if shadow maps are not reused
     bool allowTransparentShadows = !renderer_->GetReuseShadowMaps();
     bool hasVertexLights = drawable->GetVertexLights().Size() > 0;
+    bool prepass = renderer_->GetLightPrepass();
     unsigned numBatches = drawable->GetNumBatches();
     
     for (unsigned i = 0; i < numBatches; ++i)
@@ -885,27 +877,11 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue)
         if (!litBatch.geometry_ || !tech)
             continue;
         
-        Pass* pass = 0;
-        
-        // Do not create pixel lit passes for materials that render into the G-buffer
+        // Do not create pixel lit forward passes for materials that render into the G-buffer
         if (prepass && tech->HasPass(PASS_GBUFFER))
             continue;
         
-        // Check for lit base pass. Because it uses the replace blend mode, it must be ensured to be the first light
-        // Also vertex lighting requires the non-lit base pass, so skip if any vertex lights
-        if (light == firstLight && !hasVertexLights && !drawable->HasBasePass(i))
-        {
-            pass = tech->GetPass(PASS_LITBASE);
-            if (pass)
-            {
-                litBatch.isBase_ = true;
-                drawable->SetBasePass(i);
-            }
-        }
-        
-        // If no lit base pass, get ordinary light pass
-        if (!pass)
-            pass = tech->GetPass(PASS_LIGHT);
+        Pass* pass = tech->GetPass(PASS_LIGHT);
         // Skip if material does not receive light at all
         if (!pass)
             continue;
@@ -963,7 +939,7 @@ void View::RenderBatchesForward()
     
     if (!lightQueues_.Empty())
     {
-        // Render shadow maps + opaque objects' shadowed additive lighting
+        // Render shadow maps + opaque objects' additive lighting
         PROFILE(RenderLights);
         
         for (List<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
@@ -1044,10 +1020,10 @@ void View::RenderBatchesLightPrepass()
     else
     {
         graphics_->SetRenderTarget(0, depthBuffer);
+        graphics_->SetRenderTarget(1, normalBuffer);
         graphics_->SetDepthStencil(depthStencil);
         graphics_->SetViewport(screenRect_);
-        graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, Color::WHITE);
-        graphics_->SetRenderTarget(1, normalBuffer);
+        graphics_->Clear(CLEAR_DEPTH | CLEAR_STENCIL);
     }
     
     if (!gbufferQueue_.IsEmpty())
@@ -1087,12 +1063,13 @@ void View::RenderBatchesLightPrepass()
             
             for (unsigned j = 0; j < i->volumeBatches_.Size(); ++j)
             {
-                SetupLightBatch(i->volumeBatches_[j]);
+                SetupLightVolumeBatch(i->volumeBatches_[j]);
                 i->volumeBatches_[j].Draw(graphics_, renderer_);
             }
         }
     }
     
+    // Clear destination render target with fog color
     graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetRenderTarget(0, renderTarget_);
@@ -1457,7 +1434,7 @@ IntRect View::GetShadowMapViewport(Light* light, unsigned splitIndex, Texture2D*
 
 void View::OptimizeLightByScissor(Light* light)
 {
-    if (light)
+    if (light && light->GetLightType() != LIGHT_DIRECTIONAL)
         graphics_->SetScissorTest(true, GetLightScissor(light));
     else
         graphics_->SetScissorTest(false);
@@ -1467,14 +1444,14 @@ void View::OptimizeLightByStencil(Light* light)
 {
     if (light && renderer_->GetLightStencilMasking())
     {
-        Geometry* geometry = renderer_->GetLightGeometry(light);
-        if (!geometry)
+        LightType type = light->GetLightType();
+        if (type == LIGHT_DIRECTIONAL)
         {
             graphics_->SetStencilTest(false);
             return;
         }
         
-        LightType type = light->GetLightType();
+        Geometry* geometry = renderer_->GetLightGeometry(light);
         Matrix3x4 view(camera_->GetInverseWorldTransform());
         Matrix4 projection(camera_->GetProjection());
         float lightDist;
@@ -1516,7 +1493,7 @@ void View::OptimizeLightByStencil(Light* light)
         graphics_->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, lightStencilValue_);
         graphics_->SetShaders(renderer_->GetStencilVS(), renderer_->GetStencilPS());
         graphics_->SetShaderParameter(VSP_VIEWPROJ, projection * view);
-        graphics_->SetShaderParameter(VSP_MODEL, light->GetVolumeTransform(*camera_));
+        graphics_->SetShaderParameter(VSP_MODEL, light->GetVolumeTransform(camera_));
         
         geometry->Draw(graphics_);
         
@@ -2007,7 +1984,7 @@ void View::PrepareInstancingBuffer()
     }
 }
 
-void View::SetupLightBatch(Batch& batch)
+void View::SetupLightVolumeBatch(Batch& batch)
 {
     Light* light = batch.lightQueue_->light_;
     LightType type = light->GetLightType();
@@ -2039,22 +2016,22 @@ void View::SetupLightBatch(Batch& batch)
     else
     {
         graphics_->SetCullMode(CULL_NONE);
-        graphics_->SetDepthTest(CMP_GREATER);
+        graphics_->SetDepthTest(CMP_ALWAYS);
     }
     
-    /// \todo Set stencil test to check for light masks
     graphics_->SetScissorTest(false);
-    graphics_->SetStencilTest(false);
+    graphics_->SetStencilTest(true, CMP_LESS, OP_KEEP, OP_KEEP, OP_KEEP, 0, light->GetLightMask());
 }
 
-void View::DrawFullscreenQuad(Camera& camera, bool nearQuad)
+void View::DrawFullscreenQuad(Camera* camera, bool nearQuad)
 {
     Light quadDirLight(context_);
+    quadDirLight.SetLightType(LIGHT_DIRECTIONAL);
     Matrix3x4 model(quadDirLight.GetDirLightTransform(camera, nearQuad));
     
     graphics_->SetCullMode(CULL_NONE);
     graphics_->SetShaderParameter(VSP_MODEL, model);
-    graphics_->SetShaderParameter(VSP_VIEWPROJ, camera.GetProjection());
+    graphics_->SetShaderParameter(VSP_VIEWPROJ, camera->GetProjection());
     graphics_->ClearTransformSources();
     
     renderer_->GetLightGeometry(&quadDirLight)->Draw(graphics_);
@@ -2063,7 +2040,13 @@ void View::DrawFullscreenQuad(Camera& camera, bool nearQuad)
 void View::RenderBatchQueue(const BatchQueue& queue, bool useScissor)
 {
     graphics_->SetScissorTest(false);
-    graphics_->SetStencilTest(false);
+    
+    // During G-buffer rendering, mark opaque pixels to scissor
+    /// \todo Use objects' light masks
+    if (&queue != &gbufferQueue_)
+        graphics_->SetStencilTest(false);
+    else
+        graphics_->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, 0xff);
     
     // Base instanced
     for (PODVector<BatchGroup*>::ConstIterator i = queue.sortedBaseBatchGroups_.Begin(); i !=

+ 2 - 2
Engine/Graphics/View.h

@@ -174,9 +174,9 @@ private:
     /// Prepare instancing buffer by filling it with all instance transforms.
     void PrepareInstancingBuffer();
     /// %Set up a light volume rendering batch.
-    void SetupLightBatch(Batch& batch);
+    void SetupLightVolumeBatch(Batch& batch);
     /// Draw a full screen quad (either near or far.) Shaders must have been set beforehand.
-    void DrawFullscreenQuad(Camera& camera, bool nearQuad);
+    void DrawFullscreenQuad(Camera* camera, bool nearQuad);
     /// Render everything in a batch queue, priority batches first.
     void RenderBatchQueue(const BatchQueue& queue, bool useScissor = false);
     /// Render batches lit by a specific light.

+ 6 - 6
SourceAssets/HLSLShaders/Ambient.hlsl

@@ -24,7 +24,7 @@ void VS(float4 iPos : POSITION,
     #ifdef BILLBOARD
         float2 iSize : TEXCOORD1,
     #endif
-    out float4 oTexCoord : TEXCOORD0,
+    out float3 oTexCoord : TEXCOORD0,
     out float3 oVertexLighting : TEXCOORD1,
     #ifdef VERTEXCOLOR
         out float4 oColor : COLOR0,
@@ -34,9 +34,9 @@ void VS(float4 iPos : POSITION,
     float4x3 modelMatrix = iModelMatrix;
     float3 worldPos = GetWorldPos(modelMatrix);
     oPos = GetClipPos(worldPos);
-    oTexCoord = float4(GetTexCoord(iTexCoord), GetZonePos(worldPos), GetDepth(oPos));
+    oTexCoord = float3(GetTexCoord(iTexCoord), GetDepth(oPos));
 
-    oVertexLighting = 0.0;
+    oVertexLighting = GetAmbient(GetZonePos(worldPos));
     #ifdef NUMVERTEXLIGHTS
     float3 normal = GetWorldNormal(modelMatrix);
     for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
@@ -48,7 +48,7 @@ void VS(float4 iPos : POSITION,
     #endif
 }
 
-void PS(float4 iTexCoord : TEXCOORD0,
+void PS(float3 iTexCoord : TEXCOORD0,
     float3 iVertexLighting : TEXCOORD1,
     #ifdef VERTEXCOLOR
         float4 iColor : COLOR0,
@@ -65,7 +65,7 @@ void PS(float4 iTexCoord : TEXCOORD0,
         diffColor *= iColor;
     #endif
 
-    float3 finalColor = (GetAmbient(iTexCoord.z) + iVertexLighting) * diffColor.rgb;
+    float3 finalColor = iVertexLighting * diffColor.rgb;
 
-    oColor = float4(GetFog(finalColor, iTexCoord.w), diffColor.a);
+    oColor = float4(GetFog(finalColor, iTexCoord.z), diffColor.a);
 }

+ 3 - 3
SourceAssets/HLSLShaders/CMakeLists.txt

@@ -2,13 +2,13 @@ set (ALL_SHADERS)
 
 add_shader (Ambient)
 add_shader (Basic)
-add_shader (BlinnPhong)
+add_shader (DeferredLight)
+add_shader (ForwardLit)
 add_shader (GBuffer)
-add_shader (LightVolume)
+add_shader (LitParticle)
 add_shader (Material)
 add_shader (Shadow)
 add_shader (Stencil)
 add_shader (Unlit)
-add_shader (Volumetric)
 
 add_custom_target (Shaders ALL DEPENDS ${ALL_SHADERS})

+ 4 - 4
SourceAssets/HLSLShaders/LightVolume.hlsl → SourceAssets/HLSLShaders/DeferredLight.hlsl

@@ -118,11 +118,11 @@ void PS(
 
     #ifdef SHADOW
         #if defined(DIRLIGHT)
-            float4x4 shadowMatrix = GetDirShadowMatrix(depth);
+            float4x4 shadowMatrix = GetDirShadowMatrix(depth, cLightMatricesPS);
             float4 shadowPos = mul(float4(worldPos, 1.0), shadowMatrix);
             diff *= saturate(GetShadow(shadowPos) + GetShadowFade(depth));
         #elif defined(SPOTLIGHT)
-            float4 shadowPos = mul(float4(worldPos, 1.0), cShadowProjPS[1]);
+            float4 shadowPos = mul(float4(worldPos, 1.0), cLightMatricesPS[1]);
             diff *= GetShadow(shadowPos);
         #else
             float3 shadowPos = worldPos - cLightPosPS.xyz;
@@ -131,11 +131,11 @@ void PS(
     #endif
 
     #ifdef SPOTLIGHT
-        float4 spotPos = mul(float4(worldPos, 1.0), cShadowProjPS[0]);
+        float4 spotPos = mul(float4(worldPos, 1.0), cLightMatricesPS[0]);
         lightColor = spotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : 0.0;
     #else
         #ifdef CUBEMASK
-            lightColor = texCUBE(sLightCubeMap, mul(lightVec, (float3x3)cShadowProjPS[0])).rgb * cLightColor.rgb;
+            lightColor = texCUBE(sLightCubeMap, mul(lightVec, (float3x3)cLightMatricesPS[0])).rgb * cLightColor.rgb;
         #else
             lightColor = cLightColor.rgb;
         #endif

+ 2 - 2
SourceAssets/HLSLShaders/LightVolume.xml → SourceAssets/HLSLShaders/DeferredLight.xml

@@ -1,9 +1,9 @@
 <shaders>
-    <shader name="LightVolume" type="vs">
+    <shader name="DeferredLight" type="vs">
         <option name="Ortho" define="ORTHO" />
         <option name="Dir" define="DIRLIGHT" />
     </shader>
-    <shader name="LightVolume" type="ps">
+    <shader name="DeferredLight" type="ps">
         <option name="Linear" define="LINEAR" exclude="Ortho" />
         <option name="Ortho" define="ORTHO" exclude="Linear" />
         <variation name="Dir" define="DIRLIGHT" />

+ 13 - 18
SourceAssets/HLSLShaders/BlinnPhong.hlsl → SourceAssets/HLSLShaders/ForwardLit.hlsl

@@ -23,7 +23,7 @@ void VS(float4 iPos : POSITION,
     #ifdef BILLBOARD
         float2 iSize : TEXCOORD1,
     #endif
-    out float4 oTexCoord : TEXCOORD0,
+    out float3 oTexCoord : TEXCOORD0,
     out float3 oLightVec : TEXCOORD1,
     #ifndef NORMALMAP
         out float3 oNormal : TEXCOORD2,
@@ -54,7 +54,7 @@ void VS(float4 iPos : POSITION,
     float4x3 modelMatrix = iModelMatrix;
     float3 worldPos = GetWorldPos(modelMatrix);
     oPos = GetClipPos(worldPos);
-    oTexCoord = float4(GetTexCoord(iTexCoord), GetZonePos(worldPos), GetDepth(oPos));
+    oTexCoord = float3(GetTexCoord(iTexCoord), GetDepth(oPos));
 
     #ifdef VERTEXCOLOR
         oColor = iColor;
@@ -78,12 +78,12 @@ void VS(float4 iPos : POSITION,
     #ifdef SHADOW
         // Shadow projection: transform from world space to shadow space
         #if defined(DIRLIGHT)
-            oShadowPos[0] = mul(projWorldPos, cShadowProj[0]);
-            oShadowPos[1] = mul(projWorldPos, cShadowProj[1]);
-            oShadowPos[2] = mul(projWorldPos, cShadowProj[2]);
-            oShadowPos[3] = mul(projWorldPos, cShadowProj[3]);
+            oShadowPos[0] = mul(projWorldPos, cLightMatrices[0]);
+            oShadowPos[1] = mul(projWorldPos, cLightMatrices[1]);
+            oShadowPos[2] = mul(projWorldPos, cLightMatrices[2]);
+            oShadowPos[3] = mul(projWorldPos, cLightMatrices[3]);
         #elif defined(SPOTLIGHT)
-            oShadowPos = mul(projWorldPos, cShadowProj[0]);
+            oShadowPos = mul(projWorldPos, cLightMatrices[1]);
         #else
             oShadowPos = worldPos - cLightPos.xyz;
         #endif
@@ -91,11 +91,11 @@ void VS(float4 iPos : POSITION,
 
     #ifdef SPOTLIGHT
         // Spotlight projection: transform from world space to projector texture coordinates
-        oSpotPos = mul(projWorldPos, cSpotProj);
+        oSpotPos = mul(projWorldPos, cLightMatrices[0]);
     #endif
 
     #ifdef POINTLIGHT
-        oCubeMaskVec = mul(oLightVec, cLightVecRot);
+        oCubeMaskVec = mul(oLightVec, (float3x3)cLightMatrices[0]);
     #endif
 
     #ifdef NORMALMAP
@@ -111,7 +111,7 @@ void VS(float4 iPos : POSITION,
     #endif
 }
 
-void PS(float4 iTexCoord : TEXCOORD0,
+void PS(float3 iTexCoord : TEXCOORD0,
     float3 iLightVec : TEXCOORD1,
     #ifndef NORMALMAP
         float3 iNormal : TEXCOORD2,
@@ -173,8 +173,8 @@ void PS(float4 iTexCoord : TEXCOORD0,
 
     #ifdef SHADOW
         #if defined(DIRLIGHT)
-            float4 shadowPos = GetDirShadowPos(iShadowPos, iTexCoord.w);
-            diff *= saturate(GetShadow(shadowPos) + GetShadowFade(iTexCoord.w));
+            float4 shadowPos = GetDirShadowPos(iShadowPos, iTexCoord.z);
+            diff *= saturate(GetShadow(shadowPos) + GetShadowFade(iTexCoord.z));
         #elif defined(SPOTLIGHT)
             diff *= GetShadow(iShadowPos);
         #else
@@ -202,10 +202,5 @@ void PS(float4 iTexCoord : TEXCOORD0,
         finalColor = diff * lightColor * diffColor.rgb;
     #endif
 
-    #ifdef AMBIENT
-        finalColor += GetAmbient(iTexCoord.z) * diffColor.rgb;
-        oColor = float4(GetFog(finalColor, iTexCoord.w), diffColor.a);
-    #else
-        oColor = float4(GetLitFog(finalColor, iTexCoord.w), diffColor.a);
-    #endif
+    oColor = float4(GetLitFog(finalColor, iTexCoord.z), diffColor.a);
 }

+ 2 - 3
SourceAssets/HLSLShaders/BlinnPhong.xml → SourceAssets/HLSLShaders/ForwardLit.xml

@@ -1,5 +1,5 @@
 <shaders>
-    <shader name="BlinnPhong" type="vs">
+    <shader name="ForwardLit" type="vs">
         <option name="Normal" define="NORMALMAP" />
         <option name="VCol" define="VERTEXCOLOR" />
         <variation name="Dir" define="DIRLIGHT" />
@@ -12,12 +12,11 @@
         <variation name="Instanced" define="INSTANCED" require="SM3" />
         <variation name="Billboard" define="BILLBOARD" />
     </shader>
-    <shader name="BlinnPhong" type="ps">
+    <shader name="ForwardLit" type="ps">
         <option name="Diff" define="DIFFMAP" />
         <option name="Normal" define="NORMALMAP" require="DIFFMAP" />
         <option name="SpecMap" define="SPECMAP" require="DIFFMAP" />
         <option name="VCol" define="VERTEXCOLOR" />
-        <option name="Ambient" define="AMBIENT" />
         <variation name="Dir" define="DIRLIGHT" />
         <variation name="Spot" define="SPOTLIGHT" />
         <variation name="Point" define="POINTLIGHT" />

+ 1 - 1
SourceAssets/HLSLShaders/GBuffer.xml

@@ -9,7 +9,7 @@
     <shader name="GBuffer" type="ps">
         <option name="Normal" define="NORMALMAP" />
         <option name="Spec" define="SPECMAP" />
-        <option name="Mask" define="ALPHAMASK" include="Diff" />
+        <option name="Mask" define="ALPHAMASK" />
         <option name="HW" define="HWDEPTH" exclude="FB" />
         <option name="FB" define="FALLBACK" exclude="HW" />
     </shader>

+ 8 - 8
SourceAssets/HLSLShaders/Lighting.hlsl

@@ -157,24 +157,24 @@ float4 GetDirShadowPos(const float4 iShadowPos[4], float depth)
         return iShadowPos[3];
 }
 
-float4x4 GetDirShadowMatrix(float depth)
+float4x4 GetDirShadowMatrix(float depth, const float4x4 matrices[4])
 {
     #ifdef SM3
         if (depth < cShadowSplits.x)
-            return cShadowProjPS[0];
+            return matrices[0];
         else if (depth < cShadowSplits.y)
-            return cShadowProjPS[1];
+            return matrices[1];
         else if (depth < cShadowSplits.z)
-            return cShadowProjPS[2];
+            return matrices[2];
         else
-            return cShadowProjPS[3];
+            return matrices[3];
     #else
         if (depth < cShadowSplits.x)
-            return cShadowProjPS[0];
+            return matrices[0];
         else if (depth < cShadowSplits.y)
-            return cShadowProjPS[1];
+            return matrices[1];
         else
-            return cShadowProjPS[2];
+            return matrices[2];
     #endif
 }
 

+ 11 - 21
SourceAssets/HLSLShaders/Volumetric.hlsl → SourceAssets/HLSLShaders/LitParticle.hlsl

@@ -20,14 +20,13 @@ void VS(float4 iPos : POSITION,
     #ifdef BILLBOARD
         float2 iSize : TEXCOORD1,
     #endif
-    out float2 oTexCoord : TEXCOORD0,
+    out float3 oTexCoord : TEXCOORD0,
     out float3 oLightVec : TEXCOORD1,
-    out float2 oZonePosDepth : TEXCOORD2,
     #ifdef SPOTLIGHT
-        out float4 oSpotPos : TEXCOORD3,
+        out float4 oSpotPos : TEXCOORD2,
     #endif
     #ifdef POINTLIGHT
-        out float3 oCubeMaskVec : TEXCOORD3,
+        out float3 oCubeMaskVec : TEXCOORD2,
     #endif
     #ifdef VERTEXCOLOR
         out float4 oColor : COLOR0,
@@ -37,7 +36,7 @@ void VS(float4 iPos : POSITION,
     float4x3 modelMatrix = iModelMatrix;
     float3 worldPos = GetWorldPos(modelMatrix);
     oPos = GetClipPos(worldPos);
-    oTexCoord = GetTexCoord(iTexCoord);
+    oTexCoord = float3(GetTexCoord(iTexCoord), GetDepth(oPos));
 
     #ifdef VERTEXCOLOR
         oColor = iColor;
@@ -51,26 +50,23 @@ void VS(float4 iPos : POSITION,
         oLightVec = (cLightPos.xyz - worldPos) * cLightPos.w;
     #endif
 
-    oZonePosDepth = float2(GetZonePos(worldPos), GetDepth(oPos));
-
     #ifdef SPOTLIGHT
         // Spotlight projection: transform from world space to projector texture coordinates
-        oSpotPos = mul(projWorldPos, cSpotProj);
+        oSpotPos = mul(projWorldPos, cLightMatrices[0]);
     #endif
 
     #ifdef POINTLIGHT
-        oCubeMaskVec = mul(oLightVec, cLightVecRot);
+        oCubeMaskVec = mul(oLightVec, (float3x3)cLightMatrices[0]);
     #endif
 }
 
-void PS(float2 iTexCoord : TEXCOORD0,
+void PS(float3 iTexCoord : TEXCOORD0,
     float3 iLightVec : TEXCOORD1,
-    float2 iZonePosDepth : TEXCOORD2,
     #ifdef SPOTLIGHT
-        float4 iSpotPos : TEXCOORD3,
+        float4 iSpotPos : TEXCOORD2,
     #endif
     #ifdef CUBEMASK
-        float3 iCubeMaskVec : TEXCOORD3,
+        float3 iCubeMaskVec : TEXCOORD2,
     #endif
     #ifdef VERTEXCOLOR
         float4 iColor : COLOR0,
@@ -78,7 +74,7 @@ void PS(float2 iTexCoord : TEXCOORD0,
     out float4 oColor : COLOR0)
 {
     #ifdef DIFFMAP
-        float4 diffColor = cMatDiffColor * tex2D(sDiffMap, iTexCoord);
+        float4 diffColor = cMatDiffColor * tex2D(sDiffMap, iTexCoord.xy);
     #else
         float4 diffColor = cMatDiffColor;
     #endif
@@ -106,11 +102,5 @@ void PS(float2 iTexCoord : TEXCOORD0,
     #endif
 
     finalColor = diff * lightColor * diffColor.rgb;
-
-    #ifdef AMBIENT
-        finalColor += GetAmbient(iZonePosDepth.x) * diffColor.rgb;
-        oColor = float4(GetFog(finalColor, iZonePosDepth.y), diffColor.a);
-    #else
-        oColor = float4(GetLitFog(finalColor, iZonePosDepth.y), diffColor.a);
-    #endif
+    oColor = float4(GetLitFog(finalColor, iTexCoord.z), diffColor.a);
 }

+ 2 - 3
SourceAssets/HLSLShaders/Volumetric.xml → SourceAssets/HLSLShaders/LitParticle.xml

@@ -1,5 +1,5 @@
 <shaders>
-    <shader name="Volumetric" type="vs">
+    <shader name="LitParticle" type="vs">
         <option name="VCol" define="VERTEXCOLOR" />
         <variation name="Dir" define="DIRLIGHT" />
         <variation name="Spot" define="SPOTLIGHT" />
@@ -10,10 +10,9 @@
         <variation name="Instanced" define="INSTANCED" require="SM3" />
         <variation name="Billboard" define="BILLBOARD" />
     </shader>
-    <shader name="Volumetric" type="ps">
+    <shader name="LitParticle" type="ps">
         <option name="Diff" define="DIFFMAP" />
         <option name="VCol" define="VERTEXCOLOR" />
-        <option name="Ambient" define="AMBIENT" />
         <variation name="Dir" define="DIRLIGHT" />
         <variation name="Spot" define="SPOTLIGHT" />
         <variation name="Point" define="POINTLIGHT" />

+ 6 - 7
SourceAssets/HLSLShaders/Material.hlsl

@@ -19,7 +19,7 @@ void VS(float4 iPos : POSITION,
         float4x3 iModelInstance : TEXCOORD2,
     #endif
     float2 iTexCoord : TEXCOORD0,
-    out float4 oTexCoord : TEXCOORD0,
+    out float3 oTexCoord : TEXCOORD0,
     out float3 oVertexLighting : TEXCOORD1,
     out float4 oScreenPos : TEXCOORD2,
     #ifdef VERTEXCOLOR
@@ -30,11 +30,10 @@ void VS(float4 iPos : POSITION,
     float4x3 modelMatrix = iModelMatrix;
     float3 worldPos = GetWorldPos(modelMatrix);
     oPos = GetClipPos(worldPos);
-
-    oTexCoord = float4(GetTexCoord(iTexCoord), GetZonePos(worldPos), GetDepth(oPos));
+    oTexCoord = float3(GetTexCoord(iTexCoord), GetDepth(oPos));
     oScreenPos = GetScreenPos(oPos);
-    oVertexLighting = 0.0;
 
+    oVertexLighting = GetAmbient(GetZonePos(worldPos));
     #ifdef NUMVERTEXLIGHTS
     float3 normal = GetWorldNormal(modelMatrix);
     for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
@@ -46,7 +45,7 @@ void VS(float4 iPos : POSITION,
     #endif
 }
 
-void PS(float4 iTexCoord : TEXCOORD0,
+void PS(float3 iTexCoord : TEXCOORD0,
     float3 iVertexLighting : TEXCOORD1,
     float4 iScreenPos : TEXCOORD2,
     #ifdef VERTEXCOLOR
@@ -75,6 +74,6 @@ void PS(float4 iTexCoord : TEXCOORD0,
     float4 lightInput = 2.0 * tex2Dproj(sLightBuffer, iScreenPos);
     float3 lightSpecColor = lightInput.a * (lightInput.rgb / GetIntensity(lightInput.rgb));
 
-    float3 finalColor = (GetAmbient(iTexCoord.z) + iVertexLighting + lightInput.rgb) * diffColor + lightSpecColor * specIntensity;
-    oColor = float4(GetFog(finalColor, iTexCoord.w), 1.0);
+    float3 finalColor = (iVertexLighting + lightInput.rgb) * diffColor + lightSpecColor * specIntensity;
+    oColor = float4(GetFog(finalColor, iTexCoord.z), 1.0);
 }

+ 34 - 36
SourceAssets/HLSLShaders/Uniforms.hlsl

@@ -1,39 +1,37 @@
 // Vertex shader parameters
-uniform float3 cCameraPos : register(C0);
-uniform float3x3 cCameraRot : register(C1);
-uniform float4 cDepthMode : register(C4);
-uniform float3 cFrustumSize : register(C5);
-uniform float4 cGBufferOffsets : register(C6);
-uniform float3 cLightDir : register(C7);
-uniform float4 cLightPos : register(C8);
-uniform float3x3 cLightVecRot: register(C9);
-uniform float4x3 cModel : register(C12);
-uniform float4x4 cSpotProj : register(C15);
-uniform float4x4 cViewProj : register(C19);
-uniform float4 cUOffset : register(C23);
-uniform float4 cVOffset : register(C24);
-uniform float3 cViewRightVector : register(C25);
-uniform float3 cViewUpVector : register(C26);
-uniform float4x3 cZone : register(C27);
-uniform float4x4 cShadowProj[4] : register(C30);
-uniform float4x3 cSkinMatrices[64] : register(C46);
-uniform float4 cVertexLights[6*3] : register(C238);
-
-// Pixel shader parameters
 uniform float3 cAmbientStartColor : register(C0);
 uniform float3 cAmbientEndColor : register(C1);
-uniform float2 cDepthReconstruct : register(C2);
-uniform float4 cFogParams : register(C3);
-uniform float3 cFogColor : register(C4);
-uniform float4 cLightColor : register(C5);
-uniform float4 cLightPosPS : register(C6);
-uniform float3 cLightDirPS : register(C7);
-uniform float4 cMatDiffColor : register(C8);
-uniform float3 cMatEmissiveColor : register(C9);
-uniform float2 cMatSpecProperties : register(C10);
-uniform float2 cSampleOffsets : register(C11);
-uniform float4 cShadowCubeAdjust : register(C12);
-uniform float4 cShadowDepthFade : register(C13);
-uniform float4 cShadowIntensity : register(C14);
-uniform float4 cShadowSplits : register(C15);
-uniform float4x4 cShadowProjPS[4] :  register(C16);
+uniform float3 cCameraPos : register(C2);
+uniform float3x3 cCameraRot : register(C3);
+uniform float4 cDepthMode : register(C6);
+uniform float3 cFrustumSize : register(C7);
+uniform float4 cGBufferOffsets : register(C8);
+uniform float3 cLightDir : register(C9);
+uniform float4 cLightPos : register(C10);
+uniform float4x3 cModel : register(C11);
+uniform float4x4 cViewProj : register(C14);
+uniform float4 cUOffset : register(C18);
+uniform float4 cVOffset : register(C19);
+uniform float3 cViewRightVector : register(C20);
+uniform float3 cViewUpVector : register(C21);
+uniform float4x3 cZone : register(C22);
+uniform float4x4 cLightMatrices[4] : register(C25);
+uniform float4x3 cSkinMatrices[64] : register(C41);
+uniform float4 cVertexLights[6*3] : register(C233);
+
+// Pixel shader parameters
+uniform float2 cDepthReconstruct : register(C0);
+uniform float4 cFogParams : register(C1);
+uniform float3 cFogColor : register(C2);
+uniform float4 cLightColor : register(C3);
+uniform float4 cLightPosPS : register(C4);
+uniform float3 cLightDirPS : register(C5);
+uniform float4 cMatDiffColor : register(C6);
+uniform float3 cMatEmissiveColor : register(C7);
+uniform float2 cMatSpecProperties : register(C8);
+uniform float2 cSampleOffsets : register(C9);
+uniform float4 cShadowCubeAdjust : register(C10);
+uniform float4 cShadowDepthFade : register(C11);
+uniform float4 cShadowIntensity : register(C12);
+uniform float4 cShadowSplits : register(C13);
+uniform float4x4 cLightMatricesPS[4] :  register(C14);