Browse Source

Animation curve splitting added to FBX importer

BearishSun 9 years ago
parent
commit
cb9202e68d

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

@@ -69,6 +69,19 @@ namespace BansheeEngine
 		 */
 		TAnimationCurve<T> split(float start, float end);
 
+		/** 
+		 * Converts a normal curve into an additive curve. It is assumed the first keyframe in the curve is the reference
+		 * key from which to generate the additive curve. Such curves can then be added on top of a curve containing
+		 * reference keys.
+		 */
+		void makeAdditive();
+
+		/** Returns the total number of key-frames in the curve. */
+		UINT32 getNumKeyFrames() const { return (UINT32)mKeyframes.size(); }
+
+		/** Returns a keyframe at the specified index. */
+		const TKeyframe<T>& getKeyFrame(UINT32 idx) const { return mKeyframes[idx]; }
+
 	private:
 		friend struct RTTIPlainType<TAnimationCurve<T>>;
 

+ 8 - 3
Source/BansheeCore/Include/BsMeshImportOptions.h

@@ -22,10 +22,12 @@ namespace BansheeEngine
 	/** Contains information about a piece of imported animation that will be used for generating its own AnimationClip. */
 	struct AnimationSplitInfo : IReflectable
 	{
+		AnimationSplitInfo() { }
+
 		String name;
-		UINT32 startFrame;
-		UINT32 endFrame;
-		bool isAdditive;
+		UINT32 startFrame = 0;
+		UINT32 endFrame = 0;
+		bool isAdditive = false;
 
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
@@ -114,6 +116,9 @@ namespace BansheeEngine
 		/** Removes an animation split info at the specified index. */
 		void removeAnimationClipSplit(UINT32 idx) { mAnimationSplits.erase(mAnimationSplits.begin() + idx); }
 
+		/** Returns a copy of the animation splits array. */
+		Vector<AnimationSplitInfo> getAnimationClipSplits() const { return mAnimationSplits; }
+
 	private:
 		bool mCPUReadable;
 		bool mImportNormals;

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

@@ -478,6 +478,12 @@ namespace BansheeEngine
 		return TAnimationCurve<T>(keyFrames);
 	}
 
+	template <class T>
+	void TAnimationCurve<T>::makeAdditive()
+	{
+		
+	}
+
 	template class TAnimationCurve<Vector3>;
 	template class TAnimationCurve<Quaternion>;
 	template class TAnimationCurve<float>;

+ 4 - 1
Source/BansheeFBXImporter/Include/BsFBXImporter.h

@@ -15,6 +15,8 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
+	struct AnimationSplitInfo;
+
 	/** Importer implementation that handles FBX/OBJ/DAE/3DS file import by using the FBX SDK. */
 	class BS_FBX_EXPORT FBXImporter : public SpecificImporter
 	{
@@ -99,7 +101,8 @@ namespace BansheeEngine
 		void importCurve(FbxAnimCurve* fbxCurve, FBXImportOptions& importOptions, FBXAnimationCurve& curve, float start, float end);
 
 		/** Converts FBX animation clips into engine-ready animation curve format. */
-		void convertAnimations(const Vector<FBXAnimationClip>& clips, UnorderedMap<String, SPtr<AnimationCurves>>& output);
+		void convertAnimations(const Vector<FBXAnimationClip>& clips, const Vector<AnimationSplitInfo>& splits, 
+			UnorderedMap<String, SPtr<AnimationCurves>>& output);
 
 		/**	Converts a set of curves containing rotation in euler angles into a set of curves using	quaternion rotation. */
 		void eulerToQuaternionCurves(FBXAnimationCurve(&eulerCurves)[3], FBXAnimationCurve(&quatCurves)[4]);

+ 73 - 4
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -225,7 +225,10 @@ namespace BansheeEngine
 
 		// Import animation clips
 		if (!importedScene.clips.empty())
-			convertAnimations(importedScene.clips, animation);
+		{
+			Vector<AnimationSplitInfo> splits = meshImportOptions->getAnimationClipSplits();
+			convertAnimations(importedScene.clips, splits, animation);
+		}
 
 		// TODO - Later: Optimize mesh: Remove bad and degenerate polygons, weld nearby vertices, optimize for vertex cache
 
@@ -419,14 +422,14 @@ namespace BansheeEngine
 		scene.meshes = splitMeshes;
 	}
 
-	void FBXImporter::convertAnimations(const Vector<FBXAnimationClip>& clips, 
+	void FBXImporter::convertAnimations(const Vector<FBXAnimationClip>& clips, const Vector<AnimationSplitInfo>& splits,
 		UnorderedMap<String, SPtr<AnimationCurves>>& output)
 	{
+		bool isFirstClip = true;
 		for (auto& clip : clips)
 		{
 			SPtr<AnimationCurves> curves = bs_shared_ptr_new<AnimationCurves>();
-			output.insert(std::make_pair(clip.name, curves));
-
+			
 			for (auto& bone : clip.boneAnimations)
 			{
 				// Translation curves
@@ -503,6 +506,72 @@ namespace BansheeEngine
 					curves->scale.push_back({ bone.node->name, keyFrames });
 				}
 			}
+
+			// See if any splits are required. We only split the first clip as it is assumed if FBX has multiple clips the
+			// user has the ability to split them externally.
+			if(isFirstClip && !splits.empty())
+			{
+				for(auto& split : splits)
+				{
+					SPtr<AnimationCurves> splitClipCurve = bs_shared_ptr_new<AnimationCurves>();
+
+					auto splitCurves = [&](auto& inCurves, auto& outCurves)
+					{
+						UINT32 numCurves = inCurves.size();
+						outCurves.resize(numCurves);
+
+						for (UINT32 i = 0; i < numCurves; i++)
+						{
+							TAnimationCurve<Vector3>& animCurve = inCurves[i].curve;
+							outCurves[i].name = inCurves[i].name;
+
+							UINT32 numFrames = animCurve.getNumKeyFrames();
+							if (numFrames == 0)
+								continue;
+
+							UINT32 lastFrame = numFrames - 1;
+							float startTime = animCurve.getKeyFrame(std::min(split.startFrame, lastFrame)).time;
+							float endTime = animCurve.getKeyFrame(std::min(split.endFrame, lastFrame)).time;
+
+							outCurves[i].curve = inCurves->position[i].curve.split(startTime, endTime);
+
+							if (split.isAdditive)
+								outCurves[i].curve->makeAdditive();
+						}
+					};
+
+					splitCurves(curves->position, splitClipCurve->position);
+					splitCurves(curves->rotation, splitClipCurve->rotation);
+					splitCurves(curves->scale, splitClipCurve->scale);
+					splitCurves(curves->generic, splitClipCurve->generic);
+
+					// Search for a unique name
+					String name = split.name;
+					UINT32 attemptIdx = 0;
+					while (output.find(name) != output.end())
+					{
+						name = clip.name + "_" + toString(attemptIdx);
+						attemptIdx++;
+					}
+
+					output.insert(std::make_pair(name, splitClipCurve));
+				}
+			}
+			else
+			{
+				// Search for a unique name
+				String name = clip.name;
+				UINT32 attemptIdx = 0;
+				while(output.find(name) != output.end())
+				{
+					name = clip.name + "_" + toString(attemptIdx);
+					attemptIdx++;
+				}
+
+				output.insert(std::make_pair(name, curves));
+			}
+
+			isFirstClip = false;
 		}
 	}