Răsfoiți Sursa

Skeleton bone -> animation curve mapping added to AnimationClip

BearishSun 9 ani în urmă
părinte
comite
c466d5713f

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

@@ -23,6 +23,27 @@ namespace BansheeEngine
 		Vector<TNamedAnimationCurve<float>> generic;
 		Vector<TNamedAnimationCurve<float>> generic;
 	};
 	};
 
 
+	/** Contains indices for position/rotation/scale animation curves. */
+	struct AnimationCurveMapping
+	{
+		UINT32 position;
+		UINT32 rotation;
+		UINT32 scale;
+	};
+
+	/** Types of curves in an AnimationClip. */
+	enum class CurveType
+	{
+		Position,
+		Rotation,
+		Scale,
+		Generic
+	};
+
+	/** 
+	 * Contains animation curves for translation/rotation/scale of scene objects/skeleton bones, as well as curves for
+	 * generic property animation. 
+	 */
 	class BS_CORE_EXPORT AnimationClip : public Resource
 	class BS_CORE_EXPORT AnimationClip : public Resource
 	{
 	{
 	public:
 	public:
@@ -108,6 +129,29 @@ namespace BansheeEngine
 		 */
 		 */
 		void removeGenericCurve(const String& name);
 		void removeGenericCurve(const String& name);
 
 
+		/** 
+		 * Returns all curves stored in the animation. Returned value will not be updated if the animation clip curves are
+		 * added or removed. Caller must monitor for changes and retrieve a new set of curves when that happens.
+		 */
+		SPtr<AnimationCurves> getCurves() const { return mCurves; }
+
+		/**
+		 * Maps skeleton bone names to animation clip names, and returns a set of indices that can be easily used for
+		 * locating an animation curve based on the bone index.
+		 *
+		 * @param[in]	skeleton	Skeleton to create the mapping for.
+		 * @param[out]	mapping		Pre-allocated array that will receive output animation clip indices. The array must
+		 *							be large enough to store an index for every bone in the @p skeleton. Bones that have
+		 *							no related animation curves will be assigned value -1.
+		 */
+		void getBoneMapping(const SPtr<Skeleton>& skeleton, AnimationCurveMapping* mapping);
+
+		/** 
+		 * Returns a version that can be used for detecting modifications on the clip by external systems. Whenever the clip
+		 * is modified the version is increased by one.
+		 */
+		UINT64 getVersion() const { return mVersion; }
+
 		/** 
 		/** 
 		 * Creates an animation clip with no curves. After creation make sure to register some animation curves before
 		 * Creates an animation clip with no curves. After creation make sure to register some animation curves before
 		 * using it. 
 		 * using it. 
@@ -135,6 +179,14 @@ namespace BansheeEngine
 		AnimationClip();
 		AnimationClip();
 		AnimationClip(const SPtr<AnimationCurves>& curves);
 		AnimationClip(const SPtr<AnimationCurves>& curves);
 
 
+		/** @copydoc Resource::initialize() */
+		void initialize() override;
+
+		/** Creates a name -> curve index mapping for quicker curve lookup by name. */
+		void buildNameMapping();
+
+		UINT64 mVersion;
+
 		/** 
 		/** 
 		 * Contains all the animation curves in the clip. It's important this field is immutable so it may be used on other
 		 * Contains all the animation curves in the clip. It's important this field is immutable so it may be used on other
 		 * threads. This means any modifications to the field will require a brand new data structure to be generated and
 		 * threads. This means any modifications to the field will require a brand new data structure to be generated and
@@ -142,6 +194,11 @@ namespace BansheeEngine
 		 */
 		 */
 		SPtr<AnimationCurves> mCurves;
 		SPtr<AnimationCurves> mCurves;
 
 
+		/** 
+		 * Contains a map from curve name to curve index. Indices are stored as specified in CurveType enum. 
+		 */
+		UnorderedMap<String, UINT32[4]> mNameMapping;
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
 		/* 								SERIALIZATION                      		*/
 		/************************************************************************/
 		/************************************************************************/

+ 6 - 3
Source/BansheeCore/Include/BsSkeleton.h

@@ -20,11 +20,10 @@ namespace BansheeEngine
 		Matrix4 invBindPose;
 		Matrix4 invBindPose;
 	};
 	};
 
 
-	struct ANIMATION_STATE_DESC
+	struct ANIM_BLEND_STATE_DESC
 	{
 	{
 		const AnimationClip* clip;
 		const AnimationClip* clip;
 		float weight;
 		float weight;
-		float speed;
 		bool loop;
 		bool loop;
 		UINT8 layer;
 		UINT8 layer;
 	};
 	};
@@ -56,7 +55,11 @@ namespace BansheeEngine
 		~Skeleton();
 		~Skeleton();
 
 
 		void getPose(SkeletonPose& pose, const AnimationClip& clip, float time, bool loop = true);
 		void getPose(SkeletonPose& pose, const AnimationClip& clip, float time, bool loop = true);
-		void getPose(SkeletonPose& pose, const ANIMATION_STATE_DESC* states, UINT32 numStates, float time);
+		void getPose(SkeletonPose& pose, const ANIM_BLEND_STATE_DESC* states, UINT32 numStates, float time);
+
+		UINT32 getNumBones() const { return mNumBones; }
+		const SkeletonBoneInfo& getBoneInfo(UINT32 idx) const { return mBoneInfo[idx]; }
+		const Matrix4& getBindPose(UINT32 idx) const { return mBindPoses[idx]; }
 
 
 		static SPtr<Skeleton> create(BONE_DESC* bones, UINT32 numBones);
 		static SPtr<Skeleton> create(BONE_DESC* bones, UINT32 numBones);
 
 

+ 87 - 8
Source/BansheeCore/Source/BsAnimationClip.cpp

@@ -2,18 +2,19 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsAnimationClip.h"
 #include "BsAnimationClip.h"
 #include "BsResources.h"
 #include "BsResources.h"
+#include "BsSkeleton.h"
 #include "BsAnimationClipRTTI.h"
 #include "BsAnimationClipRTTI.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	AnimationClip::AnimationClip()
 	AnimationClip::AnimationClip()
-		: Resource(false), mCurves(bs_shared_ptr_new<AnimationCurves>())
+		: Resource(false), mVersion(0), mCurves(bs_shared_ptr_new<AnimationCurves>())
 	{
 	{
-		
+
 	}
 	}
 
 
 	AnimationClip::AnimationClip(const SPtr<AnimationCurves>& curves)
 	AnimationClip::AnimationClip(const SPtr<AnimationCurves>& curves)
-		: Resource(false), mCurves(curves)
+		: Resource(false), mVersion(0), mCurves(curves)
 	{
 	{
 
 
 	}
 	}
@@ -66,8 +67,10 @@ namespace BansheeEngine
 		}
 		}
 
 
 		newCurves->position.push_back({ name, curve });
 		newCurves->position.push_back({ name, curve });
-
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
 	}
 	}
 
 
 	void AnimationClip::addRotationCurve(const String& name, const TAnimationCurve<Quaternion>& curve)
 	void AnimationClip::addRotationCurve(const String& name, const TAnimationCurve<Quaternion>& curve)
@@ -84,8 +87,10 @@ namespace BansheeEngine
 		}
 		}
 
 
 		newCurves->rotation.push_back({ name, curve });
 		newCurves->rotation.push_back({ name, curve });
-
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
 	}
 	}
 
 
 	void AnimationClip::addScaleCurve(const String& name, const TAnimationCurve<Vector3>& curve)
 	void AnimationClip::addScaleCurve(const String& name, const TAnimationCurve<Vector3>& curve)
@@ -102,8 +107,10 @@ namespace BansheeEngine
 		}
 		}
 
 
 		newCurves->scale.push_back({ name, curve });
 		newCurves->scale.push_back({ name, curve });
-
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
 	}
 	}
 
 
 	void AnimationClip::addGenericCurve(const String& name, const TAnimationCurve<float>& curve)
 	void AnimationClip::addGenericCurve(const String& name, const TAnimationCurve<float>& curve)
@@ -119,9 +126,10 @@ namespace BansheeEngine
 				newCurves->generic.push_back(entry);
 				newCurves->generic.push_back(entry);
 		}
 		}
 
 
-		newCurves->generic.push_back({ name, curve });
-
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
 	}
 	}
 
 
 	void AnimationClip::removePositionCurve(const String& name)
 	void AnimationClip::removePositionCurve(const String& name)
@@ -138,6 +146,9 @@ namespace BansheeEngine
 		}
 		}
 
 
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
 	}
 	}
 
 
 	void AnimationClip::removeRotationCurve(const String& name)
 	void AnimationClip::removeRotationCurve(const String& name)
@@ -154,6 +165,9 @@ namespace BansheeEngine
 		}
 		}
 
 
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
 	}
 	}
 
 
 	void AnimationClip::removeScaleCurve(const String& name)
 	void AnimationClip::removeScaleCurve(const String& name)
@@ -170,6 +184,9 @@ namespace BansheeEngine
 		}
 		}
 
 
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
 	}
 	}
 
 
 	void AnimationClip::removeGenericCurve(const String& name)
 	void AnimationClip::removeGenericCurve(const String& name)
@@ -186,6 +203,68 @@ namespace BansheeEngine
 		}
 		}
 
 
 		mCurves = newCurves;
 		mCurves = newCurves;
+
+		buildNameMapping();
+		mVersion++;
+	}
+
+	void AnimationClip::buildNameMapping()
+	{
+		mNameMapping.clear();
+
+		auto registerEntries = [&](auto& curve, CurveType type)
+		{
+			UINT32 typeIdx = (UINT32)type;
+
+			for (UINT32 i = 0; i < (UINT32)curve.size(); i++)
+			{
+				auto& entry = curve[i];
+
+				auto iterFind = mNameMapping.find(entry.name);
+				if (iterFind == mNameMapping.end())
+				{
+					UINT32* indices = mNameMapping[entry.name];
+					memset(indices, -1, sizeof(UINT32) * 4);
+
+					indices[typeIdx] = i;
+				}
+				else
+					mNameMapping[entry.name][typeIdx] = i;
+			}
+		};
+
+		registerEntries(mCurves->position, CurveType::Position);
+		registerEntries(mCurves->rotation, CurveType::Rotation);
+		registerEntries(mCurves->scale, CurveType::Scale);
+		registerEntries(mCurves->generic, CurveType::Generic);
+	}
+
+	void AnimationClip::initialize()
+	{
+		buildNameMapping();
+
+		Resource::initialize();
+	}
+
+	void AnimationClip::getBoneMapping(const SPtr<Skeleton>& skeleton, AnimationCurveMapping* mapping)
+	{
+		UINT32 numBones = skeleton->getNumBones();
+		for(UINT32 i = 0; i < numBones; i++)
+		{
+			const SkeletonBoneInfo& boneInfo = skeleton->getBoneInfo(i);
+
+			auto iterFind = mNameMapping.find(boneInfo.name);
+			if(iterFind != mNameMapping.end())
+			{
+				UINT32* indices = iterFind->second;
+
+				mapping[i].position = indices[(UINT32)CurveType::Position];
+				mapping[i].rotation = indices[(UINT32)CurveType::Rotation];
+				mapping[i].scale = indices[(UINT32)CurveType::Scale];
+			}
+			else
+				mapping[i] = { (UINT32)-1, (UINT32)-1, (UINT32)-1 };
+		}
 	}
 	}
 
 
 	RTTITypeBase* AnimationClip::getRTTIStatic()
 	RTTITypeBase* AnimationClip::getRTTIStatic()

+ 2 - 3
Source/BansheeCore/Source/BsSkeleton.cpp

@@ -38,17 +38,16 @@ namespace BansheeEngine
 
 
 	void Skeleton::getPose(SkeletonPose& pose, const AnimationClip& clip, float time, bool loop)
 	void Skeleton::getPose(SkeletonPose& pose, const AnimationClip& clip, float time, bool loop)
 	{
 	{
-		ANIMATION_STATE_DESC state;
+		ANIM_BLEND_STATE_DESC state;
 		state.clip = &clip;
 		state.clip = &clip;
 		state.layer = 0;
 		state.layer = 0;
 		state.loop = loop;
 		state.loop = loop;
-		state.speed = 1.0f;
 		state.weight = 1.0f;
 		state.weight = 1.0f;
 
 
 		getPose(pose, &state, 1, time);
 		getPose(pose, &state, 1, time);
 	}
 	}
 
 
-	void Skeleton::getPose(SkeletonPose& pose, const ANIMATION_STATE_DESC* states, UINT32 numStates, float time)
+	void Skeleton::getPose(SkeletonPose& pose, const ANIM_BLEND_STATE_DESC* states, UINT32 numStates, float time)
 	{
 	{
 		// TODO -Blend locally, normalize all weights to 1, layers for additive animations
 		// TODO -Blend locally, normalize all weights to 1, layers for additive animations