Browse Source

Refactor material shader parameter animations so that they happen in response to update events, the same as component/node attribute animations. This fixes material animations depending on visibility and therefore possibly going out of sync from other updates. Add possibility to associate material with scene to make it use the scene attribute update event instead of the global update event.

Lasse Öörni 11 years ago
parent
commit
3969b69b0d

+ 2 - 0
Bin/Data/LuaScripts/31_MaterialAnimation.lua

@@ -60,6 +60,8 @@ function CreateScene()
     specColorAnimation:SetKeyFrame(1.0, Variant(Color(1.0, 0.0, 0.0, 2.0)))
     specColorAnimation:SetKeyFrame(1.0, Variant(Color(1.0, 0.0, 0.0, 2.0)))
     specColorAnimation:SetKeyFrame(2.0, Variant(Color(1.0, 1.0, 0.0, 2.0)))
     specColorAnimation:SetKeyFrame(2.0, Variant(Color(1.0, 1.0, 0.0, 2.0)))
     specColorAnimation:SetKeyFrame(3.0, Variant(Color(0.1, 0.1, 0.1, 16.0)))
     specColorAnimation:SetKeyFrame(3.0, Variant(Color(0.1, 0.1, 0.1, 16.0)))
+    -- Optionally associate material with scene to make sure shader parameter animation respects scene time scale
+    mushroomMat.scene = scene_;
     mushroomMat:SetShaderParameterAnimation("MatSpecColor", specColorAnimation)
     mushroomMat:SetShaderParameterAnimation("MatSpecColor", specColorAnimation)
 
 
     local NUM_OBJECTS = 200
     local NUM_OBJECTS = 200

+ 2 - 0
Bin/Data/Scripts/31_MaterialAnimation.as

@@ -62,6 +62,8 @@ void CreateScene()
     specColorAnimation.SetKeyFrame(1.0f, Variant(Color(1.0f, 0.0f, 0.0f, 2.0f)));
     specColorAnimation.SetKeyFrame(1.0f, Variant(Color(1.0f, 0.0f, 0.0f, 2.0f)));
     specColorAnimation.SetKeyFrame(2.0f, Variant(Color(1.0f, 1.0f, 0.0f, 2.0f)));
     specColorAnimation.SetKeyFrame(2.0f, Variant(Color(1.0f, 1.0f, 0.0f, 2.0f)));
     specColorAnimation.SetKeyFrame(3.0f, Variant(Color(0.1f, 0.1f, 0.1f, 16.0f)));
     specColorAnimation.SetKeyFrame(3.0f, Variant(Color(0.1f, 0.1f, 0.1f, 16.0f)));
+    // Optionally associate material with scene to make sure shader parameter animation respects scene time scale
+    mushroomMat.scene = scene_;
     mushroomMat.SetShaderParameterAnimation("MatSpecColor", specColorAnimation);
     mushroomMat.SetShaderParameterAnimation("MatSpecColor", specColorAnimation);
 
 
     const uint NUM_OBJECTS = 200;
     const uint NUM_OBJECTS = 200;

+ 0 - 3
Source/Engine/Graphics/Batch.cpp

@@ -551,9 +551,6 @@ void Batch::Prepare(View* view, bool setModelTransform) const
     {
     {
         if (graphics->NeedParameterUpdate(SP_MATERIAL, material_))
         if (graphics->NeedParameterUpdate(SP_MATERIAL, material_))
         {
         {
-            // Update shader parameter animations
-            material_->UpdateShaderParameterAnimations();
-
             const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
             const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
             for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
             for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
                 graphics->SetShaderParameter(i->first_, i->second_.value_);
                 graphics->SetShaderParameter(i->first_, i->second_.value_);

+ 55 - 26
Source/Engine/Graphics/Material.cpp

@@ -22,6 +22,7 @@
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "Context.h"
 #include "Context.h"
+#include "CoreEvents.h"
 #include "FileSystem.h"
 #include "FileSystem.h"
 #include "Graphics.h"
 #include "Graphics.h"
 #include "Log.h"
 #include "Log.h"
@@ -29,6 +30,8 @@
 #include "Matrix3x4.h"
 #include "Matrix3x4.h"
 #include "Profiler.h"
 #include "Profiler.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
+#include "Scene.h"
+#include "SceneEvents.h"
 #include "Technique.h"
 #include "Technique.h"
 #include "Texture2D.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
 #include "TextureCube.h"
@@ -151,7 +154,7 @@ Material::Material(Context* context) :
     auxViewFrameNumber_(0),
     auxViewFrameNumber_(0),
     occlusion_(true),
     occlusion_(true),
     specular_(false),
     specular_(false),
-    animationFrameNumber_(0)
+    subscribed_(false)
 {
 {
     ResetToDefaults();
     ResetToDefaults();
 }
 }
@@ -342,7 +345,6 @@ bool Material::Load(const XMLElement& source)
     if (depthBiasElem)
     if (depthBiasElem)
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
 
 
-    // Calculate memory use
     RefreshMemoryUse();
     RefreshMemoryUse();
     CheckOcclusion();
     CheckOcclusion();
     return true;
     return true;
@@ -482,6 +484,7 @@ void Material::SetShaderParameterAnimation(const String& name, ValueAnimation* a
         
         
         StringHash nameHash(name);
         StringHash nameHash(name);
         shaderParameterAnimationInfos_[nameHash] = new ShaderParameterAnimationInfo(this, name, animation, wrapMode, speed);
         shaderParameterAnimationInfos_[nameHash] = new ShaderParameterAnimationInfo(this, name, animation, wrapMode, speed);
+        UpdateEventSubscription();
     }
     }
     else
     else
     {
     {
@@ -489,6 +492,7 @@ void Material::SetShaderParameterAnimation(const String& name, ValueAnimation* a
         {
         {
             StringHash nameHash(name);
             StringHash nameHash(name);
             shaderParameterAnimationInfos_.Erase(nameHash);
             shaderParameterAnimationInfos_.Erase(nameHash);
+            UpdateEventSubscription();
         }
         }
     }
     }
 }
 }
@@ -562,6 +566,15 @@ void Material::SetDepthBias(const BiasParameters& parameters)
     depthBias_.Validate();
     depthBias_.Validate();
 }
 }
 
 
+void Material::SetScene(Scene* scene)
+{
+    UnsubscribeFromEvent(E_UPDATE);
+    UnsubscribeFromEvent(E_ATTRIBUTEANIMATIONUPDATE);
+    subscribed_ = false;
+    scene_ = scene;
+    UpdateEventSubscription();
+}
+
 void Material::RemoveShaderParameter(const String& name)
 void Material::RemoveShaderParameter(const String& name)
 {
 {
     StringHash nameHash(name);
     StringHash nameHash(name);
@@ -611,30 +624,6 @@ void Material::MarkForAuxView(unsigned frameNumber)
     auxViewFrameNumber_ = frameNumber;
     auxViewFrameNumber_ = frameNumber;
 }
 }
 
 
-void Material::UpdateShaderParameterAnimations()
-{
-    if (shaderParameterAnimationInfos_.Empty())
-        return;
-
-    Time* time = GetSubsystem<Time>();
-    if (time->GetFrameNumber() == animationFrameNumber_)
-        return;
-
-    animationFrameNumber_ = time->GetFrameNumber();
-    float timeStep = time->GetTimeStep();
-
-    Vector<String> finishedNames;
-    for (HashMap<StringHash, SharedPtr<ShaderParameterAnimationInfo> >::ConstIterator i = shaderParameterAnimationInfos_.Begin(); i != shaderParameterAnimationInfos_.End(); ++i)
-    {
-        if (i->second_->Update(timeStep))
-            finishedNames.Push(i->second_->GetName());
-    }
-
-    // Remove finished animation
-    for (unsigned i = 0; i < finishedNames.Size(); ++i)
-        SetShaderParameterAnimation(finishedNames[i], 0);
-}
-
 const TechniqueEntry& Material::GetTechniqueEntry(unsigned index) const
 const TechniqueEntry& Material::GetTechniqueEntry(unsigned index) const
 {
 {
     return index < techniques_.Size() ? techniques_[index] : noEntry;
     return index < techniques_.Size() ? techniques_[index] : noEntry;
@@ -680,6 +669,11 @@ float Material::GetShaderParameterAnimationSpeed(const String& name) const
     return info == 0 ? 0 : info->GetSpeed();
     return info == 0 ? 0 : info->GetSpeed();
 }
 }
 
 
+Scene* Material::GetScene() const
+{
+    return scene_;
+}
+
 String Material::GetTextureUnitName(TextureUnit unit)
 String Material::GetTextureUnitName(TextureUnit unit)
 {
 {
     return textureUnitNames[unit];
     return textureUnitNames[unit];
@@ -758,4 +752,39 @@ ShaderParameterAnimationInfo* Material::GetShaderParameterAnimationInfo(const St
     return i->second_;
     return i->second_;
 }
 }
 
 
+void Material::UpdateEventSubscription()
+{
+    if (shaderParameterAnimationInfos_.Size() && !subscribed_)
+    {
+        if (scene_)
+            SubscribeToEvent(scene_, E_ATTRIBUTEANIMATIONUPDATE, HANDLER(Material, HandleAttributeAnimationUpdate));
+        else
+            SubscribeToEvent(E_UPDATE, HANDLER(Material, HandleAttributeAnimationUpdate));
+        subscribed_ = true;
+    }
+    else if (subscribed_)
+    {
+        UnsubscribeFromEvent(E_UPDATE);
+        UnsubscribeFromEvent(E_ATTRIBUTEANIMATIONUPDATE);
+        subscribed_ = false;
+    }
+}
+
+void Material::HandleAttributeAnimationUpdate(StringHash eventType, VariantMap& eventData)
+{
+    // Timestep parameter is same no matter what event is being listened to
+    float timeStep = eventData[Update::P_TIMESTEP].GetFloat();
+
+    Vector<String> finishedNames;
+    for (HashMap<StringHash, SharedPtr<ShaderParameterAnimationInfo> >::ConstIterator i = shaderParameterAnimationInfos_.Begin(); i != shaderParameterAnimationInfos_.End(); ++i)
+    {
+        if (i->second_->Update(timeStep))
+            finishedNames.Push(i->second_->GetName());
+    }
+
+    // Remove finished animations
+    for (unsigned i = 0; i < finishedNames.Size(); ++i)
+        SetShaderParameterAnimation(finishedNames[i], 0);
+}
+
 }
 }

+ 13 - 4
Source/Engine/Graphics/Material.h

@@ -33,6 +33,7 @@ namespace Urho3D
 
 
 class Material;
 class Material;
 class Pass;
 class Pass;
+class Scene;
 class Technique;
 class Technique;
 class Texture;
 class Texture;
 class Texture2D;
 class Texture2D;
@@ -137,6 +138,8 @@ public:
     void SetShadowCullMode(CullMode mode);
     void SetShadowCullMode(CullMode mode);
     /// Set depth bias.
     /// Set depth bias.
     void SetDepthBias(const BiasParameters& parameters);
     void SetDepthBias(const BiasParameters& parameters);
+    /// 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.
     /// Remove shader parameter.
     void RemoveShaderParameter(const String& name);
     void RemoveShaderParameter(const String& name);
     /// Reset all shader pointers.
     /// Reset all shader pointers.
@@ -147,8 +150,6 @@ public:
     void SortTechniques();
     void SortTechniques();
     /// Mark material for auxiliary view rendering.
     /// Mark material for auxiliary view rendering.
     void MarkForAuxView(unsigned frameNumber);
     void MarkForAuxView(unsigned frameNumber);
-    /// Update shader parameter animations.
-    void UpdateShaderParameterAnimations();
 
 
     /// Return number of techniques.
     /// Return number of techniques.
     unsigned GetNumTechniques() const { return techniques_.Size(); }
     unsigned GetNumTechniques() const { return techniques_.Size(); }
@@ -186,6 +187,8 @@ public:
     bool GetOcclusion() const { return occlusion_; }
     bool GetOcclusion() const { return occlusion_; }
     /// Return whether should render specular.
     /// Return whether should render specular.
     bool GetSpecular() const { return specular_; }
     bool GetSpecular() const { return specular_; }
+    /// Return the scene associated with the material for shader parameter animation updates.
+    Scene* GetScene() const;
 
 
     /// Return name for texture unit.
     /// Return name for texture unit.
     static String GetTextureUnitName(TextureUnit unit);
     static String GetTextureUnitName(TextureUnit unit);
@@ -201,6 +204,10 @@ private:
     void RefreshMemoryUse();
     void RefreshMemoryUse();
     /// Return shader parameter animation info.
     /// Return shader parameter animation info.
     ShaderParameterAnimationInfo* GetShaderParameterAnimationInfo(const String& name) const;
     ShaderParameterAnimationInfo* GetShaderParameterAnimationInfo(const String& name) const;
+    /// Update whether should be subscribed to scene or global update events for shader parameter animation.
+    void UpdateEventSubscription();
+    /// Update shader parameter animations.
+    void HandleAttributeAnimationUpdate(StringHash eventType, VariantMap& eventData);
 
 
     /// Techniques.
     /// Techniques.
     Vector<TechniqueEntry> techniques_;
     Vector<TechniqueEntry> techniques_;
@@ -222,10 +229,12 @@ private:
     bool occlusion_;
     bool occlusion_;
     /// Specular lighting flag.
     /// Specular lighting flag.
     bool specular_;
     bool specular_;
-    /// Last animation update frame number.
-    unsigned animationFrameNumber_;
+    /// Flag for whether is subscribed to animation updates.
+    bool subscribed_;
     /// XML file used while loading.
     /// XML file used while loading.
     SharedPtr<XMLFile> loadXMLFile_;
     SharedPtr<XMLFile> loadXMLFile_;
+    /// Associated scene for shader parameter animation updates.
+    WeakPtr<Scene> scene_;
 };
 };
 
 
 }
 }

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

@@ -20,6 +20,7 @@ class Material : public Resource
     void SetCullMode(CullMode mode);
     void SetCullMode(CullMode mode);
     void SetShadowCullMode(CullMode mode);
     void SetShadowCullMode(CullMode mode);
     void SetDepthBias(const BiasParameters& parameters);
     void SetDepthBias(const BiasParameters& parameters);
+    void SetScene(Scene* scene);
     void RemoveShaderParameter(const String name);
     void RemoveShaderParameter(const String name);
     void ReleaseShaders();
     void ReleaseShaders();
     
     
@@ -47,12 +48,14 @@ class Material : public Resource
     unsigned GetAuxViewFrameNumber() const;
     unsigned GetAuxViewFrameNumber() const;
     bool GetOcclusion() const;
     bool GetOcclusion() const;
     bool GetSpecular() const;
     bool GetSpecular() const;
+    Scene* GetScene() const;
     
     
     tolua_readonly tolua_property__get_set CullMode cullMode;
     tolua_readonly tolua_property__get_set CullMode cullMode;
     tolua_readonly tolua_property__get_set CullMode shadowCullMode;
     tolua_readonly tolua_property__get_set CullMode shadowCullMode;
     tolua_readonly tolua_property__get_set unsigned auxViewFrameNumber;
     tolua_readonly tolua_property__get_set unsigned auxViewFrameNumber;
     tolua_readonly tolua_property__get_set bool occlusion;
     tolua_readonly tolua_property__get_set bool occlusion;
     tolua_readonly tolua_property__get_set bool specular;
     tolua_readonly tolua_property__get_set bool specular;
+    tolua_property__get_set Scene* scene;
 };
 };
 
 
 ${
 ${

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

@@ -684,6 +684,8 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Material", "CullMode get_shadowCullMode() const", asMETHOD(Material, GetShadowCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "CullMode get_shadowCullMode() const", asMETHOD(Material, GetShadowCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_depthBias(const BiasParameters&in)", asMETHOD(Material, SetDepthBias), 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", "const BiasParameters& get_depthBias() const", asMETHOD(Material, GetDepthBias), 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);
     
     
     engine->RegisterGlobalFunction("String GetTextureUnitName(TextureUnit)", asFUNCTION(Material::GetTextureUnitName), asCALL_CDECL);
     engine->RegisterGlobalFunction("String GetTextureUnitName(TextureUnit)", asFUNCTION(Material::GetTextureUnitName), asCALL_CDECL);
 }
 }

+ 2 - 0
Source/Samples/31_MaterialAnimation/MaterialAnimation.cpp

@@ -108,6 +108,8 @@ void MaterialAnimation::CreateScene()
     specColorAnimation->SetKeyFrame(1.0f, Color(1.0f, 0.0f, 0.0f, 2.0f));
     specColorAnimation->SetKeyFrame(1.0f, Color(1.0f, 0.0f, 0.0f, 2.0f));
     specColorAnimation->SetKeyFrame(2.0f, Color(1.0f, 1.0f, 0.0f, 2.0f));
     specColorAnimation->SetKeyFrame(2.0f, Color(1.0f, 1.0f, 0.0f, 2.0f));
     specColorAnimation->SetKeyFrame(3.0f, Color(0.1f, 0.1f, 0.1f, 16.0f));
     specColorAnimation->SetKeyFrame(3.0f, Color(0.1f, 0.1f, 0.1f, 16.0f));
+    // Optionally associate material with scene to make sure shader parameter animation respects scene time scale
+    mushroomMat->SetScene(scene_);
     mushroomMat->SetShaderParameterAnimation("MatSpecColor", specColorAnimation);
     mushroomMat->SetShaderParameterAnimation("MatSpecColor", specColorAnimation);
 
 
     const unsigned NUM_OBJECTS = 200;
     const unsigned NUM_OBJECTS = 200;