Ogre Animations implemented but they don't work yet.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@485 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
jonathanklein 2009-09-28 16:53:33 +00:00
parent 49ff2e8c44
commit 449bff99be
6 changed files with 323 additions and 196 deletions

View File

@ -71,15 +71,30 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
}
//-------------------Read all submeshs:-----------------------
//-------------------Read the submesh:-----------------------
SubMesh theSubMesh;
XmlRead(MeshFile);
while(string(MeshFile->getNodeName())=="submesh")//read the index values (the faces):
if(MeshFile->getNodeName()==string("submesh"))
{
SubMesh NewSubMesh;
NewSubMesh.MaterialName=GetAttribute<string>(MeshFile, "material");
DefaultLogger::get()->debug("Loading Submehs with Material: "+NewSubMesh.MaterialName);
ReadSubMesh(NewSubMesh, MeshFile);
theSubMesh.MaterialName=GetAttribute<string>(MeshFile, "material");
DefaultLogger::get()->debug("Loading Submehs with Material: "+theSubMesh.MaterialName);
ReadSubMesh(theSubMesh, MeshFile);
//Load the Material:
aiMaterial* MeshMat=LoadMaterial(theSubMesh.MaterialName);
//Set the Material:
if(m_CurrentScene->mMaterials)
throw new ImportErrorException("only 1 material supported at this time!");
m_CurrentScene->mMaterials=new aiMaterial*[1];
m_CurrentScene->mNumMaterials=1;
m_CurrentScene->mMaterials[0]=MeshMat;
theSubMesh.MaterialIndex=0;
}
//check for second root node:
if(MeshFile->getNodeName()==string("submesh"))
throw new ImportErrorException("more than one submesh in the file, abording!");
//____________________________________________________________
@ -94,16 +109,22 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
//----------------Load the skeleton: -------------------------------
vector<Bone> Bones;
vector<Animation> Animations;
if(MeshFile->getNodeName()==string("skeletonlink"))
{
string SkeletonFile=GetAttribute<string>(MeshFile, "name");
LoadSkeleton(SkeletonFile);
LoadSkeleton(SkeletonFile, Bones, Animations);
}
else
{
DefaultLogger::get()->warn("No skeleton file will be loaded");
DefaultLogger::get()->warn(MeshFile->getNodeName());
}
//__________________________________________________________________
CreateAssimpSubMesh(theSubMesh, Bones);
CreateAssimpSkeleton(Bones, Animations);
}
@ -121,12 +142,6 @@ void OgreImporter::SetupProperties(const Importer* pImp)
void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
{
vector<Face> FaceList;
vector<aiVector3D> Positions; bool HasPositions=false;
vector<aiVector3D> Normals; bool HasNormals=false;
vector<aiVector3D> Uvs; unsigned int NumUvs=0;//nearly always 2d, but assimp has always 3d texcoords
vector< vector<Weight> > Weights;
XmlRead(Reader);
//TODO: maybe we have alsways just 1 faces and 1 geometry and always in this order. this loop will only work correct, wenn the order
//of faces and geometry changed, and not if we habe more than one of one
@ -149,7 +164,7 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
{
throw new ImportErrorException("Submesh has quads, only traingles are supported!");
}
FaceList.push_back(NewFace);
theSubMesh.FaceList.push_back(NewFace);
}
}//end of faces
@ -166,13 +181,13 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
{
throw new ImportErrorException("vertexbuffer node is not first in geometry node!");
}
HasPositions=GetAttribute<bool>(Reader, "positions");
HasNormals=GetAttribute<bool>(Reader, "normals");
theSubMesh.HasPositions=GetAttribute<bool>(Reader, "positions");
theSubMesh.HasNormals=GetAttribute<bool>(Reader, "normals");
if(!Reader->getAttributeValue("texture_coords"))//we can have 1 or 0 uv channels, and if the mesh has no uvs, it also doesn't have the attribute
NumUvs=0;
theSubMesh.NumUvs=0;
else
NumUvs=GetAttribute<int>(Reader, "texture_coords");
if(NumUvs>1)
theSubMesh.NumUvs=GetAttribute<int>(Reader, "texture_coords");
if(theSubMesh.NumUvs>1)
throw new ImportErrorException("too many texcoords (just 1 supported!)");
//read all the vertices:
@ -182,35 +197,35 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
//read all vertex attributes:
//Position
if(HasPositions)
if(theSubMesh.HasPositions)
{
XmlRead(Reader);
aiVector3D NewPos;
NewPos.x=GetAttribute<float>(Reader, "x");
NewPos.y=GetAttribute<float>(Reader, "y");
NewPos.z=GetAttribute<float>(Reader, "z");
Positions.push_back(NewPos);
theSubMesh.Positions.push_back(NewPos);
}
//Normal
if(HasNormals)
if(theSubMesh.HasNormals)
{
XmlRead(Reader);
aiVector3D NewNormal;
NewNormal.x=GetAttribute<float>(Reader, "x");
NewNormal.y=GetAttribute<float>(Reader, "y");
NewNormal.z=GetAttribute<float>(Reader, "z");
Normals.push_back(NewNormal);
theSubMesh.Normals.push_back(NewNormal);
}
//Uv:
if(1==NumUvs)
if(1==theSubMesh.NumUvs)
{
XmlRead(Reader);
aiVector3D NewUv;
NewUv.x=GetAttribute<float>(Reader, "u");
NewUv.y=GetAttribute<float>(Reader, "v")*(-1)+1;//flip the uv vertikal, blender exports them so!
Uvs.push_back(NewUv);
theSubMesh.Uvs.push_back(NewUv);
}
XmlRead(Reader);
}
@ -218,126 +233,168 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
}//end of "geometry
else if(string(Reader->getNodeName())=="boneassignments")
{
Weights.resize(Positions.size());
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");
theSubMesh.BonesUsed=max(theSubMesh.BonesUsed, NewWeight.BoneId+1);//calculate the number of bones used (this is the highest id +1 becuase bone ids start at 0)
Weights[VertexId].push_back(NewWeight);
theSubMesh.Weights[VertexId].push_back(NewWeight);
//XmlRead(Reader);//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!!!
}
}//end of boneassignments
}
DefaultLogger::get()->debug(str(format("Positionen: %1% Normale: %2% TexCoords: %3%") % Positions.size() % Normals.size() % Uvs.size()));
DefaultLogger::get()->debug(str(format("Positionen: %1% Normale: %2% TexCoords: %3%") % theSubMesh.Positions.size() % theSubMesh.Normals.size() % theSubMesh.Uvs.size()));
DefaultLogger::get()->warn(Reader->getNodeName());
//---------------Make all Vertexes unique: (this is required by assimp)-----------------------
vector<Face> UniqueFaceList(FaceList.size());
vector<aiVector3D> UniquePositions(FaceList.size()*3);//*3 because each face consits of 3 vertexes, because we only support triangles^^
vector<aiVector3D> UniqueNormals(FaceList.size()*3);
vector<aiVector3D> UniqueUvs(FaceList.size()*3);
vector< vector<Weight> > UniqueWeights(FaceList.size()*3);
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> UniqueUvs(UniqueVertexCount);
vector< vector<Weight> > UniqueWeights(UniqueVertexCount);
for(unsigned int i=0; i<FaceList.size(); ++i)
for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
{
UniquePositions[3*i+0]=Positions[FaceList[i].VertexIndices[0]];
UniquePositions[3*i+1]=Positions[FaceList[i].VertexIndices[1]];
UniquePositions[3*i+2]=Positions[FaceList[i].VertexIndices[2]];
//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];
UniqueNormals[3*i+0]=Normals[FaceList[i].VertexIndices[0]];
UniqueNormals[3*i+1]=Normals[FaceList[i].VertexIndices[1]];
UniqueNormals[3*i+2]=Normals[FaceList[i].VertexIndices[2]];
UniquePositions[3*i+0]=theSubMesh.Positions[Vertex1];
UniquePositions[3*i+1]=theSubMesh.Positions[Vertex2];
UniquePositions[3*i+2]=theSubMesh.Positions[Vertex3];
if(1==NumUvs)
UniqueNormals[3*i+0]=theSubMesh.Normals[Vertex1];
UniqueNormals[3*i+1]=theSubMesh.Normals[Vertex2];
UniqueNormals[3*i+2]=theSubMesh.Normals[Vertex3];
if(1==theSubMesh.NumUvs)
{
UniqueUvs[3*i+0]=Uvs[FaceList[i].VertexIndices[0]];
UniqueUvs[3*i+1]=Uvs[FaceList[i].VertexIndices[1]];
UniqueUvs[3*i+2]=Uvs[FaceList[i].VertexIndices[2]];
UniqueUvs[3*i+0]=theSubMesh.Uvs[Vertex1];
UniqueUvs[3*i+1]=theSubMesh.Uvs[Vertex2];
UniqueUvs[3*i+2]=theSubMesh.Uvs[Vertex3];
}
UniqueWeights[3*i+0]=UniqueWeights[FaceList[i].VertexIndices[0]];
UniqueWeights[3*i+1]=UniqueWeights[FaceList[i].VertexIndices[1]];
UniqueWeights[3*i+2]=UniqueWeights[FaceList[i].VertexIndices[2]];
UniqueWeights[3*i+0]=theSubMesh.Weights[Vertex1];
UniqueWeights[3*i+1]=theSubMesh.Weights[Vertex2];
UniqueWeights[3*i+2]=theSubMesh.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;
}
//_________________________________________________________________________________________
//----------------Load the Material:-------------------------------
aiMaterial* MeshMat=LoadMaterial(theSubMesh.MaterialName);
//_________________________________________________________________
//now we have the unique datas, but want them in the SubMesh, so we swap all the containers:
theSubMesh.FaceList.swap(UniqueFaceList);
theSubMesh.Positions.swap(UniquePositions);
theSubMesh.Normals.swap(UniqueNormals);
theSubMesh.Uvs.swap(UniqueUvs);
theSubMesh.Weights.swap(UniqueWeights);
}
void OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vector<Bone>& Bones)
{
//Mesh is fully loaded, copy it into the aiScene:
if(m_CurrentScene->mNumMeshes!=0)
throw new ImportErrorException("Currently only one mesh per File is allowed!!");
//---------------------Create the aiMesh:-----------------------
aiMesh* NewAiMesh=new aiMesh();
//Positions
NewAiMesh->mVertices=new aiVector3D[UniquePositions.size()];
memcpy(NewAiMesh->mVertices, &UniquePositions[0], UniquePositions.size()*sizeof(aiVector3D));
NewAiMesh->mNumVertices=UniquePositions.size();
//Normals
NewAiMesh->mNormals=new aiVector3D[UniqueNormals.size()];
memcpy(NewAiMesh->mNormals, &UniqueNormals[0], UniqueNormals.size()*sizeof(aiVector3D));
//Uvs
if(0!=NumUvs)
{
NewAiMesh->mNumUVComponents[0]=2;
NewAiMesh->mTextureCoords[0]= new aiVector3D[UniqueUvs.size()];
memcpy(NewAiMesh->mTextureCoords[0], &UniqueUvs[0], UniqueUvs.size()*sizeof(aiVector3D));
}
//Bones
/*NewAiMesh->mNumBones=UniqueWeights.size();
NewAiMesh->mBones=new aiBone*[UniqueWeights.size()];
for(un*/
//Faces
NewAiMesh->mFaces=new aiFace[UniqueFaceList.size()];
for(unsigned int i=0; i<UniqueFaceList.size(); ++i)
{
NewAiMesh->mFaces[i].mNumIndices=3;
NewAiMesh->mFaces[i].mIndices=new unsigned int[3];
NewAiMesh->mFaces[i].mIndices[0]=UniqueFaceList[i].VertexIndices[0];
NewAiMesh->mFaces[i].mIndices[1]=UniqueFaceList[i].VertexIndices[1];
NewAiMesh->mFaces[i].mIndices[2]=UniqueFaceList[i].VertexIndices[2];
}
NewAiMesh->mNumFaces=UniqueFaceList.size();
//Set the Material:
NewAiMesh->mMaterialIndex=0;
if(m_CurrentScene->mMaterials)
throw new ImportErrorException("only 1 material supported at this time!");
m_CurrentScene->mMaterials=new aiMaterial*[1];
m_CurrentScene->mNumMaterials=1;
m_CurrentScene->mMaterials[0]=MeshMat;
//_____________________________________________________________________________
//Attach the mesh to the scene:
m_CurrentScene->mNumMeshes=1;
m_CurrentScene->mMeshes=new aiMesh*;
m_CurrentScene->mMeshes[0]=NewAiMesh;
//Positions
NewAiMesh->mVertices=new aiVector3D[theSubMesh.Positions.size()];
memcpy(NewAiMesh->mVertices, &theSubMesh.Positions[0], theSubMesh.Positions.size()*sizeof(aiVector3D));
NewAiMesh->mNumVertices=theSubMesh.Positions.size();
//Normals
NewAiMesh->mNormals=new aiVector3D[theSubMesh.Normals.size()];
memcpy(NewAiMesh->mNormals, &theSubMesh.Normals[0], theSubMesh.Normals.size()*sizeof(aiVector3D));
//Uvs
if(0!=theSubMesh.NumUvs)
{
NewAiMesh->mNumUVComponents[0]=2;
NewAiMesh->mTextureCoords[0]= new aiVector3D[theSubMesh.Uvs.size()];
memcpy(NewAiMesh->mTextureCoords[0], &theSubMesh.Uvs[0], theSubMesh.Uvs.size()*sizeof(aiVector3D));
}
//---------------------------------------- Bones --------------------------------------------
//Copy the weights in in Bone-Vertices Struktur
//(we have them in a Vertex-Bones Struktur, this is much easier for making them unique, which is required by assimp
vector< vector<aiVertexWeight> > aiWeights(theSubMesh.BonesUsed);//now the outer list are the bones, and the inner vector the vertices
for(unsigned int VertexId=0; VertexId<theSubMesh.Weights.size(); ++VertexId)//iterate over all vertices
{
for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
{
aiVertexWeight NewWeight;
NewWeight.mVertexId=VertexId;//the current Vertex, we can't use the Id form the submehs weights, because they are bone id's
NewWeight.mWeight=theSubMesh.Weights[VertexId][BoneId].Value;
aiWeights[theSubMesh.Weights[VertexId][BoneId].BoneId].push_back(NewWeight);
}
}
vector<aiBone*> aiBones;
aiBones.reserve(theSubMesh.BonesUsed);//the vector might be smaller, because there might be empty bones (bones that are not attached to any vertex)
//create all the bones and fill them with informations
for(unsigned int i=0; i<theSubMesh.BonesUsed; ++i)
{
if(aiWeights[i].size()>0)
{
aiBone* NewBone=new aiBone();
NewBone->mNumWeights=aiWeights[i].size();
NewBone->mWeights=new aiVertexWeight[aiWeights[i].size()];
memcpy(NewBone->mWeights, &(aiWeights[i][0]), sizeof(aiVertexWeight)*aiWeights[i].size());
NewBone->mName=Bones[i].Name;//The bone list should be sorted after its ids, this was done in LoadSkeleton
NewBone->mOffsetMatrix=aiMatrix4x4(Bones[i].WorldToBoneSpace).Inverse();//we suggest, that the mesh space is the world space!
aiBones.push_back(NewBone);
}
}
NewAiMesh->mNumBones=aiBones.size();
NewAiMesh->mBones=new aiBone* [aiBones.size()];
memcpy(NewAiMesh->mBones, &(aiBones[0]), aiBones.size()*sizeof(aiBone*));
//______________________________________________________________________________________________________
//Faces
NewAiMesh->mFaces=new aiFace[theSubMesh.FaceList.size()];
for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
{
NewAiMesh->mFaces[i].mNumIndices=3;
NewAiMesh->mFaces[i].mIndices=new unsigned int[3];
NewAiMesh->mFaces[i].mIndices[0]=theSubMesh.FaceList[i].VertexIndices[0];
NewAiMesh->mFaces[i].mIndices[1]=theSubMesh.FaceList[i].VertexIndices[1];
NewAiMesh->mFaces[i].mIndices[2]=theSubMesh.FaceList[i].VertexIndices[2];
}
NewAiMesh->mNumFaces=theSubMesh.FaceList.size();
//Link the material:
NewAiMesh->mMaterialIndex=theSubMesh.MaterialIndex;//the index is set by the function who called ReadSubMesh
}
aiMaterial* OgreImporter::LoadMaterial(std::string MaterialName)
aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName)
{
MaterialHelper *NewMaterial=new MaterialHelper();
@ -501,7 +558,8 @@ aiMaterial* OgreImporter::LoadMaterial(std::string MaterialName)
return NewMaterial;
}
void OgreImporter::LoadSkeleton(std::string FileName)
void OgreImporter::LoadSkeleton(std::string FileName, vector<Bone> &Bones, vector<Animation> &Animations)
{
//most likely the skeleton file will only end with .skeleton
//But this is a xml reader, so we need: .skeleton.xml
@ -520,9 +578,6 @@ void OgreImporter::LoadSkeleton(std::string FileName)
if(!SkeletonFile)
throw new ImportErrorException(string("Failed to create XML Reader for ")+FileName);
//Variables to store the data from the skeleton file:
vector<Bone> Bones;
//Quick note: Whoever read this should know this one thing: irrXml fucking sucks!!!
XmlRead(SkeletonFile);
@ -618,11 +673,19 @@ void OgreImporter::LoadSkeleton(std::string FileName)
}
//_____________________________________________________________________________
//--------- Calculate the WorldToBoneSpace Matrix recursivly for all bones: ------------------
BOOST_FOREACH(Bone theBone, Bones)
{
if(-1==theBone.ParentId) //the bone is a root bone
{
theBone.CalculateWorldToBoneSpaceMatrix(Bones);
}
}
//_______________________________________________________________________
//---------------------------load animations-----------------------------
vector<Animation> Animations;
if(string("animations")==SkeletonFile->getNodeName())//animations are optional values
{
DefaultLogger::get()->debug("Loading Animations");
@ -697,10 +760,11 @@ void OgreImporter::LoadSkeleton(std::string FileName)
}
//_____________________________________________________________________________
}
void OgreImporter::CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations)
{
//-----------------skeleton is completly loaded, now but it in the assimp scene:-------------------------------
if(!m_CurrentScene->mRootNode)
@ -708,7 +772,7 @@ void OgreImporter::LoadSkeleton(std::string FileName)
if(0!=m_CurrentScene->mRootNode->mNumChildren)
throw new ImportErrorException("Root Node already has childnodes!");
//--------------Creatre the assimp bone hierarchy-----------------
//--------------Createt the assimp bone hierarchy-----------------
DefaultLogger::get()->debug("Root Bones");
vector<aiNode*> RootBoneNodes;
BOOST_FOREACH(Bone theBone, Bones)
@ -735,7 +799,7 @@ void OgreImporter::LoadSkeleton(std::string FileName)
aiAnimation* NewAnimation=new aiAnimation();
NewAnimation->mName=Animations[i].Name;
NewAnimation->mDuration=Animations[i].Length;
NewAnimation->mTicksPerSecond=0.05f;
NewAnimation->mTicksPerSecond=1.0f;
//Create all tracks in this animation
NewAnimation->mNumChannels=Animations[i].Tracks.size();
@ -778,8 +842,7 @@ void OgreImporter::LoadSkeleton(std::string FileName)
aiNode* CreateAiNodeFromBone(int BoneId, std::vector<Bone> Bones, aiNode* ParentNode)
aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode)
{
//----Create the node for this bone and set its values-----
aiNode* NewNode=new aiNode(Bones[BoneId].Name);
@ -794,7 +857,7 @@ aiNode* CreateAiNodeFromBone(int BoneId, std::vector<Bone> Bones, aiNode* Parent
//__________________________________________________________
//----recursivly create all children Nodes:------
//---------- recursivly create all children Nodes: ----------
NewNode->mNumChildren=Bones[BoneId].Children.size();
NewNode->mChildren=new aiNode*[Bones[BoneId].Children.size()];
for(unsigned int i=0; i<Bones[BoneId].Children.size(); ++i)
@ -808,6 +871,31 @@ aiNode* CreateAiNodeFromBone(int BoneId, std::vector<Bone> Bones, aiNode* Parent
}
void Bone::CalculateWorldToBoneSpaceMatrix(vector<Bone> &Bones)
{
//Calculate the matrix for this bone:
if(-1==ParentId)
{
WorldToBoneSpace= aiMatrix4x4::Translation(Position, aiMatrix4x4())
* aiMatrix4x4::Rotation(RotationAngle, RotationAxis, aiMatrix4x4())
;
}
else
{
WorldToBoneSpace= Bones[ParentId].WorldToBoneSpace
* aiMatrix4x4::Translation(Position, aiMatrix4x4())
* aiMatrix4x4::Rotation(RotationAngle, RotationAxis, aiMatrix4x4())
;
}
//and recursivly for all children:
BOOST_FOREACH(int theChildren, Children)
{
Bones[theChildren].CalculateWorldToBoneSpaceMatrix(Bones);
}
}
}//namespace Ogre
}//namespace Assimp

View File

@ -2,20 +2,19 @@
#include <vector>
#include "OgreXmlHelper.h"
#include "irrXMLWrapper.h"
#include "fast_atof.h"
namespace Assimp
{
namespace Ogre
{
typedef irr::io::IrrXMLReader XmlReader;
//Forward declarations:
struct SubMesh;
struct Face;
struct Weight;
struct SubMesh;
struct Bone;
struct Animation;
struct Track;
@ -32,10 +31,15 @@ public:
private:
///Helper Functions to read parts of the XML File
/** @param Filename We need this to check for a material File with the same name.*/
void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);
aiMaterial* LoadMaterial(std::string MaterialName);
void LoadSkeleton(std::string FileName);
void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);//the submesh reference is the result value
void LoadSkeleton(std::string FileName, std::vector<Bone> &Bones, std::vector<Animation> &Animations);///< writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it!
void CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector<Bone>& Bones);
void CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
aiMaterial* LoadMaterial(const std::string MaterialName);
///Recursivly creates a filled aiNode from a given root bone
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;
@ -44,71 +48,21 @@ private:
aiScene *m_CurrentScene;
};
///A submesh from Ogre
struct SubMesh
{
std::string Name;
std::string MaterialName;
std::vector<Face> FaceList;
std::vector<aiVector3D> Positions; bool HasPositions;
std::vector<aiVector3D> Normals; bool HasNormals;
std::vector<aiVector3D> Uvs; unsigned int NumUvs;//nearly always 2d, but assimp has always 3d texcoords
std::vector< std::vector<Weight> > Weights;//a list of bones for each vertex
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)
//------------Helper Funktion to Get a Attribute Save---------------
template<typename t> inline t GetAttribute(XmlReader* Reader, std::string Name)
{
throw std::exception("unimplemented Funtcion used!");
return t();
}
template<> inline int GetAttribute<int>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
return atoi(Value);
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
template<> inline float GetAttribute<float>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
return fast_atof(Value);
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
template<> inline std::string GetAttribute<std::string>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
return std::string(Value);
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
template<> inline bool GetAttribute<bool>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
{
if(Value==std::string("true"))
return true;
else if(Value==std::string("false"))
return false;
else
throw new ImportErrorException(std::string("Bool value has invalid value: "+Name+" / "+Value+" / "+Reader->getNodeName()));
}
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
//__________________________________________________________________
inline bool XmlRead(XmlReader* Reader)
{
do
{
if(!Reader->read())
return false;
}
while(Reader->getNodeType()!=irr::io::EXN_ELEMENT);
return true;
}
SubMesh(): HasPositions(false), HasNormals(false), NumUvs(0), MaterialIndex(-1), BonesUsed(0) {}//initialize everything
};
///For the moment just triangles, no other polygon types!
struct Face
@ -116,22 +70,21 @@ struct Face
unsigned int VertexIndices[3];
};
struct BoneAssignment
{
unsigned int BoneId;//this is, what we get from ogre
std::string BoneName;//this is, what we need for assimp
};
///for a vertex->bone structur
struct Weight
{
unsigned int BoneId;
float Value;
};
/// Helper Class to describe a complete SubMesh
struct SubMesh
{
std::string Name;
std::string MaterialName;
std::vector<Face> Faces;
};
/// Helper Class to describe an ogre-bone
/// Helper Class to describe an ogre-bone for the skeleton:
/** All Id's are signed ints, because than we have -1 as a simple INVALID_ID Value (we start from 0 so 0 is a valid bone ID!*/
struct Bone
{
@ -142,6 +95,7 @@ struct Bone
float RotationAngle;
aiVector3D RotationAxis;
std::vector<int> Children;
aiMatrix4x4 WorldToBoneSpace;
///ctor
Bone(): Id(-1), ParentId(-1), RotationAngle(0.0f) {}
@ -151,11 +105,11 @@ struct Bone
///this operator is needed to find a bone by its name in a vector<Bone>
bool operator==(const std::string& rval) const
{return Name==rval; }
void CalculateWorldToBoneSpaceMatrix(std::vector<Bone>& Bones);
};
///Recursivly creates a filled aiNode from a given root bone
aiNode* CreateAiNodeFromBone(int BoneId, std::vector<Bone> Bones, aiNode* ParentNode);
///Describes an Ogre Animation

View File

@ -0,0 +1,76 @@
#include "irrXMLWrapper.h"
#include "fast_atof.h"
namespace Assimp
{
namespace Ogre
{
typedef irr::io::IrrXMLReader XmlReader;
//------------Helper Funktion to Get a Attribute Save---------------
template<typename t> inline t GetAttribute(XmlReader* Reader, std::string Name)
{
throw std::exception("unimplemented Funtcion used!");
return t();
}
template<> inline int GetAttribute<int>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
return atoi(Value);
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
template<> inline float GetAttribute<float>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
return fast_atof(Value);
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
template<> inline std::string GetAttribute<std::string>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
return std::string(Value);
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
template<> inline bool GetAttribute<bool>(XmlReader* Reader, std::string Name)
{
const char* Value=Reader->getAttributeValue(Name.c_str());
if(Value)
{
if(Value==std::string("true"))
return true;
else if(Value==std::string("false"))
return false;
else
throw new ImportErrorException(std::string("Bool value has invalid value: "+Name+" / "+Value+" / "+Reader->getNodeName()));
}
else
throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
}
//__________________________________________________________________
inline bool XmlRead(XmlReader* Reader)
{
do
{
if(!Reader->read())
return false;
}
while(Reader->getNodeType()!=irr::io::EXN_ELEMENT);
return true;
}
}//namespace Ogre
}//namespace Assimp

View File

@ -1461,5 +1461,6 @@ Material: The right material in the file will be searched, the importer should w
have 1 technique and 1 pass in this technique. From there, the texturename (for 1 color- and 1 normalmap) will be loaded. Also, the
materialname will be set.
Skeleton: Skeleton with Bone hierarchie, names and transformations, but no animations.
Skeleton: Skeleton with Bone hierarchy (Position and Rotation, but no Scaling in the skeleton is supported), names and transformations,
animations with rotation, translation and scaling keys.
*/

View File

@ -1946,6 +1946,10 @@
RelativePath="..\..\code\OgreImporter.h"
>
</File>
<File
RelativePath="..\..\code\OgreXmlHelper.h"
>
</File>
</Filter>
<Filter
Name="collada"

View File

@ -1954,6 +1954,10 @@
RelativePath="..\..\code\OgreImporter.h"
>
</File>
<File
RelativePath="..\..\code\OgreXmlHelper.h"
>
</File>
</Filter>
</Filter>
<Filter