浏览代码

Re-added the alpha masking hint to give priority to fully opaque materials.

Lasse Öörni 13 年之前
父节点
当前提交
5d55c0959d

+ 7 - 7
Bin/CoreData/Techniques/DiffAlphaMask.xml

@@ -1,9 +1,9 @@
 <technique>
 <technique>
-    <pass name="base" vs="Ambient" ps="Ambient_DiffAlphaMask" />
-    <pass name="litbase" vs="ForwardLit" ps="ForwardLit_DiffAlphaMaskAmbient" />
-    <pass name="light" vs="ForwardLit" ps="ForwardLit_DiffAlphaMask"  depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="shadow" vs="Shadow_Mask" ps="Shadow_AlphaMask" />
-    <pass name="prepass" vs="Prepass" ps="Prepass_AlphaMask" />
-    <pass name="material" vs="Material" ps="Material_DiffAlphaMask" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vs="Deferred" ps="Deferred_DiffAlphaMask" />
+    <pass name="base" vs="Ambient" ps="Ambient_DiffAlphaMask" alphamask="true" />
+    <pass name="litbase" vs="ForwardLit" ps="ForwardLit_DiffAlphaMaskAmbient" alphamask="true" />
+    <pass name="light" vs="ForwardLit" ps="ForwardLit_DiffAlphaMask"  depthtest="equal" depthwrite="false" blend="add" alphamask="true" />
+    <pass name="shadow" vs="Shadow_Mask" ps="Shadow_AlphaMask" alphamask="true" />
+    <pass name="prepass" vs="Prepass" ps="Prepass_AlphaMask" alphamask="true" />
+    <pass name="material" vs="Material" ps="Material_DiffAlphaMask" depthtest="equal" depthwrite="false" alphamask="true" />
+    <pass name="deferred" vs="Deferred" ps="Deferred_DiffAlphaMask" alphamask="true" />
 </technique>
 </technique>

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

@@ -1,9 +1,9 @@
 <technique>
 <technique>
-    <pass name="base" vs="Ambient" ps="Ambient_DiffAlphaMask" />
-    <pass name="litbase" vs="ForwardLit_Normal" ps="ForwardLit_DiffNormalAlphaMaskAmbient" />
-    <pass name="light" vs="ForwardLit_Normal" ps="ForwardLit_DiffNormalAlphaMask" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="shadow" vs="Shadow_Mask" ps="Shadow_AlphaMask" />
-    <pass name="prepass" vs="Prepass_Normal" ps="Prepass_NormalAlphaMask" />
-    <pass name="material" vs="Material" ps="Material_DiffAlphaMask" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vs="Deferred_Normal" ps="Deferred_DiffNormalAlphaMask" />
+    <pass name="base" vs="Ambient" ps="Ambient_DiffAlphaMask" alphamask="true" />
+    <pass name="litbase" vs="ForwardLit_Normal" ps="ForwardLit_DiffNormalAlphaMaskAmbient" alphamask="true" />
+    <pass name="light" vs="ForwardLit_Normal" ps="ForwardLit_DiffNormalAlphaMask" depthtest="equal" depthwrite="false" blend="add" alphamask="true" />
+    <pass name="shadow" vs="Shadow_Mask" ps="Shadow_AlphaMask" alphamask="true" />
+    <pass name="prepass" vs="Prepass_Normal" ps="Prepass_NormalAlphaMask" alphamask="true" />
+    <pass name="material" vs="Material" ps="Material_DiffAlphaMask" depthtest="equal" depthwrite="false" alphamask="true" />
+    <pass name="deferred" vs="Deferred_Normal" ps="Deferred_DiffNormalAlphaMask" alphamask="true" />
 </technique>
 </technique>

+ 3 - 1
Docs/Reference.dox

@@ -584,7 +584,7 @@ A technique definition looks like this:
 <technique>
 <technique>
     <pass name="base|litbase|light|prealpha|postalpha|prepass|material|deferred|shadow" vs="VertexShaderName" ps="PixelShaderName"
     <pass name="base|litbase|light|prealpha|postalpha|prepass|material|deferred|shadow" vs="VertexShaderName" ps="PixelShaderName"
         alphatest="true|false" blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha"
         alphatest="true|false" blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha"
-        depthtest="always|equal|less|lessequal|greater|greaterequal" depthwrite="true|false" />
+        depthtest="always|equal|less|lessequal|greater|greaterequal" depthwrite="true|false" alphamask="true|false" />
     <pass ... />
     <pass ... />
     <pass ... />
     <pass ... />
 </technique>
 </technique>
@@ -608,6 +608,8 @@ Note that the technique does not need to enumerate shaders used for different ge
 
 
 The optional "litbase" pass reduces draw call count by combining ambient lighting with the first per-pixel light affecting an object. However, it has intentional limitations to not require too many shader permutations: there must be no vertex lights affecting the object, and the ambient lighting can not have a gradient. In case of excessive overdraw, it is possibly better not to define it, but instead allow the base pass (which is computationally very lightweight) to run first, initializing the Z buffer for later passes.
 The optional "litbase" pass reduces draw call count by combining ambient lighting with the first per-pixel light affecting an object. However, it has intentional limitations to not require too many shader permutations: there must be no vertex lights affecting the object, and the ambient lighting can not have a gradient. In case of excessive overdraw, it is possibly better not to define it, but instead allow the base pass (which is computationally very lightweight) to run first, initializing the Z buffer for later passes.
 
 
+"Alphamask" is not an actual rendering state, but a hint which tells that the pixel shader will use discard based on alpha. Because this may interfere with the early-Z culling, materials without the alpha masking hint will be drawn first.
+
 
 
 \page Lights Lights and shadows
 \page Lights Lights and shadows
 
 

+ 1 - 0
Docs/ScriptAPI.dox

@@ -1673,6 +1673,7 @@ Properties:<br>
 - BlendMode blendMode
 - BlendMode blendMode
 - CompareMode depthTestMode
 - CompareMode depthTestMode
 - bool depthWrite
 - bool depthWrite
+- bool alphaMask
 - String vertexShader
 - String vertexShader
 - String pixelShader
 - String pixelShader
 
 

+ 2 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -332,6 +332,8 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Pass", "CompareMode get_depthTestMode() const", asMETHOD(Pass, GetDepthTestMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "CompareMode get_depthTestMode() const", asMETHOD(Pass, GetDepthTestMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_depthWrite(bool)", asMETHOD(Pass, SetDepthWrite), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_depthWrite(bool)", asMETHOD(Pass, SetDepthWrite), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_depthWrite() const", asMETHOD(Pass, GetDepthWrite), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_depthWrite() const", asMETHOD(Pass, GetDepthWrite), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pass", "void set_alphaMask(bool)", asMETHOD(Pass, SetAlphaMask), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pass", "bool get_alphaMask() const", asMETHOD(Pass, GetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_vertexShader(const String&in)", asMETHOD(Pass, SetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_vertexShader(const String&in)", asMETHOD(Pass, SetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "const String& get_vertexShader() const", asMETHOD(Pass, GetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "const String& get_vertexShader() const", asMETHOD(Pass, GetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_pixelShader(const String&in)", asMETHOD(Pass, SetPixelShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_pixelShader(const String&in)", asMETHOD(Pass, SetPixelShader), asCALL_THISCALL);

+ 8 - 4
Engine/Graphics/Batch.cpp

@@ -63,7 +63,10 @@ inline bool CompareInstancesFrontToBack(const InstanceData& lhs, const InstanceD
 
 
 inline bool CompareBatchGroupsFrontToBack(BatchGroup* lhs, BatchGroup* rhs)
 inline bool CompareBatchGroupsFrontToBack(BatchGroup* lhs, BatchGroup* rhs)
 {
 {
-    return lhs->distance_ < rhs->distance_;
+    if (lhs->sortKey_ == rhs->sortKey_)
+        return lhs->distance_ < rhs->distance_;
+    else
+        return lhs->sortKey_ > rhs->sortKey_;
 }
 }
 
 
 void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split, Renderer* renderer, const Vector3& translation)
 void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split, Renderer* renderer, const Vector3& translation)
@@ -152,12 +155,14 @@ void CalculateSpotMatrix(Matrix4& dest, Light* light, const Vector3& translation
 
 
 void Batch::CalculateSortKey()
 void Batch::CalculateSortKey()
 {
 {
-    unsigned lightQueue = (*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0x7fff;
+    unsigned lightQueue = (*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0x3fff;
     unsigned pass = (*((unsigned*)&pass_) / sizeof(Pass)) & 0xffff;
     unsigned pass = (*((unsigned*)&pass_) / sizeof(Pass)) & 0xffff;
     unsigned material = (*((unsigned*)&material_) / sizeof(Material)) & 0xffff;
     unsigned material = (*((unsigned*)&material_) / sizeof(Material)) & 0xffff;
     unsigned geometry = (*((unsigned*)&geometry_) / sizeof(Geometry)) & 0xffff;
     unsigned geometry = (*((unsigned*)&geometry_) / sizeof(Geometry)) & 0xffff;
     if (isBase_)
     if (isBase_)
         lightQueue |= 0x8000;
         lightQueue |= 0x8000;
+    if (pass_ && !pass_->GetAlphaMask())
+        lightQueue |= 0x4000;
     sortKey_ = (((unsigned long long)lightQueue) << 48) | (((unsigned long long)pass) << 32) |
     sortKey_ = (((unsigned long long)lightQueue) << 48) | (((unsigned long long)pass) << 32) |
         (((unsigned long long)material) << 16) | geometry;
         (((unsigned long long)material) << 16) | geometry;
 }
 }
@@ -718,8 +723,7 @@ void BatchQueue::SortFrontToBack()
     sortedBaseBatches_.Clear();
     sortedBaseBatches_.Clear();
     sortedBatches_.Clear();
     sortedBatches_.Clear();
     
     
-    // Must explicitly divide into base and non-base batches, so that priorities do not get mixed up between
-    // instanced and non-instanced batches
+    // Need to divide into base and non-base batches here to ensure proper order in relation to grouped batches
     for (unsigned i = 0; i < batches_.Size(); ++i)
     for (unsigned i = 0; i < batches_.Size(); ++i)
     {
     {
         if (batches_[i].isBase_)
         if (batches_[i].isBase_)

+ 1 - 1
Engine/Graphics/Material.cpp

@@ -418,7 +418,7 @@ void Material::CheckOcclusion()
         if (tech)
         if (tech)
         {
         {
             Pass* pass = tech->GetPass(PASS_BASE);
             Pass* pass = tech->GetPass(PASS_BASE);
-            if (pass && pass->GetDepthWrite())
+            if (pass && pass->GetDepthWrite() && !pass->GetAlphaMask())
                 occlusion_ = true;
                 occlusion_ = true;
         }
         }
     }
     }

+ 10 - 1
Engine/Graphics/Technique.cpp

@@ -75,7 +75,8 @@ Pass::Pass(PassType type) :
     type_(type),
     type_(type),
     blendMode_(BLEND_REPLACE),
     blendMode_(BLEND_REPLACE),
     depthTestMode_(CMP_LESSEQUAL),
     depthTestMode_(CMP_LESSEQUAL),
-    depthWrite_(true)
+    depthWrite_(true),
+    alphaMask_(false)
 {
 {
 }
 }
 
 
@@ -98,6 +99,11 @@ void Pass::SetDepthWrite(bool enable)
     depthWrite_ = enable;
     depthWrite_ = enable;
 }
 }
 
 
+void Pass::SetAlphaMask(bool enable)
+{
+    alphaMask_ = enable;
+}
+
 void Pass::SetVertexShader(const String& name)
 void Pass::SetVertexShader(const String& name)
 {
 {
     vertexShaderName_ = name;
     vertexShaderName_ = name;
@@ -187,6 +193,9 @@ bool Technique::Load(Deserializer& source)
             
             
             if (passElem.HasAttribute("depthwrite"))
             if (passElem.HasAttribute("depthwrite"))
                 newPass->SetDepthWrite(passElem.GetBool("depthwrite"));
                 newPass->SetDepthWrite(passElem.GetBool("depthwrite"));
+            
+            if (passElem.HasAttribute("alphamask"))
+                newPass->SetAlphaMask(passElem.GetBool("alphamask"));
         }
         }
         
         
         passElem = passElem.GetNext("pass");
         passElem = passElem.GetNext("pass");

+ 9 - 6
Engine/Graphics/Technique.h

@@ -43,6 +43,8 @@ public:
     void SetDepthTestMode(CompareMode mode);
     void SetDepthTestMode(CompareMode mode);
     /// %Set depth write on/off.
     /// %Set depth write on/off.
     void SetDepthWrite(bool enable);
     void SetDepthWrite(bool enable);
+    /// %Set alpha masking hint. Completely opaque draw calls will be performed before alpha masked.
+    void SetAlphaMask(bool enable);
     /// %Set vertex shader name.
     /// %Set vertex shader name.
     void SetVertexShader(const String& name);
     void SetVertexShader(const String& name);
     /// %Set pixel shader name.
     /// %Set pixel shader name.
@@ -58,6 +60,8 @@ public:
     CompareMode GetDepthTestMode() const { return depthTestMode_; }
     CompareMode GetDepthTestMode() const { return depthTestMode_; }
     /// Return depth write mode.
     /// Return depth write mode.
     bool GetDepthWrite() const { return depthWrite_; }
     bool GetDepthWrite() const { return depthWrite_; }
+    /// Return alpha masking hint.
+    bool GetAlphaMask() const { return alphaMask_; }
     /// Return vertex shader name.
     /// Return vertex shader name.
     const String& GetVertexShader() const { return vertexShaderName_; }
     const String& GetVertexShader() const { return vertexShaderName_; }
     /// Return pixel shader name.
     /// Return pixel shader name.
@@ -76,6 +80,8 @@ private:
     CompareMode depthTestMode_;
     CompareMode depthTestMode_;
     /// Depth write mode.
     /// Depth write mode.
     bool depthWrite_;
     bool depthWrite_;
+    /// Alpha masking hint.
+    bool alphaMask_;
     /// Vertex shader name.
     /// Vertex shader name.
     String vertexShaderName_;
     String vertexShaderName_;
     /// Pixel shader name.
     /// Pixel shader name.
@@ -104,7 +110,7 @@ public:
     /// Load resource. Return true if successful.
     /// Load resource. Return true if successful.
     virtual bool Load(Deserializer& source);
     virtual bool Load(Deserializer& source);
     
     
-    /// %Set whether requires Shader Model 3.
+    /// %Set whether requires %Shader %Model 3.
     void SetIsSM3(bool enable);
     void SetIsSM3(bool enable);
     /// Create a new pass.
     /// Create a new pass.
     Pass* CreatePass(PassType pass);
     Pass* CreatePass(PassType pass);
@@ -112,17 +118,14 @@ public:
     void RemovePass(PassType pass);
     void RemovePass(PassType pass);
     /// Reset shader pointers in all passes.
     /// Reset shader pointers in all passes.
     void ReleaseShaders();
     void ReleaseShaders();
-    
     /// Mark shaders loaded this frame
     /// Mark shaders loaded this frame
     void MarkShadersLoaded(unsigned frameNumber);
     void MarkShadersLoaded(unsigned frameNumber);
     
     
     /// Return whether has a pass.
     /// Return whether has a pass.
     bool HasPass(PassType pass) const { return passes_[pass] != 0; }
     bool HasPass(PassType pass) const { return passes_[pass] != 0; }
-    
     /// Return a pass.
     /// Return a pass.
     Pass* GetPass(PassType pass) const { return passes_[pass]; }
     Pass* GetPass(PassType pass) const { return passes_[pass]; }
-    
-    /// Return whether requires Shader Model 3.
+    /// Return whether requires %Shader %Model 3.
     bool IsSM3() const { return isSM3_; }
     bool IsSM3() const { return isSM3_; }
     /// Return last shaders loaded frame number.
     /// Return last shaders loaded frame number.
     unsigned GetShadersLoadedFrameNumber() const { return shadersLoadedFrameNumber_; }
     unsigned GetShadersLoadedFrameNumber() const { return shadersLoadedFrameNumber_; }
@@ -131,7 +134,7 @@ public:
     static const String& GetPassName(PassType pass);
     static const String& GetPassName(PassType pass);
     
     
 private:
 private:
-    /// Require Shader Model 3 flag.
+    /// Require %Shader %Model 3 flag.
     bool isSM3_;
     bool isSM3_;
     /// Last shaders loaded frame number.
     /// Last shaders loaded frame number.
     unsigned shadersLoadedFrameNumber_;
     unsigned shadersLoadedFrameNumber_;

+ 3 - 0
Engine/Graphics/View.cpp

@@ -2360,6 +2360,9 @@ void View::AddBatchToQueue(BatchQueue& batchQueue, Batch& batch, Technique* tech
             // Create a new group based on the batch
             // Create a new group based on the batch
             renderer_->SetBatchShaders(batch, tech, allowShadows);
             renderer_->SetBatchShaders(batch, tech, allowShadows);
             BatchGroup newGroup(batch);
             BatchGroup newGroup(batch);
+            // Retain only the base & alpha mask bits of the sort key
+            newGroup.CalculateSortKey();
+            newGroup.sortKey_ &= 0xc000000000000000ULL;
             newGroup.instances_.Push(InstanceData(batch.worldTransform_, batch.distance_));
             newGroup.instances_.Push(InstanceData(batch.worldTransform_, batch.distance_));
             groups->Insert(MakePair(key, newGroup));
             groups->Insert(MakePair(key, newGroup));
         }
         }