From 973e3fede3e4f91bde158cd3a6dd70a1276282d6 Mon Sep 17 00:00:00 2001 From: jonathanklein Date: Tue, 13 Mar 2012 16:29:29 +0000 Subject: [PATCH] Ogre: Shared BoneWeights get loaded git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1200 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/OgreImporter.cpp | 18 +++ code/OgreImporter.hpp | 36 ++++-- code/OgreMesh.cpp | 269 +++++++++++++++++++++--------------------- 3 files changed, 181 insertions(+), 142 deletions(-) diff --git a/code/OgreImporter.cpp b/code/OgreImporter.cpp index 13fd3b9e6..3241b8497 100644 --- a/code/OgreImporter.cpp +++ b/code/OgreImporter.cpp @@ -159,6 +159,7 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass { string SkeletonFile=GetAttribute(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 theSubMesh, SubMeshes) + { + ProcessSubMesh(*theSubMesh, m_SharedGeometry); + } + //_______________________________________________________ + + + //----------------- Now fill the Assimp scene --------------------------- diff --git a/code/OgreImporter.hpp b/code/OgreImporter.hpp index 181dcc409..f3d5dd3d9 100644 --- a/code/OgreImporter.hpp +++ b/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 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! + /// Reads bone weights are stores them into the given submesh + static void ReadBoneWeights(SubMesh &theSubMesh, XmlReader *Reader); + + /// 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 + aiMesh* CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector& 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 &Bones, std::vector &Animations) const; - /// converts the animations in aiAnimations and puts them into the scene + /// Converts the animations in aiAnimations and puts them into the scene void PutAnimationsInScene(const std::vector &Bones, const std::vector &Animations); - /// 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& Bones) const; - - //creates the aiskeleton in current scene + /// Creates the aiskeleton in current scene void CreateAssimpSkeleton(const std::vector &Bones, const std::vector &Animations); + /// Recursivly creates a filled aiNode from a given root bone + static aiNode* CreateAiNodeFromBone(int BoneId, const std::vector &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 &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& Bones); }; diff --git a/code/OgreMesh.cpp b/code/OgreMesh.cpp index d8e0608d0..b02641f4d 100644 --- a/code/OgreMesh.cpp +++ b/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(Reader, "usesharedvertices"); + theSubMesh.SharedData=GetAttribute(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(Reader, "vertexindex"); - NewWeight.BoneId=GetAttribute(Reader, "boneindex"); - NewWeight.Value=GetAttribute(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 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 UniquePositions(UniqueVertexCount); - vector UniqueNormals(UniqueVertexCount); - vector UniqueTangents(UniqueVertexCount); - vector UniqueUvs(UniqueVertexCount); - vector< vector > 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 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; VertexId1.0f+0.05f) - { - //normalize all weights: - for(unsigned int BoneId=0; BoneIdgetNodeName()==string("vertexboneassignment")) + { + Weight NewWeight; + unsigned int VertexId=GetAttribute(Reader, "vertexindex"); + NewWeight.BoneId=GetAttribute(Reader, "boneindex"); + NewWeight.Value=GetAttribute(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 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 UniquePositions(UniqueVertexCount); + vector UniqueNormals(UniqueVertexCount); + vector UniqueTangents(UniqueVertexCount); + vector UniqueUvs(UniqueVertexCount); + vector< vector > 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 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; VertexId1.0f+0.05f) + { + //normalize all weights: + for(unsigned int BoneId=0; BoneId& Bones) const {