Browse Source

Properly transform and combine blend shapes on import

BearishSun 9 years ago
parent
commit
646d8b6b19

+ 2 - 5
Source/BansheeFBXImporter/Include/BsFBXImporter.h

@@ -116,9 +116,6 @@ namespace BansheeEngine
 		 */
 		 */
 		TAnimationCurve<Vector3> reduceKeyframes(TAnimationCurve<Vector3>& curve);
 		TAnimationCurve<Vector3> reduceKeyframes(TAnimationCurve<Vector3>& curve);
 
 
-		/** Applies a scale to all keyframe values and tangents. */
-		TAnimationCurve<Vector3> scaleKeyframes(TAnimationCurve<Vector3>& curve, float scale);
-
 		/**
 		/**
 		 * Converts all the meshes from per-index attributes to per-vertex attributes.
 		 * Converts all the meshes from per-index attributes to per-vertex attributes.
 		 *
 		 *
@@ -147,10 +144,10 @@ namespace BansheeEngine
 		 *							multiple sub-meshes (as there can't be multiple roots).
 		 *							multiple sub-meshes (as there can't be multiple roots).
 		 * @return					Skeleton containing a set of bones, or null if meshes don't contain a skeleton.
 		 * @return					Skeleton containing a set of bones, or null if meshes don't contain a skeleton.
 		 */
 		 */
-		SPtr<Skeleton> importSkeleton(const FBXImportScene& scene, bool sharedRoot);
+		SPtr<Skeleton> createSkeleton(const FBXImportScene& scene, bool sharedRoot);
 
 
 		/** Parses the scene and generates morph shapes for the imported meshes using the imported raw data. */
 		/** Parses the scene and generates morph shapes for the imported meshes using the imported raw data. */
-		SPtr<MorphShapes> importMorphShapes(const FBXImportScene& scene);
+		SPtr<MorphShapes> createMorphShapes(const FBXImportScene& scene);
 
 
 		/**	Creates an internal representation of an FBX node from an FbxNode object. */
 		/**	Creates an internal representation of an FBX node from an FbxNode object. */
 		FBXImportNode* createImportNode(FBXImportScene& scene, FbxNode* fbxNode, FBXImportNode* parent);
 		FBXImportNode* createImportNode(FBXImportScene& scene, FbxNode* fbxNode, FBXImportNode* parent);

+ 68 - 62
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -240,8 +240,8 @@ namespace BansheeEngine
 
 
 		SPtr<RendererMeshData> rendererMeshData = generateMeshData(importedScene, fbxImportOptions, subMeshes);
 		SPtr<RendererMeshData> rendererMeshData = generateMeshData(importedScene, fbxImportOptions, subMeshes);
 
 
-		skeleton = importSkeleton(importedScene, subMeshes.size() > 1);
-		morphShapes = importMorphShapes(importedScene);		
+		skeleton = createSkeleton(importedScene, subMeshes.size() > 1);
+		morphShapes = createMorphShapes(importedScene);		
 
 
 		// Import animation clips
 		// Import animation clips
 		if (!importedScene.clips.empty())
 		if (!importedScene.clips.empty())
@@ -257,7 +257,7 @@ namespace BansheeEngine
 		return rendererMeshData;
 		return rendererMeshData;
 	}
 	}
 
 
-	SPtr<Skeleton> FBXImporter::importSkeleton(const FBXImportScene& scene, bool sharedRoot)
+	SPtr<Skeleton> FBXImporter::createSkeleton(const FBXImportScene& scene, bool sharedRoot)
 	{
 	{
 		Vector<BONE_DESC> allBones;
 		Vector<BONE_DESC> allBones;
 		UnorderedMap<FBXImportNode*, UINT32> boneMap;
 		UnorderedMap<FBXImportNode*, UINT32> boneMap;
@@ -336,61 +336,85 @@ namespace BansheeEngine
 		return nullptr;
 		return nullptr;
 	}
 	}
 
 
-	SPtr<MorphShapes> FBXImporter::importMorphShapes(const FBXImportScene& scene)
+	SPtr<MorphShapes> FBXImporter::createMorphShapes(const FBXImportScene& scene)
 	{
 	{
-		SPtr<MorphShapes> morphShapes;
+		// Combine morph shapes from all sub-meshes, and transform them
+		struct RawMorphShape
+		{
+			String name;
+			Vector<MorphVertex> vertices;
+		};
+
+		UnorderedMap<String, RawMorphShape> allRawMorphShapes;
+		UINT32 totalNumVertices = 0;
+
+		// Note: Order in which we combine meshes must match the order in MeshData::combine
 		for (auto& mesh : scene.meshes)
 		for (auto& mesh : scene.meshes)
 		{
 		{
-			// Create bones
-			size_t numVertices = mesh->positions.size();
-			bool hasNormals = mesh->normals.size() == numVertices;
+			UINT32 numVertices = (UINT32)mesh->positions.size();
+			UINT32 numNormals = (UINT32)mesh->normals.size();
+			bool hasNormals = numVertices == numNormals;
 
 
-			// Create morph targets
-			Vector<SPtr<MorphShape>> allMorphShapes;
-			for (auto& fbxBlendShape : mesh->blendShapes)
+			for (auto& node : mesh->referencedBy)
 			{
 			{
-				for (auto& frame : fbxBlendShape.frames)
-				{
-					assert(frame.positions.size() == numVertices);
-
-					if (hasNormals)
-						assert(frame.normals.size() == numVertices);
+				Matrix4 worldTransform = node->worldTransform * scene.globalScale;
+				Matrix4 worldTransformIT = worldTransform.inverse();
+				worldTransformIT = worldTransformIT.transpose();
 
 
-					Vector<MorphVertex> morphVertices;
-					for (UINT32 i = 0; i < numVertices; i++)
+				// Copy & transform positions
+				for(auto& blendShape : mesh->blendShapes)
+				{
+					for(auto& blendFrame : blendShape.frames)
 					{
 					{
-						Vector3 positionDelta = frame.positions[i] - mesh->positions[i];
-						Vector3 normalDelta;
-						if (hasNormals)
-							normalDelta = frame.normals[i] - mesh->normals[i];
-						else
-							normalDelta = Vector3::ZERO;
+						RawMorphShape& shape = allRawMorphShapes[blendFrame.name];
+						shape.name = blendFrame.name;
 
 
-						if (positionDelta.squaredLength() > 0.0001f || normalDelta.squaredLength() > 0.01f)
-							morphVertices.push_back(MorphVertex(positionDelta, normalDelta, i));
+						UINT32 frameNumVertices = (UINT32)blendFrame.positions.size();
+						if (frameNumVertices == numVertices)
+						{
+							for (UINT32 i = 0; i < numVertices; i++)
+							{
+								Vector3 blendPosition = worldTransform.multiplyAffine(blendFrame.positions[i]);
+
+								Vector3 positionDelta = blendPosition - mesh->positions[i];
+								Vector3 normalDelta;
+								if (hasNormals)
+								{
+									Vector3 blendNormal = worldTransformIT.multiplyAffine(blendFrame.normals[i]);
+									normalDelta = blendNormal - mesh->normals[i];
+								}
+								else
+									normalDelta = Vector3::ZERO;
+
+								if (positionDelta.squaredLength() > 0.0001f || normalDelta.squaredLength() > 0.01f)
+									shape.vertices.push_back(MorphVertex(positionDelta, normalDelta, totalNumVertices + i));
+							}
+						}
+						else
+						{
+							LOGERR("Corrupt blend shape frame. Number of vertices doesn't match the number of mesh vertices.");
+						}
 					}
 					}
-
-					morphVertices.shrink_to_fit();
-
-					SPtr<MorphShape> shape = MorphShape::create(frame.name, morphVertices);
-					allMorphShapes.push_back(shape);
 				}
 				}
-			}
 
 
-			// Note: Morph shapes don't work if there are multiple meshes. In order to support them logic for combining
-			// morph shapes would need to be added below in, or similar to MeshData::combine.
-			if (!allMorphShapes.empty())
-			{
-				if (morphShapes == nullptr)
-					morphShapes = MorphShapes::create(allMorphShapes);
-				else
-				{
-					LOGERR("Failed importing morph shapes. Multiple sub-meshes are not supported with morph shapes.");
-					return nullptr;
-				}
+				totalNumVertices += numVertices;
 			}
 			}
 		}
 		}
 
 
+		// Create morph shape object from combined shape data
+		SPtr<MorphShapes> morphShapes;
+		Vector<SPtr<MorphShape>> allMorphShapes;
+		for (auto& entry : allRawMorphShapes)
+		{
+			entry.second.vertices.shrink_to_fit();
+
+			SPtr<MorphShape> shape = MorphShape::create(entry.second.name, entry.second.vertices);
+			allMorphShapes.push_back(shape);
+		}
+
+		if (!allMorphShapes.empty())
+			return MorphShapes::create(allMorphShapes);
+
 		return morphShapes;
 		return morphShapes;
 	}
 	}
 
 
@@ -1766,24 +1790,6 @@ namespace BansheeEngine
 		return TAnimationCurve<Vector3>(newKeyframes);
 		return TAnimationCurve<Vector3>(newKeyframes);
 	}
 	}
 
 
-	TAnimationCurve<Vector3> FBXImporter::scaleKeyframes(TAnimationCurve<Vector3>& curve, float scale)
-	{
-		UINT32 keyCount = curve.getNumKeyFrames();
-
-		Vector<TKeyframe<Vector3>> newKeyframes(keyCount);
-		for (UINT32 i = 0; i < keyCount; i++)
-		{
-			TKeyframe<Vector3> curKey = curve.getKeyFrame(i);
-			curKey.value *= scale;
-			curKey.inTangent *= scale;
-			curKey.outTangent *= scale;
-
-			newKeyframes[i] = curKey;
-		}
-
-		return TAnimationCurve<Vector3>(newKeyframes);
-	}
-	
 	template<class T>
 	template<class T>
 	void setKeyframeValues(TKeyframe<T>& keyFrame, int idx, float value, float inTangent, float outTangent)
 	void setKeyframeValues(TKeyframe<T>& keyFrame, int idx, float value, float inTangent, float outTangent)
 	{
 	{