Marko Pintera 10 лет назад
Родитель
Сommit
78764c9a30

+ 58 - 1
BansheeFBXImporter/Include/BsFBXImportData.h

@@ -86,6 +86,63 @@ namespace BansheeEngine
 		INT32 indices[FBX_IMPORT_MAX_BONE_INFLUENCES];
 	};
 
+	/**
+	 * @brief	Represents a single frame in an animation curve. Contains
+	 *			a value at a specific time as well as the in and out tangents
+	 *			at that position.
+	 */
+	struct FBXKeyFrame
+	{
+		float time;
+		float value;
+		float inTangent;
+		float outTangent;
+	};
+
+	/**
+	 * @brief	Curve with a set of key frames used for animation
+	 *			of a single value.
+	 */
+	struct FBXAnimationCurve
+	{
+		Vector<FBXKeyFrame> keyframes;
+	};
+
+	/**
+	 * @brief	Animation curves required to animate a single bone.
+	 */
+	struct FBXBoneAnimation
+	{
+		FBXImportNode* node;
+
+		FBXAnimationCurve position[3];
+		FBXAnimationCurve rotation[4];
+		FBXAnimationCurve scale[3];
+	};
+
+	/**
+	 * @brief	Animation curve required to animate a blend shape.
+	 */
+	struct FBXBlendShapeAnimation
+	{
+		String blendShape;
+		FBXAnimationCurve curve;
+	};
+
+	/**
+	 * @brief	Animation clip containing a set of bone or blend shape
+	 *			animations.
+	 */
+	struct FBXAnimationClip
+	{
+		String name;
+		float start;
+		float end;
+
+		Vector<FBXBoneAnimation> boneAnimations;
+		Vector<FBXBlendShapeAnimation> blendShapeAnimations;
+	};
+
 	/**
 	 * @brief	Imported mesh data.
 	 */
@@ -128,7 +185,7 @@ namespace BansheeEngine
 		UnorderedMap<FbxNode*, FBXImportNode*> nodeMap;
 		UnorderedMap<FbxMesh*, UINT32> meshMap;
 
-		// TODO - Store animation & bones
+		Vector<FBXAnimationClip> clips;
 	};
 
 }

+ 12 - 0
BansheeFBXImporter/Include/BsFBXImporter.h

@@ -92,6 +92,18 @@ namespace BansheeEngine
 		 */
 		void importSkin(FBXImportScene& scene, FbxSkin* skin, FBXImportMesh& mesh);
 
+		/**
+		 * @brief	Imports all bone and blend shape animations from the FBX.
+		 */
+		void importAnimations(FbxScene* scene, bool importBlendShapeAnimations, FBXImportScene& importScene);
+
+		/**
+		 * @brief	Imports all animations for the specified animation layer and outputs them in the provided clip.
+		 *			Child nodes will be iterated recursively.
+		 */
+		void importAnimations(FbxAnimLayer* layer, FbxNode* node, bool importBlendShapeAnimations, 
+			FBXAnimationClip& clip, FBXImportScene& importScene);
+
 		/**
 		 * @brief	Converts all the meshes from per-index attributes to per-vertex attributes.
 		 *

+ 78 - 2
BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -133,6 +133,9 @@ namespace BansheeEngine
 		if (fbxImportOptions.importSkin)
 			importSkin(importedScene);
 
+		if (fbxImportOptions.importAnimation)
+			importAnimations(fbxScene, fbxImportOptions.importBlendShapes, importedScene);
+
 		splitMeshVertices(importedScene);
 		
 		Vector<SubMesh> subMeshes;
@@ -288,8 +291,6 @@ namespace BansheeEngine
 				todo.push(childNode);
 			}
 		}
-
-		// TODO - Parse animation
 	}
 
 	FBXImportNode* FBXImporter::createImportNode(FBXImportScene& scene, FbxNode* fbxNode, FBXImportNode* parent)
@@ -1050,4 +1051,79 @@ namespace BansheeEngine
 				influences[i].weights[j] *= invSum;
 		}
 	}
+
+	void FBXImporter::importAnimations(FbxScene* scene, bool importBlendShapeAnimations, FBXImportScene& importScene)
+	{
+		FbxNode* root = scene->GetRootNode();
+
+		UINT32 numAnimStacks = (UINT32)scene->GetSrcObjectCount<FbxAnimStack>();
+		for (UINT32 i = 0; i < numAnimStacks; i++)
+		{
+			FbxAnimStack* animStack = scene->GetSrcObject<FbxAnimStack>(i);
+
+			importScene.clips.push_back(FBXAnimationClip());
+			FBXAnimationClip& clip = importScene.clips.back();
+			clip.name = animStack->GetName();
+
+			FbxTimeSpan timeSpan = animStack->GetLocalTimeSpan();
+			clip.start = (float)timeSpan.GetStart().GetSecondDouble();
+			clip.end = (float)timeSpan.GetStop().GetSecondDouble();
+
+			UINT32 layerCount = animStack->GetMemberCount<FbxAnimLayer>();
+			if (layerCount > 1)
+			{
+				FbxAnimEvaluator* evaluator = scene->GetAnimationEvaluator();
+
+				FbxTime startTime;
+				startTime.SetSecondDouble(clip.start);
+
+				FbxTime endTime;
+				endTime.SetSecondDouble(clip.end);
+
+				FbxTime::EMode timeMode = scene->GetGlobalSettings().GetTimeMode();
+				FbxTime sampleRate;
+				sampleRate.SetSecondDouble(1.0f / FbxTime::GetFrameRate(timeMode));
+
+				if (!animStack->BakeLayers(evaluator, startTime, endTime, sampleRate))
+					continue;
+
+				layerCount = animStack->GetMemberCount<FbxAnimLayer>();
+			}
+
+			if (layerCount == 1)
+			{
+				FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(0);
+
+				importAnimations(animLayer, root, importBlendShapeAnimations, clip, importScene);
+			}
+		}
+	}
+
+	void FBXImporter::importAnimations(FbxAnimLayer* layer, FbxNode* node, bool importBlendShapeAnimations, 
+		FBXAnimationClip& clip, FBXImportScene& importScene)
+	{
+		FbxAnimCurve* translation[3];
+		translation[0] = node->LclTranslation.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_X);
+		translation[1] = node->LclTranslation.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_Y);
+		translation[2] = node->LclTranslation.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_Z);
+
+		FbxAnimCurve* rotation[3];
+		rotation[0] = node->LclRotation.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_X);
+		rotation[1] = node->LclRotation.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_Y);
+		rotation[2] = node->LclRotation.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_Z);
+
+		FbxAnimCurve* scale[3];
+		scale[0] = node->LclScaling.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_X);
+		scale[1] = node->LclScaling.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_Y);
+		scale[2] = node->LclScaling.GetCurve(layer, FBXSDK_CURVENODE_COMPONENT_Z);
+
+		// TODO
+
+		UINT32 childCount = (UINT32)node->GetChildCount();
+		for (UINT32 i = 0; i < childCount; i++)
+		{
+			FbxNode* child = node->GetChild(i);
+			importAnimations(layer, child, importBlendShapeAnimations, clip, importScene);
+		}
+	}
 }