Sfoglia il codice sorgente

Added morph shapes to Mesh
Refactored mesh creation so it's neater

BearishSun 9 anni fa
parent
commit
92aca46056

+ 1 - 1
Documentation/Manuals/Native/style.md

@@ -40,7 +40,7 @@ Guidelines
   - Always put a space after a semicolon (e.g. for(int i = 0; i < 5; i++)).
   - Always put a space between operators (e.g. 5 + 2).
   - Separate meaningful parts of the code in a method with empty lines
-  - Always but a blank line after a block {}, and in general try to separate relevant pieces of code with "paragraphs" separated by blank lines
+  - Always but a blank line after a block {}
   - No single line should be longer than column 124 (set up a guideline in your editor)
  - If method doesn't modify data, always mark it as const (getters especially)
  - Always pass non-primitive parameters by reference unless `null` is a valid value in which case use a pointer

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

@@ -375,6 +375,7 @@ namespace BansheeEngine
 	class MaterialParamsCore;
 	class Camera;
 	class CameraCore;
+	class MorphShapes;
 	// Asset import
 	class SpecificImporter;
 	class Importer;

+ 73 - 108
Source/BansheeCore/Include/BsMesh.h

@@ -16,6 +16,48 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
+	/** Descriptor object used for creation of a new Mesh object. */
+	struct BS_CORE_EXPORT MESH_DESC
+	{
+		MESH_DESC() { }
+
+		/** Number of vertices in the mesh. */
+		UINT32 numVertices = 0; 
+
+		/** Number of indices in the mesh. */
+		UINT32 numIndices = 0; 
+
+		/** 
+		 * Vertex description structure that describes how are vertices organized in the vertex buffer. When binding a mesh
+		 * to the pipeline you must ensure vertex description at least partially matches the input description of the
+		 * currently bound vertex GPU program.
+		 */
+		SPtr<VertexDataDesc> vertexDesc;
+
+		/** 
+		 * Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered. Sub-meshes may be
+		 * rendered independently.
+		 */
+		Vector<SubMesh> subMeshes;
+
+		/** Optimizes performance depending on planned usage of the mesh. */
+		INT32 usage = MU_STATIC; 
+
+		/** 
+		 * Size of indices, use smaller size for better performance, however be careful not to go over the number of 
+		 * vertices limited by the size.
+		 */
+		IndexType indexType = IT_32BIT;
+
+		/** Optional skeleton that can be used for skeletal animation of the mesh. */
+		SPtr<Skeleton> skeleton;
+
+		/** Optional set of morph shapes that can be used for per-vertex animation of the mesh. */
+		SPtr<MorphShapes> morphShapes;
+
+		static MESH_DESC DEFAULT;
+	};
+
 	/**
 	 * Primary class for holding geometry. Stores data in the form of a vertex buffers and optionally index buffer, which 
 	 * may be bound to the pipeline for drawing. May contain multiple sub-meshes.
@@ -97,16 +139,8 @@ namespace BansheeEngine
 	protected:
 		friend class MeshManager;
 
-		Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-			int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton);
-
-		Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-			const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton);
-
-		Mesh(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton);
-
-		Mesh(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, 
-			const SPtr<Skeleton>& skeleton);
+		Mesh(const MESH_DESC& desc);
+		Mesh(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc);
 
 		/**	Updates bounds by calculating them from the vertices in the provided mesh data object. */
 		void updateBounds(const MeshData& meshData);
@@ -130,6 +164,7 @@ namespace BansheeEngine
 		int mUsage;
 		IndexType mIndexType;
 		SPtr<Skeleton> mSkeleton; // Immutable
+		SPtr<MorphShapes> mMorphShapes; // Immutable
 
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
@@ -161,93 +196,52 @@ namespace BansheeEngine
 		 *								option is a triangle list, where three indices represent a single triangle.
 		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not to
 		 *								go over the number of vertices limited by the size.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
-		static HMesh create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
+		static HMesh create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
+			int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
 
 		/**
-		 * Creates a new empty mesh. Created mesh will have specified sub-meshes you may render independently.
+		 * Creates a new empty mesh. 
 		 *
-		 * @param[in]	numVertices		Number of vertices in the mesh.
-		 * @param[in]	numIndices		Number of indices in the mesh. 
-		 * @param[in]	vertexDesc		Vertex description structure that describes how are vertices organized in the
-		 *								vertex buffer. When binding a mesh to the pipeline you must ensure vertex 
-		 *								description at least partially matches the input description of the currently bound
-		 *								vertex GPU program.
-		 * @param[in]	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes 
-		 *								rendered. Sub-meshes may be rendered independently.
-		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
-		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not to
-		 *								go over the number of vertices limited by the size.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
+		 * @param[in]	desc	Descriptor containing the properties of the mesh to create.
 		 */
-		static HMesh create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, const Vector<SubMesh>& subMeshes,
-			int usage = MU_STATIC, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
+		static HMesh create(const MESH_DESC& desc);
 
 		/**
 		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
 		 * by the mesh data exactly. Mesh will have no sub-meshes.
 		 *
 		 * @param[in]	initialData		Vertex and index data to initialize the mesh with.
-		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
-		 * @param[in]	drawOp			Determines how should the provided indices be interpreted by the pipeline. Default 
-		 *								option is a triangle strip, where three indices represent a single triangle.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
+		 * @param[in]	desc			Descriptor containing the properties of the mesh to create. Vertex and index count,
+		 *								vertex descriptor and index type properties are ignored and are read from provided
+		 *								mesh data instead.
 		 */
-		static HMesh create(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, const SPtr<Skeleton>& skeleton = nullptr);
-
-		/**
-		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described by
-		 * the mesh data exactly. Mesh will have specified the sub-meshes.
-		 *
-		 * @param[in]	initialData		Vertex and index data used for initializing the mesh. 
-		 * @param[in]	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes 
-		 *								rendered. Sub-meshes may be rendered independently.
-		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
-		 */
-		static HMesh create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC, 
-			const SPtr<Skeleton>& skeleton = nullptr);
+		static HMesh create(const SPtr<MeshData>& initialData, const MESH_DESC& desc = MESH_DESC::DEFAULT);
 
 		/** @name Internal
 		 *  @{
 		 */
 
 		/**
-		 * @copydoc	create(UINT32, UINT32, const SPtr<VertexDataDesc>&, int, DrawOperationType, IndexType, const SPtr<Skeleton>&)
-		 *
-		 * @note	Internal method. Use create() for normal use.
-		 */
-		static SPtr<Mesh> _createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-			int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, 
-			const SPtr<Skeleton>& skeleton = nullptr);
-
-		/**
-		 * @copydoc	create(UINT32, UINT32, const SPtr<VertexDataDesc>&, const Vector<SubMesh>&, int, IndexType, const SPtr<Skeleton>&)
+		 * @copydoc	create(const MESH_DESC&)
 		 *
 		 * @note	Internal method. Use create() for normal use.
 		 */
-		static SPtr<Mesh> _createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-			const Vector<SubMesh>& subMeshes, int usage = MU_STATIC, IndexType indexType = IT_32BIT, 
-			const SPtr<Skeleton>& skeleton = nullptr);
+		static SPtr<Mesh> _createPtr(const MESH_DESC& desc);
 
 		/**
 		 * @copydoc	create(const SPtr<MeshData>&, int, DrawOperationType, const SPtr<Skeleton>&)
 		 *
 		 * @note	Internal method. Use create() for normal use.
 		 */
-		static SPtr<Mesh> _createPtr(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, const SPtr<Skeleton>& skeleton = nullptr);
+		static SPtr<Mesh> _createPtr(const SPtr<MeshData>& initialData, const MESH_DESC& desc = MESH_DESC::DEFAULT);
 
 		/**
-		 * @copydoc	create(const SPtr<MeshData>&, const Vector<SubMesh>&, int, const SPtr<Skeleton>&)
-		 *
-		 * @note	Internal method. Use create() for normal use.
+		 * Creates a new empty and uninitialized mesh. You will need to manually initialize the mesh before using it.
+		 *	
+		 * @note	This should only be used for special cases like serialization and is not meant for normal use.
 		 */
-		static SPtr<Mesh> _createPtr(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes,
-			int usage = MU_STATIC, const SPtr<Skeleton>& skeleton = nullptr);
+		static SPtr<Mesh> createEmpty();
 
 		/** @} */
 	};
@@ -266,9 +260,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT MeshCore : public MeshCoreBase
 	{
 	public:
-		MeshCore(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-			const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton,
-			const SPtr<MeshData>& initialMeshData);
+		MeshCore(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc);
 
 		~MeshCore();
 
@@ -324,55 +316,27 @@ namespace BansheeEngine
 		 *								option is a triangle list, where three indices represent a single triangle.
 		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not to
 		 *								go over the number of vertices limited by the size.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
-		static SPtr<MeshCore> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
+		static SPtr<MeshCore> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
+			int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
 
 		/**
-		 * Creates a new empty mesh. Created mesh will have specified sub-meshes you may render independently.
+		 * Creates a new empty mesh. 
 		 *
-		 * @param[in]	numVertices		Number of vertices in the mesh.
-		 * @param[in]	numIndices		Number of indices in the mesh. 
-		 * @param[in]	vertexDesc		Vertex description structure that describes how are vertices organized in the
-		 *								vertex buffer. When binding a mesh to the pipeline you must ensure vertex 
-		 *								description at least partially matches the input description of the currently bound
-		 *								vertex GPU program.
-		 * @param[in]	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes 
-		 *								rendered. Sub-meshes may be rendered independently.
-		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
-		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not 
-		 *								to go over the number of vertices limited by the size.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
+		 * @param[in]	desc	Descriptor containing the properties of the mesh to create.
 		 */
-		static SPtr<MeshCore> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, const Vector<SubMesh>& subMeshes,
-			int usage = MU_STATIC, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
+		static SPtr<MeshCore> create(const MESH_DESC& desc);
 
 		/**
 		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
 		 * by the mesh data exactly. Mesh will have no sub-meshes.
 		 *
 		 * @param[in]	initialData		Vertex and index data to initialize the mesh with.
-		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
-		 * @param[in]	drawOp			Determines how should the provided indices be interpreted by the pipeline. Default 
-		 *								option is a triangle strip, where three indices represent a single triangle.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
+		 * @param[in]	desc			Descriptor containing the properties of the mesh to create. Vertex and index count,
+		 *								vertex descriptor and index type properties are ignored and are read from provided
+		 *								mesh data instead.
 		 */
-		static SPtr<MeshCore> create(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, const SPtr<Skeleton>& skeleton = nullptr);
-
-		/**
-		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
-		 * by the mesh data exactly. Mesh will have specified the sub-meshes.
-		 *
-		 * @param[in]	initialData		Vertex and index data used for initializing the mesh. 
-		 * @param[in]	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes 
-		 *								rendered. Sub-meshes may be rendered independently.
-		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
-		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
-		 */
-		static SPtr<MeshCore> create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, 
-			int usage = MU_STATIC, const SPtr<Skeleton>& skeleton = nullptr);
+		static SPtr<MeshCore> create(const SPtr<MeshData>& initialData, const MESH_DESC& desc = MESH_DESC::DEFAULT);
 
 	protected:
 		friend class Mesh;
@@ -386,8 +350,9 @@ namespace BansheeEngine
 		SPtr<VertexDataDesc> mVertexDesc;
 		int mUsage;
 		IndexType mIndexType;
-		SPtr<Skeleton> mSkeleton;
 		SPtr<MeshData> mTempInitialMeshData;
+		SPtr<Skeleton> mSkeleton; // Immutable
+		SPtr<MorphShapes> mMorphShapes; // Immutable
 	};
 
 	/** @} */

+ 1 - 24
Source/BansheeCore/Include/BsMeshManager.h

@@ -19,29 +19,6 @@ namespace BansheeEngine
 		MeshManager();
 		~MeshManager();
 
-		/** @copydoc Mesh::create(UINT32, UINT32, const SPtr<VertexDataDesc>&, int, DrawOperationType, IndexType, const SPtr<Skeleton>&) */
-		SPtr<Mesh> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, int usage = MU_STATIC, 
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
-
-		/** @copydoc Mesh::create(UINT32, UINT32, const SPtr<VertexDataDesc>&, const Vector<SubMesh>&, int, IndexType, const SPtr<Skeleton>&) */
-		SPtr<Mesh> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, const Vector<SubMesh>& subMeshes, 
-			int usage = MU_STATIC, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
-
-		/** @copydoc Mesh::create(const SPtr<MeshData>&, int, DrawOperationType, const SPtr<Skeleton>&) */
-		SPtr<Mesh> create(const SPtr<MeshData>& initialData, int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
-			const SPtr<Skeleton>& skeleton = nullptr);
-
-		/** @copydoc Mesh::create(const SPtr<MeshData>&, const Vector<SubMesh>&, int, const SPtr<Skeleton>&) */
-		SPtr<Mesh> create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC, 
-			const SPtr<Skeleton>& skeleton = nullptr);
-
-		/**
-		 * Creates a new empty and uninitialized mesh. You will need to manually initialize the mesh before using it.
-		 *	
-		 * @note	This should only be used for special cases and is not meant for normal use.
-		 */
-		SPtr<Mesh> createEmpty();
-
 		/** Returns some dummy mesh data with one triangle you may use for initializing a mesh. */
 		SPtr<MeshData> getDummyMeshData() const { return mDummyMeshData; }
 
@@ -50,7 +27,7 @@ namespace BansheeEngine
 
 	protected:
 		/** @copydoc Module::onStartUp */
-		virtual void onStartUp() override;
+		void onStartUp() override;
 
 	private:
 		SPtr<MeshData> mDummyMeshData;

+ 3 - 2
Source/BansheeCore/Include/BsMeshRTTI.h

@@ -7,7 +7,7 @@
 #include "BsCoreApplication.h"
 #include "BsMesh.h"
 #include "BsSkeleton.h"
-#include "BsMeshManager.h"
+#include "BsMorphShapes.h"
 #include "BsCoreThread.h"
 
 namespace BansheeEngine
@@ -24,6 +24,7 @@ namespace BansheeEngine
 			BS_RTTI_MEMBER_PLAIN(mIndexType, 1)
 			BS_RTTI_MEMBER_PLAIN(mUsage, 2)
 			BS_RTTI_MEMBER_REFLPTR(mSkeleton, 4)
+			BS_RTTI_MEMBER_REFLPTR(mMorphShapes, 5)
 		BS_END_RTTI_MEMBERS
 
 		SPtr<MeshData> getMeshData(Mesh* obj) 
@@ -56,7 +57,7 @@ namespace BansheeEngine
 
 		SPtr<IReflectable> newRTTIObject() override
 		{
-			return MeshManager::instance().createEmpty();
+			return Mesh::createEmpty();
 		}
 
 		const String& getRTTIName() override

+ 6 - 1
Source/BansheeCore/Include/BsMorphShapes.h

@@ -15,6 +15,11 @@ namespace BansheeEngine
 	/** A single vertex used for morph target animation. Contains a difference between base and target shape. */
 	struct BS_CORE_EXPORT MorphVertex
 	{
+		MorphVertex() { }
+		MorphVertex(const Vector3& deltaPosition, const Vector3& deltaNormal, UINT32 sourceIdx)
+			:deltaPosition(deltaPosition), deltaNormal(deltaNormal), sourceIdx(sourceIdx)
+		{ }
+
 		Vector3 deltaPosition;
 		Vector3 deltaNormal;
 		UINT32 sourceIdx;
@@ -36,7 +41,7 @@ namespace BansheeEngine
 		const Vector<MorphVertex>& getVertices() const { return mVertices; }
 
 		/** Creates a new morph shape from the provided set of vertices. */
-		SPtr<MorphShape> create(const String& name, const Vector<MorphVertex>& vertices);
+		static SPtr<MorphShape> create(const String& name, const Vector<MorphVertex>& vertices);
 
 	private:
 		String mName;

+ 70 - 91
Source/BansheeCore/Source/BsMesh.cpp

@@ -14,12 +14,13 @@
 
 namespace BansheeEngine
 {
-	MeshCore::MeshCore(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton, 
-		const SPtr<MeshData>& initialMeshData)
-		: MeshCoreBase(numVertices, numIndices, subMeshes), mVertexData(nullptr), mIndexBuffer(nullptr)
-		, mVertexDesc(vertexDesc), mUsage(usage), mIndexType(indexType), mSkeleton(skeleton)
-		, mTempInitialMeshData(initialMeshData)
+	MESH_DESC MESH_DESC::DEFAULT = MESH_DESC();
+
+	MeshCore::MeshCore(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
+		: MeshCoreBase(desc.numVertices, desc.numIndices, desc.subMeshes), mVertexData(nullptr), mIndexBuffer(nullptr)
+		, mVertexDesc(desc.vertexDesc), mUsage(desc.usage), mIndexType(desc.indexType)
+		, mTempInitialMeshData(initialMeshData), mSkeleton(desc.skeleton), mMorphShapes(desc.morphShapes)
+		
 	{ }
 
 	MeshCore::~MeshCore()
@@ -297,41 +298,26 @@ namespace BansheeEngine
 	}
 
 	SPtr<MeshCore> MeshCore::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
-	{
-		SubMesh subMesh(0, numIndices, drawOp);
-
-		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices, 
-			vertexDesc, { subMesh }, usage, indexType, skeleton, nullptr));
-		mesh->_setThisPtr(mesh);
-		mesh->initialize();
-
-		return mesh;
-	}
-
-	SPtr<MeshCore> MeshCore::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
+		int usage, DrawOperationType drawOp, IndexType indexType)
 	{
-		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices,
-			vertexDesc, subMeshes, usage, indexType, skeleton, nullptr));
+		MESH_DESC desc;
+		desc.numVertices = numVertices;
+		desc.numIndices = numIndices;
+		desc.vertexDesc = vertexDesc;
+		desc.subMeshes.push_back(SubMesh(0, numIndices, drawOp));
+		desc.usage = usage;
+		desc.indexType = indexType;
 
+		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(nullptr, desc));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
 		return mesh;
 	}
 
-	SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, 
-		const SPtr<Skeleton>& skeleton)
+	SPtr<MeshCore> MeshCore::create(const MESH_DESC& desc)
 	{
-		UINT32 numVertices = initialMeshData->getNumVertices();
-		UINT32 numIndices = initialMeshData->getNumIndices();
-		SPtr<VertexDataDesc> vertexDesc = initialMeshData->getVertexDesc();
-		SubMesh subMesh(0, numIndices, drawOp);
-		IndexType indexType = initialMeshData->getIndexType();
-		
-		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices,
-			vertexDesc, { subMesh }, usage, indexType, skeleton, initialMeshData));
+		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(nullptr, desc));
 
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
@@ -339,16 +325,15 @@ namespace BansheeEngine
 		return mesh;
 	}
 
-	SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, 
-		const SPtr<Skeleton>& skeleton)
+	SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
 	{
-		UINT32 numVertices = initialMeshData->getNumVertices();
-		UINT32 numIndices = initialMeshData->getNumIndices();
-		SPtr<VertexDataDesc> vertexDesc = initialMeshData->getVertexDesc();
-		IndexType indexType = initialMeshData->getIndexType();
+		MESH_DESC descCopy = desc;
+		descCopy.numVertices = initialMeshData->getNumVertices();
+		descCopy.numIndices = initialMeshData->getNumIndices();
+		descCopy.vertexDesc = initialMeshData->getVertexDesc();
+		descCopy.indexType = initialMeshData->getIndexType();
 
-		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices,
-			vertexDesc, subMeshes, usage, indexType, skeleton, initialMeshData));
+		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(initialMeshData, descCopy));
 
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
@@ -356,34 +341,18 @@ namespace BansheeEngine
 		return mesh;
 	}
 
-	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
-		:MeshBase(numVertices, numIndices, drawOp), mVertexDesc(vertexDesc), mUsage(usage),
-		mIndexType(indexType), mSkeleton(skeleton)
+	Mesh::Mesh(const MESH_DESC& desc)
+		:MeshBase(desc.numVertices, desc.numIndices, desc.subMeshes), mVertexDesc(desc.vertexDesc), mUsage(desc.usage),
+		mIndexType(desc.indexType), mSkeleton(desc.skeleton), mMorphShapes(desc.morphShapes)
 	{
 
 	}
 
-	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
-		:MeshBase(numVertices, numIndices, subMeshes), mVertexDesc(vertexDesc), mUsage(usage), 
-		mIndexType(indexType), mSkeleton(skeleton)
-	{
-
-	}
-
-	Mesh::Mesh(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton)
-		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), drawOp), 
+	Mesh::Mesh(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
+		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), desc.subMeshes),
 		mCPUData(initialMeshData), mVertexDesc(initialMeshData->getVertexDesc()),
-		mUsage(usage), mIndexType(initialMeshData->getIndexType()), mSkeleton(skeleton)
-	{
-
-	}
-
-	Mesh::Mesh(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, const SPtr<Skeleton>& skeleton)
-		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), subMeshes),
-		mCPUData(initialMeshData), mVertexDesc(initialMeshData->getVertexDesc()), 
-		mUsage(usage), mIndexType(initialMeshData->getIndexType()), mSkeleton(skeleton)
+		mUsage(desc.usage), mIndexType(initialMeshData->getIndexType()), mSkeleton(desc.skeleton), 
+		mMorphShapes(desc.morphShapes)
 	{
 
 	}
@@ -467,8 +436,17 @@ namespace BansheeEngine
 
 	SPtr<CoreObjectCore> Mesh::createCore() const
 	{
-		MeshCore* obj = new (bs_alloc<MeshCore>()) MeshCore(mProperties.mNumVertices, mProperties.mNumIndices, 
-			mVertexDesc, mProperties.mSubMeshes, mUsage, mIndexType, mSkeleton, mCPUData);
+		MESH_DESC desc;
+		desc.numVertices = mProperties.mNumVertices;
+		desc.numIndices = mProperties.mNumIndices;
+		desc.vertexDesc = mVertexDesc;
+		desc.subMeshes = mProperties.mSubMeshes;
+		desc.usage = mUsage;
+		desc.indexType = mIndexType;
+		desc.skeleton = mSkeleton;
+		desc.morphShapes = mMorphShapes;
+
+		MeshCore* obj = new (bs_alloc<MeshCore>()) MeshCore(mCPUData, desc);
 
 		SPtr<CoreObjectCore> meshCore = bs_shared_ptr<MeshCore>(obj);
 		meshCore->_setThisPtr(meshCore);
@@ -563,54 +541,55 @@ namespace BansheeEngine
 	/************************************************************************/
 
 	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
+		int usage, DrawOperationType drawOp, IndexType indexType)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(numVertices, numIndices, vertexDesc, usage, drawOp, indexType, skeleton);
+		MESH_DESC desc;
+		desc.numVertices = numVertices;
+		desc.numIndices = numIndices;
+		desc.vertexDesc = vertexDesc;
+		desc.usage = usage;
+		desc.subMeshes.push_back(SubMesh(0, numIndices, drawOp));
+		desc.indexType = indexType;
 
+		SPtr<Mesh> meshPtr = _createPtr(desc);
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
+	HMesh Mesh::create(const MESH_DESC& desc)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType, skeleton);
-
+		SPtr<Mesh> meshPtr = _createPtr(desc);
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton)
+	HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(initialMeshData, usage, drawOp, skeleton);
-
+		SPtr<Mesh> meshPtr = _createPtr(initialMeshData, desc);
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, const SPtr<Skeleton>& skeleton)
+	SPtr<Mesh> Mesh::_createPtr(const MESH_DESC& desc)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(initialMeshData, subMeshes, usage, skeleton);
+		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(desc));
+		mesh->_setThisPtr(mesh);
+		mesh->initialize();
 
-		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
+		return mesh;
 	}
 
-	SPtr<Mesh> Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
+	SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, const MESH_DESC& desc)
 	{
-		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, usage, drawOp, indexType, skeleton);
-	}
+		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialMeshData, desc));
+		mesh->_setThisPtr(mesh);
+		mesh->initialize();
 
-	SPtr<Mesh> Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
-	{
-		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType, skeleton);
+		return mesh;
 	}
 
-	SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton)
+	SPtr<Mesh> Mesh::createEmpty()
 	{
-		return MeshManager::instance().create(initialMeshData, usage, drawOp, skeleton);
-	}
+		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh());
+		mesh->_setThisPtr(mesh);
 
-	SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, const SPtr<Skeleton>& skeleton)
-	{
-		return MeshManager::instance().create(initialMeshData, subMeshes, usage, skeleton);
+		return mesh;
 	}
 }

+ 2 - 56
Source/BansheeCore/Source/BsMeshManager.cpp

@@ -10,64 +10,10 @@
 namespace BansheeEngine
 {
 	MeshManager::MeshManager()
-	{
-
-	}
+	{ }
 
 	MeshManager::~MeshManager()
-	{
-
-	}
-
-	SPtr<Mesh> MeshManager::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
-	{
-		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) 
-			Mesh(numVertices, numIndices, vertexDesc, usage, drawOp, indexType, skeleton));
-		mesh->_setThisPtr(mesh);
-		mesh->initialize();
-
-		return mesh;
-	}
-
-	SPtr<Mesh> MeshManager::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
-	{
-		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>())
-			Mesh(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType, skeleton));
-		mesh->_setThisPtr(mesh);
-		mesh->initialize();
-
-		return mesh;
-	}
-
-	SPtr<Mesh> MeshManager::create(const SPtr<MeshData>& initialData, int usage, DrawOperationType drawOp, 
-		const SPtr<Skeleton>& skeleton)
-	{
-		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialData, usage, drawOp, skeleton));
-		mesh->_setThisPtr(mesh);
-		mesh->initialize();
-
-		return mesh;
-	}
-
-	SPtr<Mesh> MeshManager::create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage, 
-		const SPtr<Skeleton>& skeleton)
-	{
-		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialData, subMeshes, usage, skeleton));
-		mesh->_setThisPtr(mesh);
-		mesh->initialize();
-
-		return mesh;
-	}
-
-	SPtr<Mesh> MeshManager::createEmpty()
-	{
-		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh());
-		mesh->_setThisPtr(mesh);
-
-		return mesh;
-	}
+	{ }
 
 	void MeshManager::onStartUp()
 	{

+ 1 - 2
Source/BansheeEditor/Include/BsScenePicking.h

@@ -155,11 +155,10 @@ namespace BansheeEngine
 	private:
 		friend class ScenePicking;
 
-		SPtr<MultiRenderTextureCore> mPickingTexture;
-
 		static const float ALPHA_CUTOFF;
 
 		MaterialData mMaterialData[3];
+		SPtr<MultiRenderTextureCore> mPickingTexture;
 	};
 
 	/** @} */

+ 1 - 0
Source/BansheeFBXImporter/Include/BsFBXImportData.h

@@ -53,6 +53,7 @@ namespace BansheeEngine
 		Vector<Vector3> bitangents;
 
 		float weight;
+		String name;
 	};
 
 	/**	Contains all geometry for a single blend shape. */

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

@@ -16,6 +16,7 @@ namespace BansheeEngine
 	 */
 
 	struct AnimationSplitInfo;
+	class MorphShapes;
 
 	/** Importer implementation that handles FBX/OBJ/DAE/3DS file import by using the FBX SDK. */
 	class BS_FBX_EXPORT FBXImporter : public SpecificImporter
@@ -52,7 +53,8 @@ namespace BansheeEngine
 		 * Reads the FBX file and outputs mesh data from the read file. Sub-mesh information will be output in @p subMeshes.
 		 */
 		SPtr<RendererMeshData> importMeshData(const Path& filePath, SPtr<const ImportOptions> importOptions, 
-			Vector<SubMesh>& subMeshes, Vector<FBXAnimationClipData>& animationClips, SPtr<Skeleton>& skeleton);
+			Vector<SubMesh>& subMeshes, Vector<FBXAnimationClipData>& animationClips, SPtr<Skeleton>& skeleton, 
+			SPtr<MorphShapes>& morphShapes);
 
 		/**
 		 * Loads the data from the file at the provided path into the provided FBX scene. Returns false if the file
@@ -135,7 +137,20 @@ namespace BansheeEngine
 
 		/** Converts the mesh data from the imported FBX scene into mesh data that can be used for initializing a mesh. */
 		SPtr<RendererMeshData> generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options, 
-			Vector<SubMesh>& outputSubMeshes, SPtr<Skeleton>& outputSkeleton);
+			Vector<SubMesh>& outputSubMeshes);
+
+		/** 
+		 * Parses the scene and outputs a skeleton for the imported meshes using the imported raw data. 
+		 *
+		 * @param[in]	scene		Scene whose meshes to parse.
+		 * @param[in]	sharedRoot	Determines should a shared root bone be created. Set this to true if the scene contains
+		 *							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.
+		 */
+		SPtr<Skeleton> importSkeleton(const FBXImportScene& scene, bool sharedRoot);
+
+		/** Parses the scene and generates morph shapes for the imported meshes using the imported raw data. */
+		SPtr<MorphShapes> importMorphShapes(const FBXImportScene& scene);
 
 		/**	Creates an internal representation of an FBX node from an FbxNode object. */
 		FBXImportNode* createImportNode(FBXImportScene& scene, FbxNode* fbxNode, FBXImportNode* parent);

+ 161 - 85
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -20,6 +20,7 @@
 #include "BsAnimationClip.h"
 #include "BsAnimationUtility.h"
 #include "BsSkeleton.h"
+#include "BsMorphShapes.h"
 #include "BsPhysics.h"
 
 namespace BansheeEngine
@@ -117,18 +118,19 @@ namespace BansheeEngine
 
 	SPtr<Resource> FBXImporter::import(const Path& filePath, SPtr<const ImportOptions> importOptions)
 	{
-		Vector<SubMesh> subMeshes;
+		MESH_DESC desc;
+
 		Vector<FBXAnimationClipData> dummy;
-		SPtr<Skeleton> skeleton;
-		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, subMeshes, dummy, skeleton);
+		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, desc.subMeshes, dummy, 
+			desc.skeleton, desc.morphShapes);
 
 		const MeshImportOptions* meshImportOptions = static_cast<const MeshImportOptions*>(importOptions.get());
 
-		INT32 usage = MU_STATIC;
+		desc.usage = MU_STATIC;
 		if (meshImportOptions->getCPUReadable())
-			usage |= MU_CPUCACHED;
+			desc.usage |= MU_CPUCACHED;
 
-		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), subMeshes, usage, skeleton);
+		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), desc);
 
 		WString fileName = filePath.getWFilename(false);
 		mesh->setName(fileName);
@@ -138,18 +140,19 @@ namespace BansheeEngine
 
 	Vector<SubResourceRaw> FBXImporter::importAll(const Path& filePath, SPtr<const ImportOptions> importOptions)
 	{
-		Vector<SubMesh> subMeshes;
+		MESH_DESC desc;
+
 		Vector<FBXAnimationClipData> animationClips;
-		SPtr<Skeleton> skeleton;
-		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, subMeshes, animationClips, skeleton);
+		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, desc.subMeshes, animationClips, 
+			desc.skeleton, desc.morphShapes);
 
 		const MeshImportOptions* meshImportOptions = static_cast<const MeshImportOptions*>(importOptions.get());
 
-		INT32 usage = MU_STATIC;
+		desc.usage = MU_STATIC;
 		if (meshImportOptions->getCPUReadable())
-			usage |= MU_CPUCACHED;
+			desc.usage |= MU_CPUCACHED;
 
-		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), subMeshes, usage, skeleton);
+		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), desc);
 
 		WString fileName = filePath.getWFilename(false);
 		mesh->setName(fileName);
@@ -199,7 +202,8 @@ namespace BansheeEngine
 	}
 
 	SPtr<RendererMeshData> FBXImporter::importMeshData(const Path& filePath, SPtr<const ImportOptions> importOptions, 
-		Vector<SubMesh>& subMeshes, Vector<FBXAnimationClipData>& animation, SPtr<Skeleton>& skeleton)
+		Vector<SubMesh>& subMeshes, Vector<FBXAnimationClipData>& animation, SPtr<Skeleton>& skeleton, 
+		SPtr<MorphShapes>& morphShapes)
 	{
 		FbxScene* fbxScene = nullptr;
 
@@ -234,7 +238,10 @@ namespace BansheeEngine
 		splitMeshVertices(importedScene);
 		generateMissingTangentSpace(importedScene, fbxImportOptions);
 
-		SPtr<RendererMeshData> rendererMeshData = generateMeshData(importedScene, fbxImportOptions, subMeshes, skeleton);
+		SPtr<RendererMeshData> rendererMeshData = generateMeshData(importedScene, fbxImportOptions, subMeshes);
+
+		skeleton = importSkeleton(importedScene, subMeshes.size() > 1);
+		morphShapes = importMorphShapes(importedScene);		
 
 		// Import animation clips
 		if (!importedScene.clips.empty())
@@ -250,6 +257,143 @@ namespace BansheeEngine
 		return rendererMeshData;
 	}
 
+	SPtr<Skeleton> FBXImporter::importSkeleton(const FBXImportScene& scene, bool sharedRoot)
+	{
+		Vector<BONE_DESC> allBones;
+		UnorderedMap<FBXImportNode*, UINT32> boneMap;
+
+		for (auto& mesh : scene.meshes)
+		{
+			// Create bones
+			UINT32 numBones = (UINT32)mesh->bones.size();
+			for (auto& fbxBone : mesh->bones)
+			{
+				UINT32 boneIdx = (UINT32)allBones.size();
+				boneMap[fbxBone.node] = boneIdx;
+
+				allBones.push_back(BONE_DESC());
+				BONE_DESC& bone = allBones.back();
+
+				bone.name = fbxBone.node->name;
+				bone.invBindPose = fbxBone.bindPose;
+			}
+		}
+
+		// Generate skeleton
+		if (allBones.size() > 0)
+		{
+			// Find bone parents
+			UINT32 numProcessedBones = 0;
+
+			// Generate common root bone for all meshes
+			UINT32 rootBoneIdx = (UINT32)-1;
+			if (sharedRoot)
+			{
+				rootBoneIdx = (UINT32)allBones.size();
+
+				allBones.push_back(BONE_DESC());
+				BONE_DESC& bone = allBones.back();
+
+				bone.name = "MultiMeshRoot";
+				bone.invBindPose = Matrix4::IDENTITY;
+				bone.parent = (UINT32)-1;
+
+				numProcessedBones++;
+			}
+
+			Stack<std::pair<FBXImportNode*, UINT32>> todo;
+			todo.push({ scene.rootNode, rootBoneIdx });
+
+			while (!todo.empty())
+			{
+				auto entry = todo.top();
+				todo.pop();
+
+				FBXImportNode* node = entry.first;
+				UINT32 parentBoneIdx = entry.second;
+
+				auto boneIter = boneMap.find(node);
+				if (boneIter != boneMap.end())
+				{
+					UINT32 boneIdx = boneIter->second;
+					allBones[boneIdx].parent = parentBoneIdx;
+					numProcessedBones++;
+
+					parentBoneIdx = boneIdx;
+				}
+
+				for (auto& child : node->children)
+					todo.push({ child, parentBoneIdx });
+			}
+
+			UINT32 numAllBones = (UINT32)allBones.size();
+			if (numProcessedBones == numAllBones)
+				return Skeleton::create(allBones.data(), numAllBones);
+
+			LOGERR("Not all bones were found in the node hierarchy. Skeleton invalid.");
+		}
+
+		return nullptr;
+	}
+
+	SPtr<MorphShapes> FBXImporter::importMorphShapes(const FBXImportScene& scene)
+	{
+		SPtr<MorphShapes> morphShapes;
+		for (auto& mesh : scene.meshes)
+		{
+			// Create bones
+			size_t numVertices = mesh->positions.size();
+			bool hasNormals = mesh->normals.size() == numVertices;
+
+			// Create morph targets
+			Vector<SPtr<MorphShape>> allMorphShapes;
+			for (auto& fbxBlendShape : mesh->blendShapes)
+			{
+				for (auto& frame : fbxBlendShape.frames)
+				{
+					assert(frame.positions.size() == numVertices);
+
+					if (hasNormals)
+						assert(frame.normals.size() == numVertices);
+
+					Vector<MorphVertex> morphVertices;
+					for (UINT32 i = 0; i < numVertices; i++)
+					{
+						Vector3 positionDelta = frame.positions[i] - mesh->positions[i];
+						Vector3 normalDelta;
+						if (hasNormals)
+							normalDelta = frame.normals[i] - mesh->normals[i];
+						else
+							normalDelta = Vector3::ZERO;
+
+						if (positionDelta.squaredLength() > 0.0001f || normalDelta.squaredLength() > 0.01f)
+							morphVertices.push_back(MorphVertex(positionDelta, normalDelta, i));
+					}
+
+					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;
+				}
+			}
+		}
+
+		return morphShapes;
+	}
+
 	bool FBXImporter::startUpSdk(FbxScene*& scene)
 	{
 		mFBXManager = FbxManager::Create();
@@ -564,7 +708,7 @@ namespace BansheeEngine
 	}
 
 	SPtr<RendererMeshData> FBXImporter::generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options, 
-		Vector<SubMesh>& outputSubMeshes, SPtr<Skeleton>& outputSkeleton)
+		Vector<SubMesh>& outputSubMeshes)
 	{
 		Vector<SPtr<MeshData>> allMeshData;
 		Vector<Vector<SubMesh>> allSubMeshes;
@@ -757,83 +901,14 @@ namespace BansheeEngine
 					bs_stack_free(weights);
 				}
 
-				// TODO - Transform blend shapes?
-
 				allMeshData.push_back(meshData->getData());
 				allSubMeshes.push_back(subMeshes);
 			}
 
-			// Create bones
 			UINT32 numBones = (UINT32)mesh->bones.size();
-			for(auto& fbxBone : mesh->bones)
-			{
-				UINT32 boneIdx = (UINT32)allBones.size();
-				boneMap[fbxBone.node] = boneIdx;
-
-				allBones.push_back(BONE_DESC());
-				BONE_DESC& bone = allBones.back();
-
-				bone.name = fbxBone.node->name;
-				bone.invBindPose = fbxBone.bindPose;
-			}
-
 			boneIndexOffset += numBones;
 		}
 
-		// Generate skeleton
-		if (allBones.size() > 0)
-		{
-			// Find bone parents
-			UINT32 numProcessedBones = 0;
-
-			// Generate common root bone for all meshes
-			UINT32 rootBoneIdx = (UINT32)-1;
-			if(allMeshData.size() > 1)
-			{
-				rootBoneIdx = (UINT32)allBones.size();
-
-				allBones.push_back(BONE_DESC());
-				BONE_DESC& bone = allBones.back();
-
-				bone.name = "MultiMeshRoot";
-				bone.invBindPose = Matrix4::IDENTITY;
-				bone.parent = (UINT32)-1;
-
-				numProcessedBones++;
-			}
-
-			Stack<std::pair<FBXImportNode*, UINT32>> todo;
-			todo.push({ scene.rootNode, rootBoneIdx });
-
-			while(!todo.empty())
-			{
-				auto entry = todo.top();
-				todo.pop();
-
-				FBXImportNode* node = entry.first;
-				UINT32 parentBoneIdx = entry.second;
-
-				auto boneIter = boneMap.find(node);
-				if (boneIter != boneMap.end())
-				{
-					UINT32 boneIdx = boneIter->second;
-					allBones[boneIdx].parent = parentBoneIdx;
-					numProcessedBones++;
-
-					parentBoneIdx = boneIdx;
-				}
-
-				for (auto& child : node->children)
-					todo.push({ child, parentBoneIdx });
-			}
-
-			UINT32 numAllBones = (UINT32)allBones.size();
-			if (numProcessedBones == numAllBones)
-				outputSkeleton = Skeleton::create(allBones.data(), numAllBones);
-			else
-				LOGERR("Not all bones were found in the node hierarchy. Skeleton invalid.");
-		}
-
 		if (allMeshData.size() > 1)
 		{
 			return RendererMeshData::create(MeshData::combine(allMeshData, allSubMeshes, outputSubMeshes));
@@ -1208,8 +1283,9 @@ namespace BansheeEngine
 						FbxShape* fbxShape = channel->GetTargetShape(k);
 
 						FBXBlendShapeFrame& frame = blendShape.frames[k];
+						frame.name = fbxShape->GetName();
 						frame.weight = (float)weights[k];
-
+						
 						importBlendShapeFrame(fbxShape, *mesh, options, frame);
 					}
 				}

+ 14 - 6
Source/SBansheeEngine/Source/BsScriptMesh.cpp

@@ -51,14 +51,19 @@ namespace BansheeEngine
 	void ScriptMesh::internal_CreateInstance(MonoObject* instance, int numVertices, int numIndices, 
 		MonoArray* subMeshes, MeshUsage usage, VertexLayout vertex, ScriptIndexType index)
 	{
-		SPtr<VertexDataDesc> vertexDesc = RendererMeshData::vertexLayoutVertexDesc(vertex);
-
 		IndexType indexType = IT_16BIT;
 		if (index == ScriptIndexType::Index32)
 			indexType = IT_32BIT;
 
-		Vector<SubMesh> nativeSubMeshes = monoToNativeSubMeshes(subMeshes);
-		HMesh mesh = Mesh::create(numVertices, numIndices, vertexDesc, nativeSubMeshes, usage, indexType);
+		MESH_DESC desc;
+		desc.numVertices = numVertices;
+		desc.numIndices = numIndices;
+		desc.vertexDesc = RendererMeshData::vertexLayoutVertexDesc(vertex);
+		desc.subMeshes = monoToNativeSubMeshes(subMeshes);
+		desc.usage = usage;
+		desc.indexType = indexType;
+
+		HMesh mesh = Mesh::create(desc);
 
 		ScriptMesh* scriptInstance;
 		ScriptResourceManager::instance().createScriptResource(instance, mesh, &scriptInstance);
@@ -71,8 +76,11 @@ namespace BansheeEngine
 		if (data != nullptr)
 			meshData = data->getInternalValue()->getData();
 
-		Vector<SubMesh> nativeSubMeshes = monoToNativeSubMeshes(subMeshes);
-		HMesh mesh = Mesh::create(meshData, nativeSubMeshes, usage);
+		MESH_DESC desc;
+		desc.subMeshes = monoToNativeSubMeshes(subMeshes);
+		desc.usage = usage;
+
+		HMesh mesh = Mesh::create(meshData, desc);
 
 		ScriptMesh* scriptInstance;
 		ScriptResourceManager::instance().createScriptResource(instance, mesh, &scriptInstance);