Quellcode durchsuchen

Merge remote-tracking branch '1vanK/master'

Lasse Öörni vor 9 Jahren
Ursprung
Commit
33d9dafc0c

+ 8 - 0
Source/Urho3D/AngelScript/GraphicsAPI.cpp

@@ -1252,6 +1252,10 @@ static void RegisterAnimatedModel(asIScriptEngine* engine)
     RegisterRefCounted<AnimationState>(engine, "AnimationState");
     RegisterStaticModel<AnimatedModel>(engine, "AnimatedModel", false);
 
+    engine->RegisterEnum("AnimationBlendingMode");
+    engine->RegisterEnumValue("AnimationBlendingMode", "ABM_OVERRIDE", ABM_OVERRIDE);
+    engine->RegisterEnumValue("AnimationBlendingMode", "ABM_ADDITIVE", ABM_ADDITIVE);
+
     engine->RegisterObjectBehaviour("AnimationState", asBEHAVE_FACTORY, "AnimationState@+ f(Node@+, Animation@+)", asFUNCTION(ConstructAnimationState), asCALL_CDECL);
     engine->RegisterObjectMethod("AnimationState", "void AddWeight(float)", asMETHOD(AnimationState, AddWeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationState", "void AddTime(float)", asMETHOD(AnimationState, AddTime), asCALL_THISCALL);
@@ -1269,6 +1273,8 @@ static void RegisterAnimatedModel(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimationState", "bool get_looped() const", asMETHOD(AnimationState, IsLooped), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationState", "void set_weight(float)", asMETHOD(AnimationState, SetWeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationState", "float get_weight() const", asMETHOD(AnimationState, GetWeight), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimationState", "void set_blendingMode(AnimationBlendingMode)", asMETHOD(AnimationState, SetBlendingMode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimationState", "AnimationBlendingMode get_blendingMode() const", asMETHOD(AnimationState, GetBlendingMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationState", "void set_time(float)", asMETHOD(AnimationState, SetTime), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationState", "float get_time() const", asMETHOD(AnimationState, GetTime), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationState", "void set_layer(uint8)", asMETHOD(AnimationState, SetLayer), asCALL_THISCALL);
@@ -1321,6 +1327,7 @@ static void RegisterAnimationController(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimationController", "bool SetTime(const String&in, float)", asMETHOD(AnimationController, SetTime), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "bool SetWeight(const String&in, float)", asMETHOD(AnimationController, SetWeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "bool SetLooped(const String&in, bool)", asMETHOD(AnimationController, SetLooped), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimationController", "bool SetBlendingMode(const String&in, AnimationBlendingMode)", asMETHOD(AnimationController, SetBlendingMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "bool SetSpeed(const String&in, float)", asMETHOD(AnimationController, SetSpeed), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "bool SetAutoFade(const String&in, float)", asMETHOD(AnimationController, SetAutoFade), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "bool SetRemoveOnCompletion(const String&in, bool)", asMETHOD(AnimationController, SetRemoveOnCompletion), asCALL_THISCALL);
@@ -1333,6 +1340,7 @@ static void RegisterAnimationController(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimationController", "float GetTime(const String&in) const", asMETHOD(AnimationController, GetTime), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "float GetWeight(const String&in) const", asMETHOD(AnimationController, GetWeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "bool GetLooped(const String&in) const", asMETHOD(AnimationController, IsLooped), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimationController", "AnimationBlendingMode GetBlendingMode(const String&in) const", asMETHOD(AnimationController, GetBlendingMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "float GetLength(const String&in) const", asMETHOD(AnimationController, GetLength), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "float GetSpeed(const String&in) const", asMETHOD(AnimationController, GetSpeed), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimationController", "float GetFadeTarget(const String&in) const", asMETHOD(AnimationController, GetFadeTarget), asCALL_THISCALL);

+ 17 - 0
Source/Urho3D/Graphics/AnimationController.cpp

@@ -393,6 +393,17 @@ bool AnimationController::SetLooped(const String& name, bool enable)
     return true;
 }
 
+bool AnimationController::SetBlendingMode(const String& name, AnimationBlendingMode mode)
+{
+    AnimationState* state = GetAnimationState(name);
+    if (!state)
+        return false;
+
+    state->SetBlendingMode(mode);
+    MarkNetworkUpdate();
+    return true;
+}
+
 bool AnimationController::SetAutoFade(const String& name, float fadeOutTime)
 {
     unsigned index;
@@ -484,6 +495,12 @@ bool AnimationController::IsLooped(const String& name) const
     return state ? state->IsLooped() : false;
 }
 
+AnimationBlendingMode AnimationController::GetBlendingMode(const String& name) const
+{
+    AnimationState* state = GetAnimationState(name);
+    return state ? state->GetBlendingMode() : ABM_OVERRIDE;
+}
+
 float AnimationController::GetLength(const String& name) const
 {
     AnimationState* state = GetAnimationState(name);

+ 5 - 1
Source/Urho3D/Graphics/AnimationController.h

@@ -24,13 +24,13 @@
 
 #include "../IO/VectorBuffer.h"
 #include "../Scene/Component.h"
+#include "../Graphics/AnimationState.h"
 
 namespace Urho3D
 {
 
 class AnimatedModel;
 class Animation;
-class AnimationState;
 struct Bone;
 
 /// Control data for an animation.
@@ -129,6 +129,8 @@ public:
     bool SetAutoFade(const String& name, float fadeOutTime);
     /// Set whether an animation auto-removes on completion.
     bool SetRemoveOnCompletion(const String& name, bool removeOnCompletion);
+    /// Set animation blending mode. Return true on success.
+    bool SetBlendingMode(const String& name, AnimationBlendingMode mode);
 
     /// Return whether an animation is active. Note that non-looping animations that are being clamped at the end also return true.
     bool IsPlaying(const String& name) const;
@@ -150,6 +152,8 @@ public:
     float GetWeight(const String& name) const;
     /// Return animation looping.
     bool IsLooped(const String& name) const;
+    /// Return animation blending mode.
+    AnimationBlendingMode GetBlendingMode(const String& name) const;
     /// Return animation length.
     float GetLength(const String& name) const;
     /// Return animation speed.

+ 60 - 120
Source/Urho3D/Graphics/AnimationState.cpp

@@ -52,7 +52,8 @@ AnimationState::AnimationState(AnimatedModel* model, Animation* animation) :
     looped_(false),
     weight_(0.0f),
     time_(0.0f),
-    layer_(0)
+    layer_(0),
+    blendingMode_(ABM_OVERRIDE)
 {
     // Set default start bone (use all tracks.)
     SetStartBone(0);
@@ -65,7 +66,8 @@ AnimationState::AnimationState(Node* node, Animation* animation) :
     looped_(false),
     weight_(1.0f),
     time_(0.0f),
-    layer_(0)
+    layer_(0),
+    blendingMode_(ABM_OVERRIDE)
 {
     if (animation_)
     {
@@ -178,6 +180,18 @@ void AnimationState::SetWeight(float weight)
     }
 }
 
+void AnimationState::SetBlendingMode(AnimationBlendingMode mode)
+{
+    if (model_)
+    {
+        if (blendingMode_ != mode)
+        {
+            blendingMode_ = mode;
+            model_->MarkAnimationDirty();
+        }
+    }
+}
+
 void AnimationState::SetTime(float time)
 {
     if (!animation_)
@@ -452,11 +466,8 @@ void AnimationState::ApplyToModel()
         // Do not apply if zero effective weight or the bone has animation disabled
         if (Equals(finalWeight, 0.0f) || !stateTrack.bone_->animated_)
             continue;
-
-        if (Equals(finalWeight, 1.0f))
-            ApplyTrackFullWeightSilent(stateTrack);
-        else
-            ApplyTrackBlendedSilent(stateTrack, finalWeight);
+            
+        ApplyTrack(stateTrack, finalWeight, true);
     }
 }
 
@@ -464,10 +475,10 @@ void AnimationState::ApplyToNodes()
 {
     // When applying to a node hierarchy, can only use full weight (nothing to blend to)
     for (Vector<AnimationStateTrack>::Iterator i = stateTracks_.Begin(); i != stateTracks_.End(); ++i)
-        ApplyTrackFullWeight(*i);
+        ApplyTrack(*i, 1.0, false);
 }
 
-void AnimationState::ApplyTrackFullWeight(AnimationStateTrack& stateTrack)
+void AnimationState::ApplyTrack(AnimationStateTrack& stateTrack, float weight, bool silent)
 {
     const AnimationTrack* track = stateTrack.track_;
     Node* node = stateTrack.node_;
@@ -495,17 +506,11 @@ void AnimationState::ApplyTrackFullWeight(AnimationStateTrack& stateTrack)
     const AnimationKeyFrame* keyFrame = &track->keyFrames_[frame];
     unsigned char channelMask = track->channelMask_;
 
-    if (!interpolate)
-    {
-        // No interpolation, full weight
-        if (channelMask & CHANNEL_POSITION)
-            node->SetPosition(keyFrame->position_);
-        if (channelMask & CHANNEL_ROTATION)
-            node->SetRotation(keyFrame->rotation_);
-        if (channelMask & CHANNEL_SCALE)
-            node->SetScale(keyFrame->scale_);
-    }
-    else
+    Vector3 newPosition;
+    Quaternion newRotation;
+    Vector3 newScale;
+
+    if (interpolate)
     {
         const AnimationKeyFrame* nextKeyFrame = &track->keyFrames_[nextFrame];
         float timeInterval = nextKeyFrame->time_ - keyFrame->time_;
@@ -513,134 +518,69 @@ void AnimationState::ApplyTrackFullWeight(AnimationStateTrack& stateTrack)
             timeInterval += animation_->GetLength();
         float t = timeInterval > 0.0f ? (time_ - keyFrame->time_) / timeInterval : 1.0f;
 
-        // Interpolation, full weight
         if (channelMask & CHANNEL_POSITION)
-            node->SetPosition(keyFrame->position_.Lerp(nextKeyFrame->position_, t));
+            newPosition = keyFrame->position_.Lerp(nextKeyFrame->position_, t);
         if (channelMask & CHANNEL_ROTATION)
-            node->SetRotation(keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t));
+            newRotation = keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t);
         if (channelMask & CHANNEL_SCALE)
-            node->SetScale(keyFrame->scale_.Lerp(nextKeyFrame->scale_, t));
-    }
-}
-
-void AnimationState::ApplyTrackFullWeightSilent(AnimationStateTrack& stateTrack)
-{
-    const AnimationTrack* track = stateTrack.track_;
-    Node* node = stateTrack.node_;
-
-    if (track->keyFrames_.Empty() || !node)
-        return;
-
-    unsigned& frame = stateTrack.keyFrame_;
-    track->GetKeyFrameIndex(time_, frame);
-
-    // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
-    unsigned nextFrame = frame + 1;
-    bool interpolate = true;
-    if (nextFrame >= track->keyFrames_.Size())
-    {
-        if (!looped_)
-        {
-            nextFrame = frame;
-            interpolate = false;
-        }
-        else
-            nextFrame = 0;
+            newScale = keyFrame->scale_.Lerp(nextKeyFrame->scale_, t);
     }
-
-    const AnimationKeyFrame* keyFrame = &track->keyFrames_[frame];
-    unsigned char channelMask = track->channelMask_;
-
-    if (!interpolate)
+    else
     {
-        // No interpolation, full weight
         if (channelMask & CHANNEL_POSITION)
-            node->SetPositionSilent(keyFrame->position_);
+            newPosition = keyFrame->position_;
         if (channelMask & CHANNEL_ROTATION)
-            node->SetRotationSilent(keyFrame->rotation_);
+            newRotation = keyFrame->rotation_;
         if (channelMask & CHANNEL_SCALE)
-            node->SetScaleSilent(keyFrame->scale_);
+            newScale = keyFrame->scale_;
     }
-    else
+    
+    if (!Equals(weight, 1.0f)) // not full weight
     {
-        const AnimationKeyFrame* nextKeyFrame = &track->keyFrames_[nextFrame];
-        float timeInterval = nextKeyFrame->time_ - keyFrame->time_;
-        if (timeInterval < 0.0f)
-            timeInterval += animation_->GetLength();
-        float t = timeInterval > 0.0f ? (time_ - keyFrame->time_) / timeInterval : 1.0f;
-
-        // Interpolation, full weight
         if (channelMask & CHANNEL_POSITION)
-            node->SetPositionSilent(keyFrame->position_.Lerp(nextKeyFrame->position_, t));
+            newPosition = node->GetPosition().Lerp(newPosition, weight);
         if (channelMask & CHANNEL_ROTATION)
-            node->SetRotationSilent(keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t));
+            newRotation = node->GetRotation().Slerp(newRotation, weight);
         if (channelMask & CHANNEL_SCALE)
-            node->SetScaleSilent(keyFrame->scale_.Lerp(nextKeyFrame->scale_, t));
+            newScale = node->GetScale().Lerp(newScale, weight);
     }
-}
-
-void AnimationState::ApplyTrackBlendedSilent(AnimationStateTrack& stateTrack, float weight)
-{
-    const AnimationTrack* track = stateTrack.track_;
-    Node* node = stateTrack.node_;
-
-    if (track->keyFrames_.Empty() || !node)
-        return;
-
-    unsigned& frame = stateTrack.keyFrame_;
-    track->GetKeyFrameIndex(time_, frame);
-
-    // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
-    unsigned nextFrame = frame + 1;
-    bool interpolate = true;
-    if (nextFrame >= track->keyFrames_.Size())
+    
+    if (blendingMode_ == ABM_ADDITIVE) // not ABM_OVERRIDE
     {
-        if (!looped_)
+        if (channelMask & CHANNEL_POSITION)
         {
-            nextFrame = frame;
-            interpolate = false;
+            Vector3 delta = newPosition - stateTrack.bone_->initialPosition_;
+            newPosition = node->GetPosition() + delta;
+        }
+        if (channelMask & CHANNEL_ROTATION)
+        {
+            Quaternion delta = newRotation * stateTrack.bone_->initialRotation_.Inverse();
+            newRotation = (delta * node->GetRotation()).Normalized();
+        }
+        if (channelMask & CHANNEL_SCALE)
+        {
+            Vector3 delta = newScale - stateTrack.bone_->initialScale_;
+            newScale = node->GetScale() + delta;
         }
-        else
-            nextFrame = 0;
     }
-
-    const AnimationKeyFrame* keyFrame = &track->keyFrames_[frame];
-    unsigned char channelMask = track->channelMask_;
-
-    if (!interpolate)
+    
+    if (silent)
     {
-        // No interpolation, blend between old transform & animation
         if (channelMask & CHANNEL_POSITION)
-            node->SetPositionSilent(node->GetPosition().Lerp(keyFrame->position_, weight));
+            node->SetPositionSilent(newPosition);
         if (channelMask & CHANNEL_ROTATION)
-            node->SetRotationSilent(node->GetRotation().Slerp(keyFrame->rotation_, weight));
+            node->SetRotationSilent(newRotation);
         if (channelMask & CHANNEL_SCALE)
-            node->SetScaleSilent(node->GetScale().Lerp(keyFrame->scale_, weight));
+            node->SetScaleSilent(newScale);
     }
     else
     {
-        const AnimationKeyFrame* nextKeyFrame = &track->keyFrames_[nextFrame];
-        float timeInterval = nextKeyFrame->time_ - keyFrame->time_;
-        if (timeInterval < 0.0f)
-            timeInterval += animation_->GetLength();
-        float t = timeInterval > 0.0f ? (time_ - keyFrame->time_) / timeInterval : 1.0f;
-
-        // Interpolation, blend between old transform & animation
         if (channelMask & CHANNEL_POSITION)
-        {
-            node->SetPositionSilent(node->GetPosition().Lerp(
-                keyFrame->position_.Lerp(nextKeyFrame->position_, t), weight));
-        }
+            node->SetPosition(newPosition);
         if (channelMask & CHANNEL_ROTATION)
-        {
-            node->SetRotationSilent(node->GetRotation().Slerp(
-                keyFrame->rotation_.Slerp(nextKeyFrame->rotation_, t), weight));
-        }
+            node->SetRotation(newRotation);
         if (channelMask & CHANNEL_SCALE)
-        {
-            node->SetScaleSilent(node->GetScale().Lerp(
-                keyFrame->scale_.Lerp(nextKeyFrame->scale_, t), weight));
-        }
+            node->SetScale(newScale);
     }
 }
 

+ 16 - 6
Source/Urho3D/Graphics/AnimationState.h

@@ -36,6 +36,13 @@ class Skeleton;
 struct AnimationTrack;
 struct Bone;
 
+/// %Animation blending mode.
+enum AnimationBlendingMode
+{
+    ABM_OVERRIDE = 0,
+    ABM_ADDITIVE
+};
+
 /// %Animation instance per-track data.
 struct AnimationStateTrack
 {
@@ -73,6 +80,8 @@ public:
     void SetLooped(bool looped);
     /// Set blending weight.
     void SetWeight(float weight);
+    /// Set blending mode.
+    void SetBlendingMode(AnimationBlendingMode mode);
     /// Set time position. Does not fire animation triggers.
     void SetTime(float time);
     /// Set per-bone blending weight by track index. Default is 1.0 (full), is multiplied  with the state's blending weight when applying the animation. Optionally recurses to child bones.
@@ -119,6 +128,9 @@ public:
     /// Return blending weight.
     float GetWeight() const { return weight_; }
 
+    /// Return blending mode.
+    AnimationBlendingMode GetBlendingMode() const { return blendingMode_; }
+
     /// Return time position.
     float GetTime() const { return time_; }
 
@@ -136,12 +148,8 @@ private:
     void ApplyToModel();
     /// Apply animation to a scene node hierarchy.
     void ApplyToNodes();
-    /// Apply animation track to a scene node, full weight.
-    void ApplyTrackFullWeight(AnimationStateTrack& stateTrack);
-    /// Apply animation track to a scene node, full weight. Apply transform changes silently without marking the node dirty.
-    void ApplyTrackFullWeightSilent(AnimationStateTrack& stateTrack);
-    /// Apply animation track to a scene node, blended with current node transform. Apply transform changes silently without marking the node dirty.
-    void ApplyTrackBlendedSilent(AnimationStateTrack& stateTrack, float weight);
+    /// Apply track.
+    void ApplyTrack(AnimationStateTrack& stateTrack, float weight, bool silent);
 
     /// Animated model (model mode.)
     WeakPtr<AnimatedModel> model_;
@@ -161,6 +169,8 @@ private:
     float time_;
     /// Blending layer.
     unsigned char layer_;
+    /// Blending mode.
+    AnimationBlendingMode blendingMode_;
 };
 
 }

+ 2 - 0
Source/Urho3D/LuaScript/pkgs/Graphics/AnimationController.pkg

@@ -32,6 +32,7 @@ class AnimationController : public Component
     bool SetTime(const String name, float time);
     bool SetWeight(const String name, float weight);
     bool SetLooped(const String name, bool enable);
+    bool SetBlendingMode(const String name, AnimationBlendingMode mode);
     bool SetSpeed(const String name, float speed);
     bool SetAutoFade(const String name, float fadeOutTime);
     bool SetRemoveOnCompletion(const String name, bool removeOnCompletion);
@@ -46,6 +47,7 @@ class AnimationController : public Component
     float GetTime(const String name) const;
     float GetWeight(const String name) const;
     bool IsLooped(const String name) const;
+    AnimationBlendingMode GetBlendingMode(const String name) const;
     float GetLength(const String name) const;
     float GetSpeed(const String name) const;
     float GetFadeTarget(const String name) const;

+ 8 - 0
Source/Urho3D/LuaScript/pkgs/Graphics/AnimationState.pkg

@@ -1,5 +1,11 @@
 $#include "Graphics/AnimationState.h"
 
+enum AnimationBlendingMode
+{
+    ABM_OVERRIDE = 0,
+    ABM_ADDITIVE
+};
+
 class AnimationState
 {
     AnimationState(AnimatedModel* model, Animation* animation);
@@ -16,6 +22,7 @@ class AnimationState
     void AddWeight(float delta);
     void AddTime(float delta);
     void SetLayer(unsigned char layer);
+    void SetBlendingMode(AnimationBlendingMode mode);
 
     Animation* GetAnimation() const;
     Bone* GetStartBone() const;
@@ -30,6 +37,7 @@ class AnimationState
     float GetTime() const;
     float GetLength() const;
     unsigned char GetLayer() const;
+    AnimationBlendingMode GetBlendingMode() const;
 
     tolua_readonly tolua_property__get_set Animation* animation;
     tolua_property__get_set Bone* startBone;