瀏覽代碼

8-bit render order support in materials. This adjusts the drawing order within a scene pass, and takes precedence over both state & distance sorting.

Lasse Öörni 10 年之前
父節點
當前提交
b53b584123

+ 3 - 0
Docs/Reference.dox

@@ -1004,6 +1004,7 @@ A material definition looks like this:
     <shadowcull value="cw|ccw|none" />
     <fill value="solid|wireframe|point" />
     <depthbias constant="x" slopescaled="y" />
+    <renderorder value="x" />
 </material>
 \endcode
 
@@ -1021,6 +1022,8 @@ The techniques for different LOD levels and quality settings must appear in a sp
 
 Default culling mode is counterclockwise. The shadowcull element specifies the culling mode to use in the shadow pass. Note that material's depth bias settings do not apply in the shadow pass; during shadow rendering the light's depth bias is used instead.
 
+Render order is a 8-bit unsigned value that can be used to affect rendering order within a pass, overriding the state or distance sorting. The default value is 128; smaller values will render earlier, and larger values later.
+
 \section Materials_Textures Material textures
 
 Diffuse maps specify the surface color in the RGB channels. Optionally they can use the alpha channel for blending and alpha testing. They should preferably be compressed to DXT1 (no alpha or 1-bit alpha) or DXT5 (smooth alpha) format.

+ 18 - 6
Source/Urho3D/Graphics/Batch.cpp

@@ -42,7 +42,9 @@ namespace Urho3D
 
 inline bool CompareBatchesState(Batch* lhs, Batch* rhs)
 {
-    if (lhs->sortKey_ != rhs->sortKey_)
+    if (lhs->renderOrder_ != rhs->renderOrder_)
+        return lhs->renderOrder_ < rhs->renderOrder_;
+    else if (lhs->sortKey_ != rhs->sortKey_)
         return lhs->sortKey_ < rhs->sortKey_;
     else
         return lhs->distance_ < rhs->distance_;
@@ -50,7 +52,9 @@ inline bool CompareBatchesState(Batch* lhs, Batch* rhs)
 
 inline bool CompareBatchesFrontToBack(Batch* lhs, Batch* rhs)
 {
-    if (lhs->distance_ != rhs->distance_)
+    if (lhs->renderOrder_ != rhs->renderOrder_)
+        return lhs->renderOrder_ < rhs->renderOrder_;
+    else if (lhs->distance_ != rhs->distance_)
         return lhs->distance_ < rhs->distance_;
     else
         return lhs->sortKey_ < rhs->sortKey_;
@@ -58,7 +62,9 @@ inline bool CompareBatchesFrontToBack(Batch* lhs, Batch* rhs)
 
 inline bool CompareBatchesBackToFront(Batch* lhs, Batch* rhs)
 {
-    if (lhs->distance_ != rhs->distance_)
+    if (lhs->renderOrder_ != rhs->renderOrder_)
+        return lhs->renderOrder_ < rhs->renderOrder_;
+    else if (lhs->distance_ != rhs->distance_)
         return lhs->distance_ > rhs->distance_;
     else
         return lhs->sortKey_ < rhs->sortKey_;
@@ -69,6 +75,11 @@ inline bool CompareInstancesFrontToBack(const InstanceData& lhs, const InstanceD
     return lhs.distance_ < rhs.distance_;
 }
 
+inline bool CompareBatchGroupOrder(BatchGroup* lhs, BatchGroup* rhs)
+{
+    return lhs->renderOrder_ < rhs->renderOrder_;
+}
+
 void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split, Renderer* renderer, const Vector3& translation)
 {
     Camera* shadowCamera = queue->shadowSplits_[split].shadowCamera_;
@@ -669,7 +680,7 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
 unsigned BatchGroupKey::ToHash() const
 {
     return (unsigned)((size_t)zone_ / sizeof(Zone) + (size_t)lightQueue_ / sizeof(LightBatchQueue) + (size_t)pass_ / sizeof(Pass) +
-                      (size_t)material_ / sizeof(Material) + (size_t)geometry_ / sizeof(Geometry));
+                      (size_t)material_ / sizeof(Material) + (size_t)geometry_ / sizeof(Geometry)) + renderOrder_;
 }
 
 void BatchQueue::Clear(int maxSortedInstances)
@@ -689,12 +700,13 @@ void BatchQueue::SortBackToFront()
 
     Sort(sortedBatches_.Begin(), sortedBatches_.End(), CompareBatchesBackToFront);
 
-    // Do not actually sort batch groups, just list them
     sortedBatchGroups_.Resize(batchGroups_.Size());
-
+    
     unsigned index = 0;
     for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
         sortedBatchGroups_[index++] = &i->second_;
+    
+    Sort(sortedBatchGroups_.Begin(), sortedBatchGroups_.End(), CompareBatchGroupOrder);
 }
 
 void BatchQueue::SortFrontToBack()

+ 18 - 12
Source/Urho3D/Graphics/Batch.h

@@ -24,6 +24,7 @@
 
 #include "../Container/Ptr.h"
 #include "../Graphics/Drawable.h"
+#include "../Graphics/Material.h"
 #include "../Math/MathDefs.h"
 #include "../Math/Matrix3x4.h"
 #include "../Math/Rect.h"
@@ -50,21 +51,22 @@ struct Batch
 {
     /// Construct with defaults.
     Batch() :
-        lightQueue_(0),
-        isBase_(false)
+        isBase_(false),
+        lightQueue_(0)
     {
     }
 
     /// Construct from a drawable's source batch.
     Batch(const SourceBatch& rhs) :
         distance_(rhs.distance_),
+        renderOrder_(rhs.material_ ? rhs.material_->GetRenderOrder() : DEFAULT_RENDER_ORDER),
+        isBase_(false),
         geometry_(rhs.geometry_),
         material_(rhs.material_),
         worldTransform_(rhs.worldTransform_),
         numWorldTransforms_(rhs.numWorldTransforms_),
         lightQueue_(0),
-        geometryType_(rhs.geometryType_),
-        isBase_(false)
+        geometryType_(rhs.geometryType_)
     {
     }
 
@@ -74,11 +76,16 @@ struct Batch
     void Prepare(View* view, bool setModelTransform, bool allowDepthWrite) const;
     /// Prepare and draw.
     void Draw(View* view, bool allowDepthWrite) const;
-
     /// State sorting key.
     unsigned long long sortKey_;
     /// Distance from camera.
     float distance_;
+    /// 8-bit render order modifier from material.
+    unsigned char renderOrder_;
+    /// 8-bit light mask for stencil marking in deferred rendering.
+    unsigned char lightMask_;
+   /// Base batch flag. This tells to draw the object fully without light optimizations.
+    bool isBase_;
     /// Geometry.
     Geometry* geometry_;
     /// Material.
@@ -101,10 +108,6 @@ struct Batch
     ShaderVariation* pixelShader_;
     /// %Geometry type.
     GeometryType geometryType_;
-    /// Base batch flag. This tells to draw the object fully without light optimizations.
-    bool isBase_;
-    /// 8-bit light mask for stencil marking in deferred rendering.
-    unsigned char lightMask_;
 };
 
 /// Data for one geometry instance.
@@ -187,7 +190,8 @@ struct BatchGroupKey
         lightQueue_(batch.lightQueue_),
         pass_(batch.pass_),
         material_(batch.material_),
-        geometry_(batch.geometry_)
+        geometry_(batch.geometry_),
+        renderOrder_(batch.renderOrder_)
     {
     }
 
@@ -201,19 +205,21 @@ struct BatchGroupKey
     Material* material_;
     /// Geometry.
     Geometry* geometry_;
+    /// 8-bit render order modifier from material.
+    unsigned char renderOrder_;
 
     /// Test for equality with another batch group key.
     bool operator ==(const BatchGroupKey& rhs) const
     {
         return zone_ == rhs.zone_ && lightQueue_ == rhs.lightQueue_ && pass_ == rhs.pass_ && material_ == rhs.material_ &&
-               geometry_ == rhs.geometry_;
+               geometry_ == rhs.geometry_ && renderOrder_ == rhs.renderOrder_;
     }
 
     /// Test for inequality with another batch group key.
     bool operator !=(const BatchGroupKey& rhs) const
     {
         return zone_ != rhs.zone_ || lightQueue_ != rhs.lightQueue_ || pass_ != rhs.pass_ || material_ != rhs.material_ ||
-               geometry_ != rhs.geometry_;
+               geometry_ != rhs.geometry_ || renderOrder_ != rhs.renderOrder_;
     }
 
     /// Return hash value.

+ 15 - 0
Source/Urho3D/Graphics/Material.cpp

@@ -390,6 +390,10 @@ bool Material::Load(const XMLElement& source)
     if (depthBiasElem)
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
 
+    XMLElement renderOrderElem = source.GetChild("renderorder");
+    if (renderOrderElem)
+        SetRenderOrder((unsigned char)renderOrderElem.GetUInt("value"));
+
     RefreshShaderParameterHash();
     RefreshMemoryUse();
     CheckOcclusion();
@@ -468,6 +472,10 @@ bool Material::Save(XMLElement& dest) const
     depthBiasElem.SetFloat("constant", depthBias_.constantBias_);
     depthBiasElem.SetFloat("slopescaled", depthBias_.slopeScaledBias_);
 
+    // Write render order
+    XMLElement renderOrderElem = dest.CreateChild("renderorder");
+    renderOrderElem.SetUInt("value", renderOrder_);
+
     return true;
 }
 
@@ -632,6 +640,11 @@ void Material::SetDepthBias(const BiasParameters& parameters)
     depthBias_.Validate();
 }
 
+void Material::SetRenderOrder(unsigned char order)
+{
+    renderOrder_ = order;
+}
+
 void Material::SetScene(Scene* scene)
 {
     UnsubscribeFromEvent(E_UPDATE);
@@ -676,6 +689,7 @@ SharedPtr<Material> Material::Clone(const String& cloneName) const
     ret->cullMode_ = cullMode_;
     ret->shadowCullMode_ = shadowCullMode_;
     ret->fillMode_ = fillMode_;
+    ret->renderOrder_ = renderOrder_;
     ret->RefreshMemoryUse();
 
     return ret;
@@ -797,6 +811,7 @@ void Material::ResetToDefaults()
     shadowCullMode_ = CULL_CCW;
     fillMode_ = FILL_SOLID;
     depthBias_ = BiasParameters(0.0f, 0.0f);
+    renderOrder_ = DEFAULT_RENDER_ORDER;
 
     RefreshShaderParameterHash();
     RefreshMemoryUse();

+ 9 - 0
Source/Urho3D/Graphics/Material.h

@@ -40,6 +40,8 @@ class Texture2D;
 class TextureCube;
 class ValueAnimationInfo;
 
+static const unsigned char DEFAULT_RENDER_ORDER = 128;
+
 /// %Material's shader parameter definition.
 struct MaterialShaderParameter
 {
@@ -148,6 +150,8 @@ public:
     void SetFillMode(FillMode mode);
     /// Set depth bias.
     void SetDepthBias(const BiasParameters& parameters);
+    /// Set 8-bit render order within pass. Default 128. Lower values will render earlier and higher values later, taking precedence over e.g. state and distance sorting.
+    void SetRenderOrder(unsigned char order);
     /// Associate the material with a scene to ensure that shader parameter animation happens in sync with scene update, respecting the scene time scale. If no scene is set, the global update events will be used.
     void SetScene(Scene* scene);
     /// Remove shader parameter.
@@ -203,6 +207,9 @@ public:
     /// Return depth bias.
     const BiasParameters& GetDepthBias() const { return depthBias_; }
 
+    /// Return render order.
+    unsigned char GetRenderOrder() const { return renderOrder_; }
+    
     /// Return last auxiliary view rendered frame number.
     unsigned GetAuxViewFrameNumber() const { return auxViewFrameNumber_; }
 
@@ -255,6 +262,8 @@ private:
     FillMode fillMode_;
     /// Depth bias parameters.
     BiasParameters depthBias_;
+    /// Render order value.
+    unsigned char renderOrder_;
     /// Last auxiliary view rendered frame number.
     unsigned auxViewFrameNumber_;
     /// Shader parameter hash value.

+ 1 - 1
Source/Urho3D/Graphics/View.h

@@ -374,7 +374,7 @@ private:
     /// Intermediate light processing results.
     Vector<LightQueryResult> lightQueryResults_;
     /// Info for scene render passes defined by the renderpath.
-    Vector<ScenePassInfo> scenePasses_;
+    PODVector<ScenePassInfo> scenePasses_;
     /// Per-pixel light queues.
     Vector<LightBatchQueue> lightQueues_;
     /// Per-vertex light queues.

+ 7 - 3
Source/Urho3D/LuaScript/pkgs/Graphics/Material.pkg

@@ -21,6 +21,7 @@ class Material : public Resource
     void SetShadowCullMode(CullMode mode);
     void SetFillMode(FillMode mode);
     void SetDepthBias(const BiasParameters& parameters);
+    void SetRenderOrder(unsigned char renderOrder);
     void SetScene(Scene* scene);
     void RemoveShaderParameter(const String name);
     void ReleaseShaders();
@@ -46,13 +47,16 @@ class Material : public Resource
     CullMode GetShadowCullMode() const;
     FillMode GetFillMode() const;
     const BiasParameters& GetDepthBias() const;
+    unsigned char GetRenderOrder() const;
     bool GetOcclusion() const;
     bool GetSpecular() const;
     Scene* GetScene() const;
 
-    tolua_readonly tolua_property__get_set CullMode cullMode;
-    tolua_readonly tolua_property__get_set CullMode shadowCullMode;
-    tolua_readonly tolua_property__get_set FillMode fillMode;
+    tolua_property__get_set CullMode cullMode;
+    tolua_property__get_set CullMode shadowCullMode;
+    tolua_property__get_set FillMode fillMode;
+    tolua_property__get_set BiasParameters depthBias;
+    tolua_property__get_set unsigned char renderOrder;
     tolua_readonly tolua_property__get_set bool occlusion;
     tolua_readonly tolua_property__get_set bool specular;
     tolua_property__get_set Scene* scene;

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

@@ -844,6 +844,8 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Material", "FillMode get_fillMode() const", asMETHOD(Material, GetFillMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_depthBias(const BiasParameters&in)", asMETHOD(Material, SetDepthBias), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "const BiasParameters& get_depthBias() const", asMETHOD(Material, GetDepthBias), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "void set_renderOrder(uint8)", asMETHOD(Material, SetRenderOrder), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "uint8 get_renderOrder() const", asMETHOD(Material, GetRenderOrder), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_scene(Scene@+)", asMETHOD(Material, SetScene), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Scene@+ get_scene() const", asMETHOD(Material, GetScene), asCALL_THISCALL);
 

+ 19 - 3
bin/Data/Scripts/Editor/EditorMaterial.as

@@ -45,6 +45,8 @@ void CreateMaterialEditor()
     SubscribeToEvent(materialWindow.GetChild("ConstantBiasEdit", true), "TextFinished", "EditConstantBias");
     SubscribeToEvent(materialWindow.GetChild("SlopeBiasEdit", true), "TextChanged", "EditSlopeBias");
     SubscribeToEvent(materialWindow.GetChild("SlopeBiasEdit", true), "TextFinished", "EditSlopeBias");
+    SubscribeToEvent(materialWindow.GetChild("RenderOrderEdit", true), "TextChanged", "EditRenderOrder");
+    SubscribeToEvent(materialWindow.GetChild("RenderOrderEdit", true), "TextFinished", "EditRenderOrder");
     SubscribeToEvent(materialWindow.GetChild("CullModeEdit", true), "ItemSelected", "EditCullMode");
     SubscribeToEvent(materialWindow.GetChild("ShadowCullModeEdit", true), "ItemSelected", "EditShadowCullMode");
     SubscribeToEvent(materialWindow.GetChild("FillModeEdit", true), "ItemSelected", "EditFillMode");
@@ -318,15 +320,16 @@ void RefreshMaterialMiscParameters()
     if (editMaterial is null)
         return;
         
-    BiasParameters bias = editMaterial.depthBias;
-
     inMaterialRefresh = true;
 
+    BiasParameters bias = editMaterial.depthBias;
     LineEdit@ attrEdit = materialWindow.GetChild("ConstantBiasEdit", true);
     attrEdit.text = String(bias.constantBias);
     attrEdit = materialWindow.GetChild("SlopeBiasEdit", true);
     attrEdit.text = String(bias.slopeScaledBias);
-    
+    attrEdit = materialWindow.GetChild("RenderOrderEdit", true);
+    attrEdit.text = String(uint(editMaterial.renderOrder));
+
     DropDownList@ attrList = materialWindow.GetChild("CullModeEdit", true);
     attrList.selection = editMaterial.cullMode;
     attrList = materialWindow.GetChild("ShadowCullModeEdit", true);
@@ -829,6 +832,19 @@ void EditSlopeBias(StringHash eventType, VariantMap& eventData)
     EndMaterialEdit();
 }
 
+void EditRenderOrder(StringHash eventType, VariantMap& eventData)
+{
+    if (editMaterial is null || inMaterialRefresh)
+        return;
+
+    BeginMaterialEdit();
+
+    LineEdit@ attrEdit = eventData["Element"].GetPtr();
+    editMaterial.renderOrder = attrEdit.text.ToUInt();
+
+    EndMaterialEdit();
+}
+
 void EditCullMode(StringHash eventType, VariantMap& eventData)
 {
     if (editMaterial is null || inMaterialRefresh)

+ 12 - 0
bin/Data/UI/EditorMaterialWindow.xml

@@ -230,6 +230,18 @@
                             <attribute name="Name" value="SlopeBiasEdit" />
                         </element>
                     </element>
+                    <element>
+                        <attribute name="Min Size" value="0 16" />
+                        <attribute name="Max Size" value="2147483647 16" />
+                        <attribute name="Layout Mode" value="Horizontal" />
+                        <attribute name="Layout Spacing" value="10" />
+                        <element type="Text" style="EditorAttributeText">
+                            <attribute name="Text" value="Render order" />
+                        </element>
+                        <element type="LineEdit">
+                            <attribute name="Name" value="RenderOrderEdit" />
+                        </element>
+                    </element>
                     <element>
                         <attribute name="Min Size" value="0 16" />
                         <attribute name="Max Size" value="2147483647 16" />