Sfoglia il codice sorgente

Ogre: Shared BoneWeights get loaded

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1200 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
jonathanklein 13 anni fa
parent
commit
973e3fede3
3 ha cambiato i file con 181 aggiunte e 142 eliminazioni
  1. 18 0
      code/OgreImporter.cpp
  2. 27 9
      code/OgreImporter.hpp
  3. 136 133
      code/OgreMesh.cpp

+ 18 - 0
code/OgreImporter.cpp

@@ -159,6 +159,7 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
 	{
 		string SkeletonFile=GetAttribute<string>(MeshFile, "name");
 		LoadSkeleton(SkeletonFile, Bones, Animations);
+		XmlRead(MeshFile);
 	}
 	else
 	{
@@ -167,6 +168,23 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
 	}
 	//__________________________________________________________________
 
+
+	//now there might be boneassignments for the shared geometry:
+	if(MeshFile->getNodeName()==string("boneassignments"))
+	{
+		ReadBoneWeights(m_SharedGeometry, MeshFile);
+	}
+
+
+	//----------------- Process Meshs -----------------------
+	BOOST_FOREACH(boost::shared_ptr<SubMesh> theSubMesh, SubMeshes)
+	{
+		ProcessSubMesh(*theSubMesh, m_SharedGeometry);
+	}
+	//_______________________________________________________
+
+
+
 	
 	//----------------- Now fill the Assimp scene ---------------------------
 	

+ 27 - 9
code/OgreImporter.hpp

@@ -22,6 +22,8 @@ struct Keyframe;
 ///A submesh from Ogre
 struct SubMesh
 {	
+	bool SharedData;
+
 	std::string Name;
 	std::string MaterialName;
 	std::vector<Face> FaceList;
@@ -35,7 +37,7 @@ struct SubMesh
 	int MaterialIndex;///< The Index in the Assimp Materialarray from the material witch is attached to this submesh
 	unsigned int BonesUsed;//the highest index of a bone from a bone weight, this is needed to create the assimp bone structur (converting from Vertex-Bones to Bone-Vertices)
 
-	SubMesh(): HasPositions(false), HasNormals(false), HasTangents(false),
+	SubMesh(): SharedData(false), HasPositions(false), HasNormals(false), HasTangents(false),
 		NumUvs(0), MaterialIndex(-1), BonesUsed(0) {}//initialize everything
 };
 
@@ -50,29 +52,44 @@ public:
 	virtual void SetupProperties(const Importer* pImp);
 private:
 
+
+	//-------------------------------- OgreMesh.cpp -------------------------------
 	/// Helper Functions to read parts of the XML File
 	void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);//the submesh reference is the result value
 
 	/// Reads a single Vertexbuffer and writes its data in the Submesh
 	static void ReadVertexBuffer(SubMesh &theSubMesh, XmlReader *Reader, unsigned int NumVertices);
 
-	/// writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it!
-	void LoadSkeleton(std::string FileName, std::vector<Bone> &Bones, std::vector<Animation> &Animations) const;
+	/// Reads bone weights are stores them into the given submesh
+	static void ReadBoneWeights(SubMesh &theSubMesh, XmlReader *Reader);
 
-	/// converts the animations in aiAnimations and puts them into the scene
-	void PutAnimationsInScene(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
+	/// After Loading a SubMehs some work needs to be done (make all Vertexes unique, normalize weights)
+	static void OgreImporter::ProcessSubMesh(SubMesh &theSubMesh, SubMesh &theSharedGeometry);
 
-	/// uses the bone data to convert a SubMesh into a aiMesh which will be created and returned
+	/// Uses the bone data to convert a SubMesh into a aiMesh which will be created and returned
 	aiMesh* CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector<Bone>& Bones) const;
+	
+
+	//-------------------------------- OgreSkeleton.cpp -------------------------------
+	/// Writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it!
+	void LoadSkeleton(std::string FileName, std::vector<Bone> &Bones, std::vector<Animation> &Animations) const;
 
-	//creates the aiskeleton in current scene
+	/// Converts the animations in aiAnimations and puts them into the scene
+	void PutAnimationsInScene(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
+
+	/// Creates the aiskeleton in current scene
 	void CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
 
+	/// Recursivly creates a filled aiNode from a given root bone
+	static aiNode* CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode);
+	
+
+	//-------------------------------- OgreMaterial.cpp -------------------------------
 	aiMaterial* LoadMaterial(const std::string MaterialName) const;
 	static void ReadTechnique(std::stringstream &ss, aiMaterial* NewMaterial);
 	
-	///Recursivly creates a filled aiNode from a given root bone
-	static aiNode* CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode);
+
+
 
 	//Now we don't have to give theses parameters to all functions
 	std::string m_CurrentFilename;
@@ -126,6 +143,7 @@ struct Bone
 	bool operator==(const aiString& rval) const
 	{return Name==std::string(rval.data); }
 
+	// implemented in OgreSkeleton.cpp
 	void CalculateBoneToWorldSpaceMatrix(std::vector<Bone>& Bones);
 };
 

+ 136 - 133
code/OgreMesh.cpp

@@ -55,10 +55,8 @@ namespace Ogre
 
 void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
 {
-	//see, if we use shared vertices
-	bool bSharedData=false;
 	if(Reader->getAttributeValue("usesharedvertices"))
-		bSharedData=GetAttribute<bool>(Reader, "usesharedvertices");
+		theSubMesh.SharedData=GetAttribute<bool>(Reader, "usesharedvertices");
 
 	XmlRead(Reader);
 	//TODO: maybe we have alsways just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order
@@ -119,28 +117,10 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
 		}//end of "geometry
 
 
-		else if(string(Reader->getNodeName())=="boneassignments")
+		else if(Reader->getNodeName()==string("boneassignments"))
 		{
-			theSubMesh.Weights.resize(theSubMesh.Positions.size());
-			while(XmlRead(Reader) && Reader->getNodeName()==string("vertexboneassignment"))
-			{
-				Weight NewWeight;
-				unsigned int VertexId=GetAttribute<int>(Reader, "vertexindex");
-				NewWeight.BoneId=GetAttribute<int>(Reader, "boneindex");
-				NewWeight.Value=GetAttribute<float>(Reader, "weight");
-				//calculate the number of bones used (this is the highest id +1 becuase bone ids start at 0)
-				theSubMesh.BonesUsed=max(theSubMesh.BonesUsed, NewWeight.BoneId+1);
-				
-				
-				theSubMesh.Weights[VertexId].push_back(NewWeight);
-
-				//Once i had this line, and than i got only every second boneassignment,
-				//but my first test models had even boneassignment counts, so i thougt, everything would work.
-				//And yes, i HATE irrXML!!!
-				//XmlRead(Reader);
-			}
-
-		}//end of boneassignments
+			ReadBoneWeights(theSubMesh, Reader);
+		}
 	}
 	DefaultLogger::get()->debug((Formatter::format(),
 		"Positionen: ",theSubMesh.Positions.size(),
@@ -149,115 +129,6 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
 		" Tantents: ",theSubMesh.Tangents.size()
 	));							
 	DefaultLogger::get()->warn(Reader->getNodeName());
-
-
-
-	//---------------Make all Vertexes unique: (this is required by assimp)-----------------------
-	vector<Face> UniqueFaceList(theSubMesh.FaceList.size());
-	unsigned int UniqueVertexCount=theSubMesh.FaceList.size()*3;//*3 because each face consists of 3 vertexes, because we only support triangles^^
-	vector<aiVector3D> UniquePositions(UniqueVertexCount);
-	vector<aiVector3D> UniqueNormals(UniqueVertexCount);
-	vector<aiVector3D> UniqueTangents(UniqueVertexCount);
-	vector<aiVector3D> UniqueUvs(UniqueVertexCount);
-	vector< vector<Weight> > UniqueWeights((theSubMesh.Weights.size() ? UniqueVertexCount : 0));
-
-	//Support for shared data:
-	/*We can use this loop to copy vertex informations from the shared data pool. In order to do so
-	  we just use a reference to a submodel instead of our submodel itself*/
-
-	SubMesh& VertexSource= bSharedData ? m_SharedGeometry : theSubMesh;
-	if(bSharedData)//copy vertexinformations to our mesh:
-	{
-		theSubMesh.HasPositions=m_SharedGeometry.HasPositions;
-		theSubMesh.HasNormals=m_SharedGeometry.HasNormals;
-		theSubMesh.HasTangents=m_SharedGeometry.HasTangents;
-		theSubMesh.NumUvs=m_SharedGeometry.NumUvs;
-	}
-
-
-	if(VertexSource.NumUvs > 0)
-	{
-		DefaultLogger::get()->error("Not all Uvs will be made unique!");
-	}
-
-	for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
-	{
-		//We precalculate the index vlaues her, because we need them in all vertex attributes
-		unsigned int Vertex1=theSubMesh.FaceList[i].VertexIndices[0];
-		unsigned int Vertex2=theSubMesh.FaceList[i].VertexIndices[1];
-		unsigned int Vertex3=theSubMesh.FaceList[i].VertexIndices[2];
-
-		UniquePositions[3*i+0]=VertexSource.Positions[Vertex1];
-		UniquePositions[3*i+1]=VertexSource.Positions[Vertex2];
-		UniquePositions[3*i+2]=VertexSource.Positions[Vertex3];
-
-		if(VertexSource.HasNormals)
-		{
-			UniqueNormals[3*i+0]=VertexSource.Normals[Vertex1];
-			UniqueNormals[3*i+1]=VertexSource.Normals[Vertex2];
-			UniqueNormals[3*i+2]=VertexSource.Normals[Vertex3];
-		}
-
-		if(VertexSource.HasTangents)
-		{
-			UniqueTangents[3*i+0]=VertexSource.Tangents[Vertex1];
-			UniqueTangents[3*i+1]=VertexSource.Tangents[Vertex2];
-			UniqueTangents[3*i+2]=VertexSource.Tangents[Vertex3];
-		}
-
-		if(VertexSource.NumUvs > 0)
-		{
-			UniqueUvs[3*i+0]=VertexSource.Uvs[Vertex1];
-			UniqueUvs[3*i+1]=VertexSource.Uvs[Vertex2];
-			UniqueUvs[3*i+2]=VertexSource.Uvs[Vertex3];
-		}
-
-		if(VertexSource.Weights.size())
-		{
-			//I don't think, that bone assinements can be shared, but who knows?
-			UniqueWeights[3*i+0]=VertexSource.Weights[Vertex1];
-			UniqueWeights[3*i+1]=VertexSource.Weights[Vertex2];
-			UniqueWeights[3*i+2]=VertexSource.Weights[Vertex3];
-		}
-
-		//The indexvalues a just continuous numbers (0, 1, 2, 3, 4, 5, 6...)
-		UniqueFaceList[i].VertexIndices[0]=3*i+0;
-		UniqueFaceList[i].VertexIndices[1]=3*i+1;
-		UniqueFaceList[i].VertexIndices[2]=3*i+2;
-	}
-	//_________________________________________________________________________________________
-
-	//now we have the unique datas, but want them in the SubMesh, so we swap all the containers:
-	//if we don't have one of them, we just swap empty containers, so everything is ok
-	theSubMesh.FaceList.swap(UniqueFaceList);
-	theSubMesh.Positions.swap(UniquePositions);
-	theSubMesh.Normals.swap(UniqueNormals);
-	theSubMesh.Tangents.swap(UniqueTangents);
-	theSubMesh.Uvs.swap(UniqueUvs);
-	theSubMesh.Weights.swap(UniqueWeights);
-
-	//------------- normalize weights -----------------------------
-	//The Blender exporter doesn't care about whether the sum of all boneweights for a single vertex equals 1 or not,
-	//so we have to make this sure:
-	for(unsigned int VertexId=0; VertexId<theSubMesh.Weights.size(); ++VertexId)//iterate over all vertices
-	{
-		float WeightSum=0.0f;
-		for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
-		{
-			WeightSum+=theSubMesh.Weights[VertexId][BoneId].Value;
-		}
-		
-		//check if the sum is too far away from 1
-		if(WeightSum<1.0f-0.05f || WeightSum>1.0f+0.05f)
-		{
-			//normalize all weights:
-			for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
-			{
-				theSubMesh.Weights[VertexId][BoneId].Value/=WeightSum;
-			}
-		}
-	}
-	//_________________________________________________________
 }
 
 
@@ -382,6 +253,138 @@ void OgreImporter::ReadVertexBuffer(SubMesh &theSubMesh, XmlReader *Reader, unsi
 }
 
 
+void OgreImporter::ReadBoneWeights(SubMesh &theSubMesh, XmlReader *Reader)
+{
+	theSubMesh.Weights.resize(theSubMesh.Positions.size());
+	while(XmlRead(Reader) && Reader->getNodeName()==string("vertexboneassignment"))
+	{
+		Weight NewWeight;
+		unsigned int VertexId=GetAttribute<int>(Reader, "vertexindex");
+		NewWeight.BoneId=GetAttribute<int>(Reader, "boneindex");
+		NewWeight.Value=GetAttribute<float>(Reader, "weight");
+		//calculate the number of bones used (this is the highest id +1 becuase bone ids start at 0)
+		theSubMesh.BonesUsed=max(theSubMesh.BonesUsed, NewWeight.BoneId+1);
+
+		theSubMesh.Weights[VertexId].push_back(NewWeight);
+	}
+}
+
+
+
+void OgreImporter::ProcessSubMesh(SubMesh &theSubMesh, SubMesh &theSharedGeometry)
+{
+	//---------------Make all Vertexes unique: (this is required by assimp)-----------------------
+	vector<Face> UniqueFaceList(theSubMesh.FaceList.size());
+	unsigned int UniqueVertexCount=theSubMesh.FaceList.size()*3;//*3 because each face consists of 3 vertexes, because we only support triangles^^
+	vector<aiVector3D> UniquePositions(UniqueVertexCount);
+	vector<aiVector3D> UniqueNormals(UniqueVertexCount);
+	vector<aiVector3D> UniqueTangents(UniqueVertexCount);
+	vector<aiVector3D> UniqueUvs(UniqueVertexCount);
+	vector< vector<Weight> > UniqueWeights(UniqueVertexCount);
+
+	//Support for shared data:
+	/*We can use this loop to copy vertex informations from the shared data pool. In order to do so
+	  we just use a reference to a submodel instead of our submodel itself*/
+
+	SubMesh& VertexSource= theSubMesh.SharedData ? theSharedGeometry : theSubMesh;
+	if(theSubMesh.SharedData)//copy vertexinformations to our mesh:
+	{
+		theSubMesh.HasPositions=theSharedGeometry.HasPositions;
+		theSubMesh.HasNormals=theSharedGeometry.HasNormals;
+		theSubMesh.HasTangents=theSharedGeometry.HasTangents;
+		theSubMesh.NumUvs=theSharedGeometry.NumUvs;
+		theSubMesh.BonesUsed=theSharedGeometry.BonesUsed;
+	}
+
+
+	if(VertexSource.NumUvs > 0)
+	{
+		DefaultLogger::get()->error("Not all Uvs will be made unique!");
+	}
+
+	for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
+	{
+		//We precalculate the index vlaues her, because we need them in all vertex attributes
+		unsigned int Vertex1=theSubMesh.FaceList[i].VertexIndices[0];
+		unsigned int Vertex2=theSubMesh.FaceList[i].VertexIndices[1];
+		unsigned int Vertex3=theSubMesh.FaceList[i].VertexIndices[2];
+
+		UniquePositions[3*i+0]=VertexSource.Positions[Vertex1];
+		UniquePositions[3*i+1]=VertexSource.Positions[Vertex2];
+		UniquePositions[3*i+2]=VertexSource.Positions[Vertex3];
+
+		if(VertexSource.HasNormals)
+		{
+			UniqueNormals[3*i+0]=VertexSource.Normals[Vertex1];
+			UniqueNormals[3*i+1]=VertexSource.Normals[Vertex2];
+			UniqueNormals[3*i+2]=VertexSource.Normals[Vertex3];
+		}
+
+		if(VertexSource.HasTangents)
+		{
+			UniqueTangents[3*i+0]=VertexSource.Tangents[Vertex1];
+			UniqueTangents[3*i+1]=VertexSource.Tangents[Vertex2];
+			UniqueTangents[3*i+2]=VertexSource.Tangents[Vertex3];
+		}
+
+		if(VertexSource.NumUvs > 0)
+		{
+			UniqueUvs[3*i+0]=VertexSource.Uvs[Vertex1];
+			UniqueUvs[3*i+1]=VertexSource.Uvs[Vertex2];
+			UniqueUvs[3*i+2]=VertexSource.Uvs[Vertex3];
+		}
+
+		if(VertexSource.Weights.size() > 0)
+		{
+			UniqueWeights[3*i+0]=VertexSource.Weights[Vertex1];
+			UniqueWeights[3*i+1]=VertexSource.Weights[Vertex2];
+			UniqueWeights[3*i+2]=VertexSource.Weights[Vertex3];
+		}
+
+		//The indexvalues a just continuous numbers (0, 1, 2, 3, 4, 5, 6...)
+		UniqueFaceList[i].VertexIndices[0]=3*i+0;
+		UniqueFaceList[i].VertexIndices[1]=3*i+1;
+		UniqueFaceList[i].VertexIndices[2]=3*i+2;
+	}
+	//_________________________________________________________________________________________
+
+	//now we have the unique datas, but want them in the SubMesh, so we swap all the containers:
+	//if we don't have one of them, we just swap empty containers, so everything is ok
+	theSubMesh.FaceList.swap(UniqueFaceList);
+	theSubMesh.Positions.swap(UniquePositions);
+	theSubMesh.Normals.swap(UniqueNormals);
+	theSubMesh.Tangents.swap(UniqueTangents);
+	theSubMesh.Uvs.swap(UniqueUvs);
+	theSubMesh.Weights.swap(UniqueWeights);
+
+
+
+	//------------- normalize weights -----------------------------
+	//The Blender exporter doesn't care about whether the sum of all boneweights for a single vertex equals 1 or not,
+	//so we have to make this sure:
+	for(unsigned int VertexId=0; VertexId<theSubMesh.Weights.size(); ++VertexId)//iterate over all vertices
+	{
+		float WeightSum=0.0f;
+		for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
+		{
+			WeightSum+=theSubMesh.Weights[VertexId][BoneId].Value;
+		}
+		
+		//check if the sum is too far away from 1
+		if(WeightSum<1.0f-0.05f || WeightSum>1.0f+0.05f)
+		{
+			//normalize all weights:
+			for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
+			{
+				theSubMesh.Weights[VertexId][BoneId].Value/=WeightSum;
+			}
+		}
+	}
+	//_________________________________________________________
+}
+
+
+
 
 aiMesh* OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vector<Bone>& Bones) const
 {