Bladeren bron

AnimationCurve (WIP)

BearishSun 9 jaren geleden
bovenliggende
commit
947bd35ee5

+ 18 - 0
Source/BansheeCore/CMakeSources.cmake

@@ -494,6 +494,20 @@ set(BS_BANSHEECORE_SRC_AUDIO
 	"Source/BsAudioManager.cpp"
 	"Source/BsAudioManager.cpp"
 )
 )
 
 
+set(BS_BANSHEECORE_INC_ANIMATION
+	"Include/BsAnimationCurve.h"
+	"Include/BsAnimationClip.h"
+	"Include/BsSkeleton.h"
+	"Include/BsAnimation.h"
+)
+
+set(BS_BANSHEECORE_SRC_ANIMATION
+	"Source/BsAnimationCurve.cpp"
+	"Source/BsAnimationClip.cpp"
+	"Source/BsSkeleton.cpp"
+	"Source/BsAnimation.cpp"
+)
+
 source_group("Header Files\\Components" FILES ${BS_BANSHEECORE_INC_COMPONENTS})
 source_group("Header Files\\Components" FILES ${BS_BANSHEECORE_INC_COMPONENTS})
 source_group("Header Files\\Physics" FILES ${BS_BANSHEECORE_INC_PHYSICS})
 source_group("Header Files\\Physics" FILES ${BS_BANSHEECORE_INC_PHYSICS})
 source_group("Header Files\\CoreThread" FILES ${BS_BANSHEECORE_INC_CORETHREAD})
 source_group("Header Files\\CoreThread" FILES ${BS_BANSHEECORE_INC_CORETHREAD})
@@ -530,6 +544,8 @@ source_group("Source Files\\Physics" FILES ${BS_BANSHEECORE_SRC_PHYSICS})
 source_group("Source Files\\Scene" FILES ${BS_BANSHEECORE_SRC_SCENE})
 source_group("Source Files\\Scene" FILES ${BS_BANSHEECORE_SRC_SCENE})
 source_group("Header Files\\Audio" FILES ${BS_BANSHEECORE_INC_AUDIO})
 source_group("Header Files\\Audio" FILES ${BS_BANSHEECORE_INC_AUDIO})
 source_group("Source Files\\Audio" FILES ${BS_BANSHEECORE_SRC_AUDIO})
 source_group("Source Files\\Audio" FILES ${BS_BANSHEECORE_SRC_AUDIO})
+source_group("Header Files\\Animation" FILES ${BS_BANSHEECORE_INC_ANIMATION})
+source_group("Source Files\\Animation" FILES ${BS_BANSHEECORE_SRC_ANIMATION})
 
 
 set(BS_BANSHEECORE_SRC
 set(BS_BANSHEECORE_SRC
 	${BS_BANSHEECORE_INC_COMPONENTS}
 	${BS_BANSHEECORE_INC_COMPONENTS}
@@ -568,4 +584,6 @@ set(BS_BANSHEECORE_SRC
 	${BS_BANSHEECORE_SRC_SCENE}
 	${BS_BANSHEECORE_SRC_SCENE}
 	${BS_BANSHEECORE_INC_AUDIO}
 	${BS_BANSHEECORE_INC_AUDIO}
 	${BS_BANSHEECORE_SRC_AUDIO}
 	${BS_BANSHEECORE_SRC_AUDIO}
+	${BS_BANSHEECORE_INC_ANIMATION}
+	${BS_BANSHEECORE_SRC_ANIMATION}
 )
 )

+ 26 - 0
Source/BansheeCore/Include/BsAnimation.h

@@ -0,0 +1,26 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Animation
+	 *  @{
+	 */
+
+	struct AnimationInstanceData
+	{
+	public:
+		AnimationInstanceData();
+
+		float time;
+	private:
+		template <class T> friend class TAnimationCurve;
+
+		mutable UINT32 cachedKey;
+	};
+
+	/** @} */
+}

+ 1 - 0
Source/BansheeCore/Include/BsAnimationClip.h

@@ -0,0 +1 @@
+#pragma once

+ 45 - 0
Source/BansheeCore/Include/BsAnimationCurve.h

@@ -0,0 +1,45 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Animation
+	 *  @{
+	 */
+
+	template <class T>
+	struct TKeyframe
+	{
+		T value;
+		T inTangent;
+		T outTangent;
+		float time;
+	};
+
+	template <class T>
+	class BS_CORE_EXPORT TAnimationCurve
+	{
+	public:
+		typedef TKeyframe<T> KeyFrame;
+
+		TAnimationCurve(const Vector<KeyFrame>& keyframes);
+
+		T evaluate(const AnimationInstanceData& animInstance, bool loop = true);
+
+	private:
+		void findKeys(const AnimationInstanceData& animInstance, UINT32& leftKey, UINT32& rightKey);
+		void findKeys(float time, UINT32& leftKey, UINT32& rightKey);
+
+		static const UINT32 CACHE_LOOKAHEAD;
+
+		Vector<KeyFrame> mKeyframes;
+		float mStart;
+		float mEnd;
+		float mLength;
+	};
+
+	/** @} */
+}

+ 6 - 0
Source/BansheeCore/Include/BsCorePrerequisites.h

@@ -17,6 +17,10 @@
  *	Audio clips, 3D sound and music reproduction.
  *	Audio clips, 3D sound and music reproduction.
  */
  */
 
 
+/** @defgroup Animation Animation
+ *	Animation clips, skeletal and blend shape animation, animation playback, blending and other features.
+ */
+
 /** @defgroup CoreThread Core thread
 /** @defgroup CoreThread Core thread
  *	Core objects and interaction with the core (rendering) thread.
  *	Core objects and interaction with the core (rendering) thread.
  */
  */
@@ -351,6 +355,8 @@ namespace BansheeEngine
 	class AudioListener;
 	class AudioListener;
 	class AudioSource;
 	class AudioSource;
 	class AudioClipImportOptions;
 	class AudioClipImportOptions;
+	class AnimationClip;
+	struct AnimationInstanceData;
 	// Asset import
 	// Asset import
 	class SpecificImporter;
 	class SpecificImporter;
 	class Importer;
 	class Importer;

+ 1 - 0
Source/BansheeCore/Include/BsSkeleton.h

@@ -0,0 +1 @@
+#pragma once

+ 12 - 0
Source/BansheeCore/Source/BsAnimation.cpp

@@ -0,0 +1,12 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsAnimation.h"
+
+namespace BansheeEngine
+{
+	AnimationInstanceData::AnimationInstanceData()
+		:time(0.0f), cachedKey((UINT32)-1)
+	{
+		
+	}
+}

+ 0 - 0
Source/BansheeCore/Source/BsAnimationClip.cpp


+ 189 - 0
Source/BansheeCore/Source/BsAnimationCurve.cpp

@@ -0,0 +1,189 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsAnimationCurve.h"
+#include "BsAnimation.h"
+#include "BsVector3.h"
+#include "BsQuaternion.h"
+#include "BsMath.h"
+
+namespace BansheeEngine
+{
+	template <class T>
+	const UINT32 TAnimationCurve<T>::CACHE_LOOKAHEAD = 3;
+
+	template <class T>
+	TAnimationCurve<T>::TAnimationCurve(const Vector<KeyFrame>& keyframes)
+		:mKeyframes(keyframes)
+	{
+#if BS_DEBUG_MODE
+		// Ensure keyframes are sorted
+		if(keyframes.size() > 0)
+		{
+			float time = keyframes[0].time;
+			for (UINT32 i = 1; i < (UINT32)keyframes.size(); i++)
+			{
+				assert(keyframes[i].time > time);
+				time = keyframes[i].time;
+			}
+		}
+#endif
+
+		if (keyframes.size() > 0)
+		{
+			mStart = keyframes[0].time;
+			mEnd = keyframes.back().time;
+		}
+		else
+		{
+			mStart = 0.0f;
+			mEnd = 0.0f;
+		}
+
+		mLength = mEnd - mStart;
+	}
+
+	template <class T>
+	T TAnimationCurve<T>::evaluate(const AnimationInstanceData& animInstance, bool loop)
+	{
+		if (mKeyframes.size() == 0)
+			return T();
+
+		float time = animInstance.time;
+
+		// TODO - If within cache evaluate it
+
+		// Clamp to start or loop
+		if(time < mStart)
+		{
+			if (loop)
+				time = time - std::floor(time / mLength) * mLength;
+			else
+				time = mStart; // TODO - Cache cubic hermite spline coefficients
+		}
+
+		// Clamp to end or loop
+		if(time > mEnd)
+		{
+			// TODO - Cache cubic hermite spline coefficients
+			if(loop)
+				time = time - std::floor(time / mLength) * mLength;
+			else
+				time = mEnd; // TODO - Cache cubic hermite spline coefficients
+		}
+
+		UINT32 leftKeyIdx;
+		UINT32 rightKeyIdx;
+
+		findKeys(animInstance, leftKeyIdx, rightKeyIdx);
+
+		// Evaluate curve as hermite cubic spline
+		const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
+		const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
+
+		float length = rightKey.time - leftKey.time;
+		float t = (time - leftKey.time) / length;
+		T leftTangent;
+		T rightTangent; // TODO - Remove zero init for vectors/quaternions by default
+
+		if (Math::approxEquals(t, 0.0f))
+		{
+			t = 0.0f;
+			leftTangent = T();
+			rightTangent = T();
+		}
+		else
+		{
+			// Resize tangents since we're not evaluating the curve over unit range
+			leftTangent = leftKey.outTangent * length;
+			rightTangent = rightKey.inTangent * length;
+		}
+
+		T output = Math::cubicHermite(t, leftKey.value, rightKey.value, leftTangent, rightTangent);
+
+		// TODO - Handle stepped curve - If tangents are infinite assume constant value from left key is used
+
+		// TODO - Cache cubic hermite spline coefficients
+
+		return output;
+	}
+
+	template <class T>
+	void TAnimationCurve<T>::findKeys(const AnimationInstanceData& animInstance, UINT32& leftKey, UINT32& rightKey)
+	{
+		float time = animInstance.time;
+
+		// Check nearby keys first if there is cached data
+		if (animInstance.cachedKey != (UINT32)-1)
+		{
+			const KeyFrame& curKey = mKeyframes[animInstance.cachedKey];
+			if (time >= curKey.time)
+			{
+				UINT32 end = std::min((UINT32)mKeyframes.size(), animInstance.cachedKey + CACHE_LOOKAHEAD + 1);
+				for (UINT32 i = animInstance.cachedKey + 1; i < end; i++)
+				{
+					const KeyFrame& nextKey = mKeyframes[i];
+
+					if (time < nextKey.time)
+					{
+						leftKey = i - 1;
+						rightKey = i;
+
+						animInstance.cachedKey = leftKey;
+						return;
+					}
+				}
+			}
+			else
+			{
+				UINT32 start = (UINT32)std::max(0, (INT32)animInstance.cachedKey - (INT32)CACHE_LOOKAHEAD);
+				for(UINT32 i = start; i < animInstance.cachedKey; i++)
+				{
+					const KeyFrame& prevKey = mKeyframes[i];
+
+					if (time >= prevKey.time)
+					{
+						leftKey = i;
+						rightKey = i + 1;
+
+						animInstance.cachedKey = leftKey;
+						return;
+					}
+				}
+			}
+		}
+
+		// Cannot find nearby ones, search all keys
+		findKeys(time, leftKey, rightKey);
+		animInstance.cachedKey = leftKey;
+	}
+
+	template <class T>
+	void TAnimationCurve<T>::findKeys(float time, UINT32& leftKey, UINT32& rightKey)
+	{
+		INT32 start = 0;
+		INT32 searchLength = (INT32)mKeyframes.size();
+		
+		while(searchLength > 0)
+		{
+			INT32 half = searchLength >> 1;
+			INT32 mid = start + half;
+
+			if(time < mKeyframes[mid].time)
+			{
+				searchLength = half;
+			}
+			else
+			{
+				start = mid + 1;
+				searchLength -= half - 1;
+			}
+		}
+
+		leftKey = start - 1;
+		rightKey = std::min(start, (INT32)mKeyframes.size() - 1);
+	}
+
+	template class TAnimationCurve<Vector3>;
+	template class TAnimationCurve<Quaternion>;
+	template class TAnimationCurve<float>;
+}

+ 0 - 0
Source/BansheeCore/Source/BsSkeleton.cpp


+ 43 - 0
Source/BansheeUtility/Include/BsMath.h

@@ -593,6 +593,49 @@ namespace BansheeEngine
 			return numRoots;
 			return numRoots;
 		}
 		}
 
 
+		/**
+		 * Evaluates a cubic Hermite curve at a specific point.
+		 *
+		 * @param[in]	t			Parameter that at which to evaluate the curve, in range [0, 1].
+		 * @param[in]	pointA		Starting point (at t=0).
+		 * @param[in]	pointB		Ending point (at t=1).
+		 * @param[in]	tangentA	Starting tangent (at t=0).
+		 * @param[in]	tangentB	Ending tangent (at t = 1).
+		 * @return					Evaluated value at @p t.
+		 */
+		template<class T>
+		static T cubicHermite(float t, const T& pointA, const T& pointB, const T& tangentA, const T& tangentB)
+		{
+			float t2 = t * t;
+			float t3 = t2 * t;
+
+			float a = 2 * t3 - 3 * t2 + 1;
+			float b = t3 - 2 * t2 + t;
+			float c = -2 * t3 + 3 * t2;
+			float d = t3 - t2;
+
+			return a * pointA + b * tangentA + c * tangentB + d * pointB;
+		}
+
+		/**
+		 * Calculates coefficients needed for evaluating a cubic curve in Hermite form.
+		 *
+		 * @param[in]	pointA			Starting point (at t=0).
+		 * @param[in]	pointB			Ending point (at t=1).
+		 * @param[in]	tangentA		Starting tangent (at t=0).
+		 * @param[in]	tangentB		Ending tangent (at t = 1).
+		 * @param[out]	coefficients	Four coefficients for the cubic curve, in order [t^3, t^2, t, 1].
+		 */
+		template<class T>
+		static void cubicHermiteCoefficients(const T& pointA, const T& pointB, const T& tangentA, const T& tangentB, 
+			T (&coefficients)[4])
+		{
+			coefficients[0] = 2 * pointA - 2 * pointB + tangentA + tangentB;
+			coefficients[1] = -3 * pointA + 3 * pointB - 2 * tangentA - tangentB;
+			coefficients[2] = tangentA;
+			coefficients[4] = pointA;
+		}
+
         static const float POS_INFINITY;
         static const float POS_INFINITY;
         static const float NEG_INFINITY;
         static const float NEG_INFINITY;
         static const float PI;
         static const float PI;

+ 45 - 8
Source/BansheeUtility/Include/BsQuaternion.h

@@ -184,11 +184,36 @@ namespace BansheeEngine
 			return *this;
 			return *this;
 		}
 		}
 
 
-        Quaternion operator+ (const Quaternion& rhs) const;
-        Quaternion operator- (const Quaternion& rhs) const;
-        Quaternion operator* (const Quaternion& rhs) const;
-        Quaternion operator* (float rhs) const;
-        Quaternion operator- () const;
+        Quaternion operator+ (const Quaternion& rhs) const 
+		{
+			return Quaternion(w + rhs.w, x + rhs.x, y + rhs.y, z + rhs.z);
+		}
+
+        Quaternion operator- (const Quaternion& rhs) const
+		{
+			return Quaternion(w - rhs.w, x - rhs.x, y - rhs.y, z - rhs.z);
+		}
+
+		Quaternion operator* (const Quaternion& rhs) const
+		{
+			return Quaternion
+			(
+				w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z,
+				w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y,
+				w * rhs.y + y * rhs.w + z * rhs.x - x * rhs.z,
+				w * rhs.z + z * rhs.w + x * rhs.y - y * rhs.x
+			);
+		}
+
+		Quaternion operator* (float rhs) const
+		{
+			return Quaternion(rhs * w, rhs * x, rhs * y, rhs * z);
+		}
+
+        Quaternion operator- () const
+		{
+			return Quaternion(-w, -x, -y, -z);
+		}
 
 
         bool operator== (const Quaternion& rhs) const
         bool operator== (const Quaternion& rhs) const
 		{
 		{
@@ -200,13 +225,25 @@ namespace BansheeEngine
 			return !operator==(rhs);
 			return !operator==(rhs);
 		}
 		}
 
 
-		friend Quaternion operator* (float lhs, const Quaternion& rhs);
+		friend Quaternion operator* (float lhs, const Quaternion& rhs)
+		{
+			return Quaternion(lhs * rhs.w, lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
+		}
 
 
         /** Calculates the dot product of this quaternion and another. */
         /** Calculates the dot product of this quaternion and another. */
-        float dot(const Quaternion& other) const;  
+        float dot(const Quaternion& other) const
+        {
+			return w * other.w + x * other.x + y * other.y + z * other.z;
+        }
 
 
         /** Normalizes this quaternion, and returns the previous length. */
         /** Normalizes this quaternion, and returns the previous length. */
-        float normalize(); 
+        float normalize()
+        {
+			float len = w*w + x*x + y*y + z*z;
+			float factor = 1.0f / Math::sqrt(len);
+			*this = *this * factor;
+			return len;
+        }
 
 
         /**
         /**
          * Gets the inverse.
          * Gets the inverse.

+ 0 - 50
Source/BansheeUtility/Source/BsQuaternion.cpp

@@ -255,42 +255,6 @@ namespace BansheeEngine
         return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy));
         return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy));
     }
     }
 
 
-    Quaternion Quaternion::operator+ (const Quaternion& rhs) const
-    {
-        return Quaternion(w+rhs.w,x+rhs.x,y+rhs.y,z+rhs.z);
-    }
-
-    Quaternion Quaternion::operator- (const Quaternion& rhs) const
-    {
-        return Quaternion(w-rhs.w,x-rhs.x,y-rhs.y,z-rhs.z);
-    }
-
-    Quaternion Quaternion::operator* (const Quaternion& rhs) const
-    {
-        return Quaternion
-        (
-            w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z,
-            w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y,
-            w * rhs.y + y * rhs.w + z * rhs.x - x * rhs.z,
-            w * rhs.z + z * rhs.w + x * rhs.y - y * rhs.x
-        );
-    }
-
-    Quaternion Quaternion::operator* (float rhs) const
-    {
-        return Quaternion(rhs*w,rhs*x,rhs*y,rhs*z);
-    }
-
-    Quaternion Quaternion::operator- () const
-    {
-        return Quaternion(-w,-x,-y,-z);
-    }
-
-    float Quaternion::dot(const Quaternion& other) const
-    {
-        return w*other.w+x*other.x+y*other.y+z*other.z;
-    }
-
     Quaternion Quaternion::inverse() const
     Quaternion Quaternion::inverse() const
     {
     {
         float fNorm = w*w+x*x+y*y+z*z;
         float fNorm = w*w+x*x+y*y+z*z;
@@ -399,14 +363,6 @@ namespace BansheeEngine
         }
         }
     }
     }
 
 
-    float Quaternion::normalize()
-    {
-        float len = w*w+x*x+y*y+z*z;
-        float factor = 1.0f / Math::sqrt(len);
-        *this = *this * factor;
-        return len;
-    }
-
 	Quaternion Quaternion::getRotationFromTo(const Vector3& from, const Vector3& dest, const Vector3& fallbackAxis)
 	Quaternion Quaternion::getRotationFromTo(const Vector3& from, const Vector3& dest, const Vector3& fallbackAxis)
 	{
 	{
 		// Based on Stan Melax's article in Game Programming Gems
 		// Based on Stan Melax's article in Game Programming Gems
@@ -456,10 +412,4 @@ namespace BansheeEngine
 
 
 		return q;
 		return q;
 	}
 	}
-
-	Quaternion operator* (float lhs, const Quaternion& rhs)
-	{
-		return Quaternion(lhs*rhs.w,lhs*rhs.x,lhs*rhs.y,
-			lhs*rhs.z);
-	}
 }
 }