Browse Source

Add per drawable shader paramaters.

PrimitiveWaste 11 years ago
parent
commit
f8ef0a39c0

+ 44 - 6
Source/Engine/Graphics/Batch.cpp

@@ -555,6 +555,14 @@ void Batch::Prepare(View* view, bool setModelTransform) const
             for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
                 graphics->SetShaderParameter(i->first_, i->second_.value_);
         }
+
+        // Set batch's shader parameters
+        if (shaderParameters_)
+        {
+            graphics->ClearParameterSource(SP_MATERIAL);
+            for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = shaderParameters_->Begin(); i != shaderParameters_->End(); ++i)
+                graphics->SetShaderParameter(i->first_, i->second_.value_);
+        }
         
         const SharedPtr<Texture>* textures = material_->GetTextures();
         for (unsigned i = 0; i < MAX_MATERIAL_TEXTURE_UNITS; ++i)
@@ -632,13 +640,43 @@ void BatchGroup::Draw(View* view) const
             graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
             graphics->SetVertexBuffers(geometry_->GetVertexBuffers(), geometry_->GetVertexElementMasks());
             
-            for (unsigned i = 0; i < instances_.Size(); ++i)
+            if (!hasInstanceShaderParameters_)
             {
-                if (graphics->NeedParameterUpdate(SP_OBJECTTRANSFORM, instances_[i].worldTransform_))
-                    graphics->SetShaderParameter(VSP_MODEL, *instances_[i].worldTransform_);
-                
-                graphics->Draw(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
-                    geometry_->GetVertexStart(), geometry_->GetVertexCount());
+                for (unsigned i = 0; i < instances_.Size(); ++i)
+                {
+                    if (graphics->NeedParameterUpdate(SP_OBJECTTRANSFORM, instances_[i].worldTransform_))
+                        graphics->SetShaderParameter(VSP_MODEL, *instances_[i].worldTransform_);
+
+                    graphics->Draw(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
+                        geometry_->GetVertexStart(), geometry_->GetVertexCount());
+                }
+            }
+            else
+            {
+                for (unsigned i = 0; i < instances_.Size(); ++i)
+                {
+                    // Set instance's shader parameters
+                    HashMap<StringHash, MaterialShaderParameter>* instanceShaderParameters = instances_[i].shaderParameters_;
+                    if (instanceShaderParameters)
+                    {
+                        graphics->ClearParameterSource(SP_MATERIAL);
+                        for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = instanceShaderParameters->Begin(); i != instanceShaderParameters->End(); ++i)
+                            graphics->SetShaderParameter(i->first_, i->second_.value_);
+                    }
+                    // Reset material's shader parameters
+                    else if (graphics->NeedParameterUpdate(SP_MATERIAL, material_))
+                    {
+                        const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
+                        for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+                            graphics->SetShaderParameter(i->first_, i->second_.value_);
+                    }
+
+                    if (graphics->NeedParameterUpdate(SP_OBJECTTRANSFORM, instances_[i].worldTransform_))
+                        graphics->SetShaderParameter(VSP_MODEL, *instances_[i].worldTransform_);
+
+                    graphics->Draw(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
+                        geometry_->GetVertexStart(), geometry_->GetVertexCount());
+                }
             }
         }
         else

+ 22 - 5
Source/Engine/Graphics/Batch.h

@@ -51,6 +51,7 @@ struct Batch
     /// Construct with defaults.
     Batch() :
         lightQueue_(0),
+        shaderParameters_(0),
         isBase_(false)
     {
     }
@@ -63,6 +64,7 @@ struct Batch
         worldTransform_(rhs.worldTransform_),
         numWorldTransforms_(rhs.numWorldTransforms_),
         lightQueue_(0),
+        shaderParameters_(0),
         geometryType_(rhs.geometryType_),
         overrideView_(rhs.overrideView_),
         isBase_(false)
@@ -100,6 +102,8 @@ struct Batch
     ShaderVariation* vertexShader_;
     /// Pixel shader.
     ShaderVariation* pixelShader_;
+    /// Shader parameters.
+    HashMap<StringHash, MaterialShaderParameter>* shaderParameters_;
     /// %Geometry type.
     GeometryType geometryType_;
     /// Override view transform flag. When set, the camera's view transform is replaced with an identity matrix.
@@ -121,7 +125,8 @@ struct InstanceData
     /// Construct with transform and distance.
     InstanceData(const Matrix3x4* worldTransform, float distance) :
         worldTransform_(worldTransform),
-        distance_(distance)
+        distance_(distance),
+        shaderParameters_()
     {
     }
     
@@ -129,6 +134,8 @@ struct InstanceData
     const Matrix3x4* worldTransform_;
     /// Distance from camera.
     float distance_;
+    /// Shader parameters.
+    HashMap<StringHash, MaterialShaderParameter>* shaderParameters_;
 };
 
 /// Instanced 3D geometry draw call.
@@ -136,14 +143,16 @@ struct BatchGroup : public Batch
 {
     /// Construct with defaults.
     BatchGroup() :
-        startIndex_(M_MAX_UNSIGNED)
+        startIndex_(M_MAX_UNSIGNED),
+        hasInstanceShaderParameters_(false)
     {
     }
     
     /// Construct from a batch.
     BatchGroup(const Batch& batch) :
         Batch(batch),
-        startIndex_(M_MAX_UNSIGNED)
+        startIndex_(M_MAX_UNSIGNED),
+        hasInstanceShaderParameters_(false)
     {
     }
 
@@ -152,11 +161,17 @@ struct BatchGroup : public Batch
     {
     }
     
-    /// Add world transform(s) from a batch.
-    void AddTransforms(const Batch& batch)
+    /// Add batch instance(s).
+    void AddBatchInstances(const Batch& batch)
     {
         InstanceData newInstance;
         newInstance.distance_ = batch.distance_;
+
+        if (batch.shaderParameters_)
+        {
+            newInstance.shaderParameters_ = batch.shaderParameters_;
+            hasInstanceShaderParameters_ = true;
+        }
         
         for (unsigned i = 0; i < batch.numWorldTransforms_; ++i)
         {
@@ -174,6 +189,8 @@ struct BatchGroup : public Batch
     PODVector<InstanceData> instances_;
     /// Instance stream start index, or M_MAX_UNSIGNED if transforms not pre-set.
     unsigned startIndex_;
+    /// Has instance shader parameters flag;
+    bool hasInstanceShaderParameters_;
 };
 
 /// Instanced draw call grouping key.

+ 21 - 0
Source/Engine/Graphics/Drawable.cpp

@@ -245,6 +245,27 @@ void Drawable::SetOccludee(bool enable)
     }
 }
 
+void Drawable::SetShaderParameter(const String& name, const Variant& value)
+{
+    MaterialShaderParameter newParam;
+    newParam.name_ = name;
+    newParam.value_ = value;
+    StringHash nameHash(name);
+    shaderParameters_[nameHash] = newParam;
+}
+
+const Variant& Drawable::GetShaderParameter(const String& name) const
+{
+    HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = shaderParameters_.Find(name);
+    return i != shaderParameters_.End() ? i->second_.value_ : Variant::EMPTY;
+}
+
+void Drawable::RemoveShaderParameter(const String& name)
+{
+    StringHash nameHash(name);
+    shaderParameters_.Erase(nameHash);
+}
+
 void Drawable::MarkForUpdate()
 {
     if (!updateQueued_ && octant_)

+ 15 - 0
Source/Engine/Graphics/Drawable.h

@@ -50,6 +50,7 @@ class OcclusionBuffer;
 class Octant;
 class RayOctreeQuery;
 class Zone;
+struct MaterialShaderParameter;
 struct RayQueryResult;
 struct WorkItem;
 
@@ -158,6 +159,10 @@ public:
     void SetOccluder(bool enable);
     /// Set occludee flag.
     void SetOccludee(bool enable);
+    /// Set shader parameter.
+    void SetShaderParameter(const String& name, const Variant& value);
+    /// Remove shader parameter.
+    void RemoveShaderParameter(const String& name);
     /// Mark for update and octree reinsertion. Update is automatically queued when the drawable's scene node moves or changes scale.
     void MarkForUpdate();
     
@@ -195,6 +200,14 @@ public:
     bool IsInView(Camera* camera) const;
     /// Return draw call source data.
     const Vector<SourceBatch>& GetBatches() const { return batches_; }
+    /// Return whether has any shader parameters.
+    bool HasShaderParameters() const { return !shaderParameters_.Empty(); }
+    /// Return all shader parameters.
+    const HashMap<StringHash, MaterialShaderParameter>& GetShaderParameters() const { return shaderParameters_; }
+    /// Return all shader parameters.
+    HashMap<StringHash, MaterialShaderParameter>& GetShaderParameters() { return shaderParameters_; }
+    /// Return shader parameter.
+    const Variant& GetShaderParameter(const String& name) const;
     
     /// Set new zone. Zone assignment may optionally be temporary, meaning it needs to be re-evaluated on the next frame.
     void SetZone(Zone* zone, bool temporary = false);
@@ -340,6 +353,8 @@ protected:
     bool zoneDirty_;
     /// Set of cameras from which is seen on the current frame.
     HashSet<Camera*> viewCameras_;
+    /// Shader parameters.
+    HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
 };
 
 inline bool CompareDrawables(Drawable* lhs, Drawable* rhs)

+ 11 - 2
Source/Engine/Graphics/View.cpp

@@ -1011,6 +1011,9 @@ void View::GetBatches()
                             destBatch.camera_ = shadowCamera;
                             destBatch.zone_ = zone;
                             destBatch.lightQueue_ = &lightQueue;
+
+                            if (drawable->HasShaderParameters())
+                                destBatch.shaderParameters_ = &(drawable->GetShaderParameters());
                             
                             AddBatchToQueue(shadowQueue.shadowBatches_, destBatch, tech);
                         }
@@ -1123,6 +1126,9 @@ void View::GetBatches()
                 destBatch.isBase_ = true;
                 destBatch.pass_ = 0;
                 destBatch.lightMask_ = GetLightMask(drawable);
+
+                if (drawable->HasShaderParameters())
+                    destBatch.shaderParameters_ = &(drawable->GetShaderParameters());
                 
                 // Check each of the scene passes
                 for (unsigned k = 0; k < scenePasses_.Size(); ++k)
@@ -1172,7 +1178,7 @@ void View::GetBatches()
                         destBatch.lightQueue_ = 0;
                     
                     bool allowInstancing = info.allowInstancing_;
-                    if (allowInstancing && info.markToStencil_ && destBatch.lightMask_ != (zone->GetLightMask() & 0xff))
+                    if (allowInstancing && info.markToStencil_ && destBatch.lightMask_ != (zone->GetLightMask() & 0xff) || destBatch.shaderParameters_)
                         allowInstancing = false;
                     
                     AddBatchToQueue(*info.batchQueue_, destBatch, tech, allowInstancing);
@@ -1329,6 +1335,9 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQ
         destBatch.camera_ = camera_;
         destBatch.lightQueue_ = &lightQueue;
         destBatch.zone_ = zone;
+
+        if (drawable->HasShaderParameters())
+            destBatch.shaderParameters_ = &(drawable->GetShaderParameters());
         
         if (!isLitAlpha)
         {
@@ -2694,7 +2703,7 @@ void View::AddBatchToQueue(BatchQueue& batchQueue, Batch& batch, Technique* tech
         }
 
         int oldSize = i->second_.instances_.Size();
-        i->second_.AddTransforms(batch);
+        i->second_.AddBatchInstances(batch);
         // Convert to using instancing shaders when the instancing limit is reached
         if (oldSize < minInstances_ && (int)i->second_.instances_.Size() >= minInstances_)
         {

+ 3 - 0
Source/Engine/LuaScript/pkgs/Graphics/Drawable.pkg

@@ -25,10 +25,13 @@ class Drawable : public Component
     void SetCastShadows(bool enable);
     void SetOccluder(bool enable);
     void SetOccludee(bool enable);
+    void SetShaderParameter(const String name, const Variant& value);
+    void RemoveShaderParameter(const String name);
     void MarkForUpdate();
     
     const BoundingBox& GetBoundingBox() const;
     const BoundingBox& GetWorldBoundingBox();
+    const Variant& GetShaderParameter(const String name) const;
     unsigned char GetDrawableFlags() const;
     float GetDrawDistance() const;
     float GetShadowDistance() const;

+ 17 - 0
Source/Engine/Script/APITemplates.h

@@ -30,6 +30,7 @@
 #include "File.h"
 #include "HashSet.h"
 #include "Log.h"
+#include "Material.h"
 #include "Node.h"
 #include "Resource.h"
 #include "Script.h"
@@ -745,6 +746,18 @@ template <class T> void RegisterResource(asIScriptEngine* engine, const char* cl
     engine->RegisterObjectMethod(className, "uint get_useTimer()" ,asMETHODPR(T, GetUseTimer, (), unsigned), asCALL_THISCALL);
 }
 
+static CScriptArray* DrawableGetShaderParameterNames(Drawable* drawable)
+{
+    Vector<String> result;
+
+    const HashMap<StringHash, MaterialShaderParameter>& parameters = drawable->GetShaderParameters();
+    for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+        result.Push(i->second_.name_);
+
+    Sort(result.Begin(), result.End());
+    return VectorToArray<String>(result, "Array<String>");
+}
+
 /// Template function for registering a class derived from Drawable.
 template <class T> void RegisterDrawable(asIScriptEngine* engine, const char* className)
 {
@@ -776,6 +789,10 @@ template <class T> void RegisterDrawable(asIScriptEngine* engine, const char* cl
     engine->RegisterObjectMethod(className, "uint get_maxLights() const", asMETHOD(T, GetMaxLights), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const BoundingBox& get_boundingBox() const", asMETHOD(T, GetBoundingBox), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const BoundingBox& get_worldBoundingBox()", asMETHOD(T, GetWorldBoundingBox), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void RemoveShaderParameter(const String&in)", asMETHOD(T, RemoveShaderParameter), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void set_shaderParameters(const String&in, const Variant&in)", asMETHOD(T, SetShaderParameter), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "const Variant& get_shaderParameters(const String&in) const", asMETHOD(T, GetShaderParameter), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "Array<String>@ get_shaderParameterNames() const", asFUNCTION(DrawableGetShaderParameterNames), asCALL_CDECL_OBJLAST);
 }
 
 /// Template function for registering a class derived from SoundSource.