Procházet zdrojové kódy

Animation clip now stores sample rate so animation editor can properly set it on load
Fixed a crash when deselecting an object selected in animation editor window

BearishSun před 9 roky
rodič
revize
9d909059b1

+ 22 - 3
Source/BansheeCore/Include/BsAnimationClip.h

@@ -151,6 +151,22 @@ namespace BansheeEngine
 		/** Returns the length of the animation clip, in seconds. */
 		float getLength() const { return mLength; }
 
+		/** 
+		 * Returns the number of samples per second the animation clip curves were sampled at.
+		 *
+		 * @note	This value is not used by the animation clip or curves directly since unevenly spaced keyframes are
+		 *			supported. But it can be of value when determining the original sample rate of an imported animation
+		 *			or similar.
+		 */
+		UINT32 getSampleRate() const { return mSampleRate; }
+
+		/** 
+		 * Sets the number of samples per second the animation clip curves were sampled at.
+		 *
+		 * @see	getSampleRate()
+		 */
+		void setSampleRate(UINT32 sampleRate) { mSampleRate = sampleRate; }
+
 		/** 
 		 * 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.
@@ -169,8 +185,10 @@ namespace BansheeEngine
 		 * @param[in]	curves		Curves to initialize the animation with.
 		 * @param[in]	isAdditive	Determines does the clip contain additive curve data. This will change the behaviour
 		 *							how is the clip blended with other animations.
+		 * @param[in]	sampleRate	If animation uses evenly spaced keyframes, number of samples per second. Not relevant
+		 *							if keyframes are unevenly spaced.
 		 */
-		static HAnimationClip create(const SPtr<AnimationCurves>& curves, bool isAdditive = false);
+		static HAnimationClip create(const SPtr<AnimationCurves>& curves, bool isAdditive = false, UINT32 sampleRate = 1);
 
 	public: // ***** INTERNAL ******
 		/** @name Internal
@@ -178,13 +196,13 @@ namespace BansheeEngine
 		 */
 
 		/** Creates a new AnimationClip without initializing it. Use create() for normal use. */
-		static SPtr<AnimationClip> _createPtr(const SPtr<AnimationCurves>& curves, bool isAdditive = false);
+		static SPtr<AnimationClip> _createPtr(const SPtr<AnimationCurves>& curves, bool isAdditive = false, UINT32 sampleRate = 1);
 
 		/** @} */
 
 	protected:
 		AnimationClip();
-		AnimationClip(const SPtr<AnimationCurves>& curves, bool isAdditive);
+		AnimationClip(const SPtr<AnimationCurves>& curves, bool isAdditive, UINT32 sampleRate);
 
 		/** @copydoc Resource::initialize() */
 		void initialize() override;
@@ -212,6 +230,7 @@ namespace BansheeEngine
 		Vector<AnimationEvent> mEvents;
 		bool mIsAdditive;
 		float mLength;
+		UINT32 mSampleRate;
 
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/

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

@@ -74,6 +74,7 @@ namespace BansheeEngine
 			BS_RTTI_MEMBER_PLAIN(mIsAdditive, 4)
 			BS_RTTI_MEMBER_PLAIN(mLength, 5)
 			BS_RTTI_MEMBER_PLAIN(mEvents, 6)
+			BS_RTTI_MEMBER_PLAIN(mSampleRate, 7)
 		BS_END_RTTI_MEMBERS
 	public:
 		AnimationClipRTTI()

+ 7 - 6
Source/BansheeCore/Source/BsAnimationClip.cpp

@@ -82,12 +82,13 @@ namespace BansheeEngine
 
 	AnimationClip::AnimationClip()
 		: Resource(false), mVersion(0), mCurves(bs_shared_ptr_new<AnimationCurves>()), mIsAdditive(false), mLength(0.0f)
+		, mSampleRate(1)
 	{
 
 	}
 
-	AnimationClip::AnimationClip(const SPtr<AnimationCurves>& curves, bool isAdditive)
-		: Resource(false), mVersion(0), mCurves(curves), mIsAdditive(isAdditive), mLength(0.0f)
+	AnimationClip::AnimationClip(const SPtr<AnimationCurves>& curves, bool isAdditive, UINT32 sampleRate)
+		: Resource(false), mVersion(0), mCurves(curves), mIsAdditive(isAdditive), mLength(0.0f), mSampleRate(sampleRate)
 	{
 		buildNameMapping();
 		calculateLength();
@@ -98,9 +99,9 @@ namespace BansheeEngine
 		return static_resource_cast<AnimationClip>(gResources()._createResourceHandle(_createPtr(nullptr, isAdditive)));
 	}
 
-	HAnimationClip AnimationClip::create(const SPtr<AnimationCurves>& curves, bool isAdditive)
+	HAnimationClip AnimationClip::create(const SPtr<AnimationCurves>& curves, bool isAdditive, UINT32 sampleRate)
 	{
-		return static_resource_cast<AnimationClip>(gResources()._createResourceHandle(_createPtr(curves, isAdditive)));
+		return static_resource_cast<AnimationClip>(gResources()._createResourceHandle(_createPtr(curves, isAdditive, sampleRate)));
 	}
 
 	SPtr<AnimationClip> AnimationClip::createEmpty()
@@ -113,9 +114,9 @@ namespace BansheeEngine
 		return newClip;
 	}
 
-	SPtr<AnimationClip> AnimationClip::_createPtr(const SPtr<AnimationCurves>& curves, bool isAdditive)
+	SPtr<AnimationClip> AnimationClip::_createPtr(const SPtr<AnimationCurves>& curves, bool isAdditive, UINT32 sampleRate)
 	{
-		AnimationClip* rawPtr = new (bs_alloc<AnimationClip>()) AnimationClip(curves, isAdditive);
+		AnimationClip* rawPtr = new (bs_alloc<AnimationClip>()) AnimationClip(curves, isAdditive, sampleRate);
 
 		SPtr<AnimationClip> newClip = bs_core_ptr<AnimationClip>(rawPtr);
 		newClip->_setThisPtr(newClip);

+ 4 - 2
Source/BansheeFBXImporter/Include/BsFBXImportData.h

@@ -108,6 +108,7 @@ namespace BansheeEngine
 		String name;
 		float start;
 		float end;
+		UINT32 sampleRate;
 
 		Vector<FBXBoneAnimation> boneAnimations;
 		Vector<FBXBlendShapeAnimation> blendShapeAnimations;
@@ -116,12 +117,13 @@ namespace BansheeEngine
 	/** All information required for creating an animation clip. */
 	struct FBXAnimationClipData
 	{
-		FBXAnimationClipData(const String& name, bool isAdditive, const SPtr<AnimationCurves>& curves)
-			:name(name), isAdditive(isAdditive), curves(curves)
+		FBXAnimationClipData(const String& name, bool isAdditive, UINT32 sampleRate, const SPtr<AnimationCurves>& curves)
+			:name(name), isAdditive(isAdditive), sampleRate(sampleRate), curves(curves)
 		{ }
 
 		String name;
 		bool isAdditive;
+		UINT32 sampleRate;
 		SPtr<AnimationCurves> curves;
 	};
 

+ 5 - 6
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -178,7 +178,7 @@ namespace BansheeEngine
 			Vector<ImportedAnimationEvents> events = meshImportOptions->getAnimationEvents();
 			for(auto& entry : animationClips)
 			{
-				SPtr<AnimationClip> clip = AnimationClip::_createPtr(entry.curves, entry.isAdditive);
+				SPtr<AnimationClip> clip = AnimationClip::_createPtr(entry.curves, entry.isAdditive, entry.sampleRate);
 				
 				for(auto& eventsEntry : events)
 				{
@@ -505,7 +505,7 @@ namespace BansheeEngine
 					}
 
 					names.insert(name);
-					output.push_back(FBXAnimationClipData(name, split.isAdditive, splitClipCurve));
+					output.push_back(FBXAnimationClipData(name, split.isAdditive, clip.sampleRate, splitClipCurve));
 				}
 			}
 			else
@@ -520,7 +520,7 @@ namespace BansheeEngine
 				}
 
 				names.insert(name);
-				output.push_back(FBXAnimationClipData(name, false, curves));
+				output.push_back(FBXAnimationClipData(name, false, clip.sampleRate, curves));
 			}
 
 			isFirstClip = false;
@@ -1423,6 +1423,8 @@ namespace BansheeEngine
 			clip.start = (float)timeSpan.GetStart().GetSecondDouble();
 			clip.end = (float)timeSpan.GetStop().GetSecondDouble();
 
+			clip.sampleRate = (UINT32)FbxTime::GetFrameRate(scene->GetGlobalSettings().GetTimeMode());
+
 			UINT32 layerCount = animStack->GetMemberCount<FbxAnimLayer>();
 			if (layerCount > 1)
 			{
@@ -1506,9 +1508,6 @@ namespace BansheeEngine
 				eulerAnimation = reduceKeyframes(eulerAnimation);
 			}
 
-			//if (importOptions.importScale != 1.0f)
-			//	boneAnim.translation = scaleKeyframes(boneAnim.translation, importOptions.importScale);
-
 			boneAnim.rotation = AnimationUtility::eulerToQuaternionCurve(eulerAnimation);
 		}
 

+ 3 - 0
Source/MBansheeEditor/Windows/Animation/EditorAnimInfo.cs

@@ -62,6 +62,7 @@ namespace BansheeEditor
     {
         public AnimationClip clip;
         public bool isImported;
+        public int sampleRate;
         public Dictionary<string, FieldAnimCurves> curves = new Dictionary<string, FieldAnimCurves>();
         public AnimationEvent[] events = new AnimationEvent[0];
 
@@ -76,6 +77,7 @@ namespace BansheeEditor
             EditorAnimClipInfo clipInfo = new EditorAnimClipInfo();
             clipInfo.clip = clip;
             clipInfo.isImported = IsClipImported(clip);
+            clipInfo.sampleRate = clip.SampleRate;
 
             AnimationCurves clipCurves = clip.Curves;
             EditorAnimClipTangents editorCurveData = null;
@@ -386,6 +388,7 @@ namespace BansheeEditor
 
                 clip.Curves = newClipCurves;
                 clip.Events = events;
+                clip.SampleRate = sampleRate;
 
                 string resourcePath = ProjectLibrary.GetPath(clip);
                 ProjectLibrary.Save(clip);

+ 0 - 3
Source/MBansheeEditor/Windows/Animation/GUIAnimFieldDisplay.cs

@@ -70,9 +70,6 @@ namespace BansheeEditor
 
         public void SetDisplayValues(GUIAnimFieldPathValue[] values)
         {
-            for(int i = 0; i < values.Length; i++)
-                Debug.Log(i + ". " + values[i].value);
-
             for (int i = 0; i < fields.Length; i++)
             {
                 string path = fields[i].Path;

+ 5 - 1
Source/MBansheeEditor/Windows/AnimationWindow.cs

@@ -118,6 +118,8 @@ namespace BansheeEditor
         private void RebuildGUI()
         {
             GUI.Clear();
+            guiCurveEditor = null;
+            guiFieldDisplay = null;
 
             if (selectedSO == null)
             {
@@ -565,6 +567,7 @@ namespace BansheeEditor
             guiCurveEditor.DisableCurveEdit = clipInfo.isImported;
 
             SetCurrentFrame(0);
+            FPS = clipInfo.sampleRate;
         }
 
         private void UpdateSelectedSO(bool force)
@@ -610,7 +613,8 @@ namespace BansheeEditor
                 if(clipInfo == null)
                     clipInfo = new EditorAnimClipInfo();
 
-                UpdateDisplayedCurves(true);
+                if(selectedSO != null)
+                    UpdateDisplayedCurves(true);
             }
         }
 

+ 17 - 0
Source/MBansheeEngine/Animation/AnimationClip.cs

@@ -35,6 +35,17 @@ namespace BansheeEngine
             get { return Internal_GetLength(mCachedPtr); }
         }
 
+        /// <summary>
+        /// Returns the number of samples per second the animation clip curves were sampled at. This value is not used by
+        /// the animation clip or curves directly since unevenly spaced keyframes are supported. But it can be of value when
+        /// determining the original sample rate of an imported animation or similar.
+        /// </summary>
+        public int SampleRate
+        {
+            get { return Internal_GetSampleRate(mCachedPtr); }
+            set { Internal_SetSampleRate(mCachedPtr, value); }
+        }
+
         /// <summary>
         /// A set of all curves stored in the animation clip.
         /// </summary>
@@ -70,6 +81,12 @@ namespace BansheeEngine
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern float Internal_GetLength(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetSampleRate(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetSampleRate(IntPtr thisPtr, int sampleRate);
     }
 
     /// <summary>

+ 2 - 0
Source/SBansheeEngine/Include/BsScriptAnimationClip.h

@@ -35,6 +35,8 @@ namespace BansheeEngine
 		static MonoArray* internal_GetAnimationEvents(ScriptAnimationClip* thisPtr);
 		static void internal_SetAnimationEvents(ScriptAnimationClip* thisPtr, MonoArray* events);
 		static float internal_GetLength(ScriptAnimationClip* thisPtr);
+		static UINT32 internal_GetSampleRate(ScriptAnimationClip* thisPtr);
+		static void internal_SetSampleRate(ScriptAnimationClip* thisPtr, UINT32 sampleRate);
 	};
 
 	/**	Interop class between C++ & CLR for AnimationEvent. */

+ 12 - 0
Source/SBansheeEngine/Source/BsScriptAnimationClip.cpp

@@ -22,6 +22,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetAnimationEvents", &ScriptAnimationClip::internal_GetAnimationEvents);
 		metaData.scriptClass->addInternalCall("Internal_SetAnimationEvents", &ScriptAnimationClip::internal_SetAnimationEvents);
 		metaData.scriptClass->addInternalCall("Internal_GetLength", &ScriptAnimationClip::internal_GetLength);
+		metaData.scriptClass->addInternalCall("Internal_GetSampleRate", &ScriptAnimationClip::internal_GetSampleRate);
+		metaData.scriptClass->addInternalCall("Internal_SetSampleRate", &ScriptAnimationClip::internal_SetSampleRate);
 	}
 
 	MonoObject* ScriptAnimationClip::createInstance()
@@ -89,6 +91,16 @@ namespace BansheeEngine
 		return thisPtr->getHandle()->getLength();
 	}
 
+	UINT32 ScriptAnimationClip::internal_GetSampleRate(ScriptAnimationClip* thisPtr)
+	{
+		return thisPtr->getHandle()->getSampleRate();
+	}
+
+	void ScriptAnimationClip::internal_SetSampleRate(ScriptAnimationClip* thisPtr, UINT32 sampleRate)
+	{
+		thisPtr->getHandle()->setSampleRate(sampleRate);
+	}
+
 	MonoField* ScriptAnimationEvent::sNameField = nullptr;
 	MonoField* ScriptAnimationEvent::sTimeField = nullptr;