- better support for OgreXmlConverter generated files

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1177 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/5/head
jonathanklein 2012-02-20 10:27:27 +00:00
parent 37fb338c1f
commit 521088e134
7 changed files with 566 additions and 372 deletions

View File

@ -326,7 +326,8 @@ SET( Obj_SRCS
SOURCE_GROUP( Obj FILES ${Obj_SRCS}) SOURCE_GROUP( Obj FILES ${Obj_SRCS})
SET( Ogre_SRCS SET( Ogre_SRCS
OgreImporter.h OgreImporter.hpp
OgreXmlHelper.hpp
OgreImporter.cpp OgreImporter.cpp
OgreImporterMaterial.cpp OgreImporterMaterial.cpp
) )

View File

@ -140,7 +140,7 @@ corresponding preprocessor flag to selectively disable formats.
# include "LWSLoader.h" # include "LWSLoader.h"
#endif #endif
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
# include "OgreImporter.h" # include "OgreImporter.hpp"
#endif #endif
#ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
# include "MS3DLoader.h" # include "MS3DLoader.h"

View File

@ -54,7 +54,7 @@ using namespace std;
#include "TinyFormatter.h" #include "TinyFormatter.h"
#include "OgreImporter.h" #include "OgreImporter.hpp"
#include "irrXMLWrapper.h" #include "irrXMLWrapper.h"
@ -80,7 +80,6 @@ bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandle
} }
void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler) void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler)
{ {
m_CurrentFilename=pFile; m_CurrentFilename=pFile;
@ -198,7 +197,6 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
} }
void OgreImporter::GetExtensionList(std::set<std::string>& extensions) void OgreImporter::GetExtensionList(std::set<std::string>& extensions)
{ {
extensions.insert("mesh.xml"); extensions.insert("mesh.xml");
@ -210,6 +208,7 @@ void OgreImporter::SetupProperties(const Importer* pImp)
m_MaterialLibFilename=pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material"); m_MaterialLibFilename=pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material");
} }
void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader) void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
{ {
XmlRead(Reader); XmlRead(Reader);
@ -242,63 +241,28 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
{ {
//some info logging: //some info logging:
unsigned int NumVertices=GetAttribute<int>(Reader, "vertexcount"); unsigned int NumVertices=GetAttribute<int>(Reader, "vertexcount");
ostringstream ss; ss<<"VertexCount: "<<NumVertices; ostringstream ss; ss<<"VertexCount: " << NumVertices;
DefaultLogger::get()->debug(ss.str()); DefaultLogger::get()->debug(ss.str());
//General Informations about vertices //General Informations about vertices
XmlRead(Reader); XmlRead(Reader);
if(!(Reader->getNodeName()==string("vertexbuffer"))) while(Reader->getNodeName()==string("vertexbuffer"))
{ {
throw DeadlyImportError("vertexbuffer node is not first in geometry node!"); ReadVertexBuffer(theSubMesh, Reader, NumVertices);
} }
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
theSubMesh.NumUvs=0;
else
theSubMesh.NumUvs=GetAttribute<int>(Reader, "texture_coords");
if(theSubMesh.NumUvs>1)
throw DeadlyImportError("too many texcoords (just 1 supported!)");
//read all the vertices: //some error checking on the loaded data
XmlRead(Reader); if(!theSubMesh.HasPositions)
while(Reader->getNodeName()==string("vertex")) throw DeadlyImportError("No positions could be loaded!");
{
//read all vertex attributes:
//Position if(theSubMesh.HasNormals && theSubMesh.Normals.size() != NumVertices)
if(theSubMesh.HasPositions) throw DeadlyImportError("Wrong Number of Normals loaded!");
{
XmlRead(Reader);
aiVector3D NewPos;
NewPos.x=GetAttribute<float>(Reader, "x");
NewPos.y=GetAttribute<float>(Reader, "y");
NewPos.z=GetAttribute<float>(Reader, "z");
theSubMesh.Positions.push_back(NewPos);
}
//Normal
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");
theSubMesh.Normals.push_back(NewNormal);
}
//Uv: if(theSubMesh.HasTangents && theSubMesh.Tangents.size() != NumVertices)
if(1==theSubMesh.NumUvs) throw DeadlyImportError("Wrong Number of Tangents loaded!");
{
XmlRead(Reader); if(theSubMesh.NumUvs==1 && theSubMesh.Uvs.size() != NumVertices)
aiVector3D NewUv; throw DeadlyImportError("Wrong Number of Uvs loaded!");
NewUv.x=GetAttribute<float>(Reader, "u");
NewUv.y=GetAttribute<float>(Reader, "v")*(-1)+1;//flip the uv vertikal, blender exports them so!
theSubMesh.Uvs.push_back(NewUv);
}
XmlRead(Reader);
}
}//end of "geometry }//end of "geometry
@ -324,7 +288,8 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
DefaultLogger::get()->debug((Formatter::format(), DefaultLogger::get()->debug((Formatter::format(),
"Positionen: ",theSubMesh.Positions.size(), "Positionen: ",theSubMesh.Positions.size(),
" Normale: ",theSubMesh.Normals.size(), " Normale: ",theSubMesh.Normals.size(),
" TexCoords: ",theSubMesh.Uvs.size() " TexCoords: ",theSubMesh.Uvs.size(),
" Tantents: ",theSubMesh.Tangents.size()
)); ));
DefaultLogger::get()->warn(Reader->getNodeName()); DefaultLogger::get()->warn(Reader->getNodeName());
@ -335,6 +300,7 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
unsigned int UniqueVertexCount=theSubMesh.FaceList.size()*3;//*3 because each face consists of 3 vertexes, because we only support triangles^^ 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> UniquePositions(UniqueVertexCount);
vector<aiVector3D> UniqueNormals(UniqueVertexCount); vector<aiVector3D> UniqueNormals(UniqueVertexCount);
vector<aiVector3D> UniqueTangents(UniqueVertexCount);
vector<aiVector3D> UniqueUvs(UniqueVertexCount); vector<aiVector3D> UniqueUvs(UniqueVertexCount);
vector< vector<Weight> > UniqueWeights((theSubMesh.Weights.size() ? UniqueVertexCount : 0)); vector< vector<Weight> > UniqueWeights((theSubMesh.Weights.size() ? UniqueVertexCount : 0));
@ -349,9 +315,19 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
UniquePositions[3*i+1]=theSubMesh.Positions[Vertex2]; UniquePositions[3*i+1]=theSubMesh.Positions[Vertex2];
UniquePositions[3*i+2]=theSubMesh.Positions[Vertex3]; UniquePositions[3*i+2]=theSubMesh.Positions[Vertex3];
UniqueNormals[3*i+0]=theSubMesh.Normals[Vertex1]; if(theSubMesh.HasNormals)
UniqueNormals[3*i+1]=theSubMesh.Normals[Vertex2]; {
UniqueNormals[3*i+2]=theSubMesh.Normals[Vertex3]; UniqueNormals[3*i+0]=theSubMesh.Normals[Vertex1];
UniqueNormals[3*i+1]=theSubMesh.Normals[Vertex2];
UniqueNormals[3*i+2]=theSubMesh.Normals[Vertex3];
}
if(theSubMesh.HasTangents)
{
UniqueTangents[3*i+0]=theSubMesh.Tangents[Vertex1];
UniqueTangents[3*i+1]=theSubMesh.Tangents[Vertex2];
UniqueTangents[3*i+2]=theSubMesh.Tangents[Vertex3];
}
if(1==theSubMesh.NumUvs) if(1==theSubMesh.NumUvs)
{ {
@ -360,7 +336,8 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
UniqueUvs[3*i+2]=theSubMesh.Uvs[Vertex3]; UniqueUvs[3*i+2]=theSubMesh.Uvs[Vertex3];
} }
if (theSubMesh.Weights.size()) { if(theSubMesh.Weights.size())
{
UniqueWeights[3*i+0]=theSubMesh.Weights[Vertex1]; UniqueWeights[3*i+0]=theSubMesh.Weights[Vertex1];
UniqueWeights[3*i+1]=theSubMesh.Weights[Vertex2]; UniqueWeights[3*i+1]=theSubMesh.Weights[Vertex2];
UniqueWeights[3*i+2]=theSubMesh.Weights[Vertex3]; UniqueWeights[3*i+2]=theSubMesh.Weights[Vertex3];
@ -374,9 +351,11 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
//_________________________________________________________________________________________ //_________________________________________________________________________________________
//now we have the unique datas, but want them in the SubMesh, so we swap all the containers: //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.FaceList.swap(UniqueFaceList);
theSubMesh.Positions.swap(UniquePositions); theSubMesh.Positions.swap(UniquePositions);
theSubMesh.Normals.swap(UniqueNormals); theSubMesh.Normals.swap(UniqueNormals);
theSubMesh.Tangents.swap(UniqueTangents);
theSubMesh.Uvs.swap(UniqueUvs); theSubMesh.Uvs.swap(UniqueUvs);
theSubMesh.Weights.swap(UniqueWeights); theSubMesh.Weights.swap(UniqueWeights);
@ -405,6 +384,119 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
} }
void OgreImporter::ReadVertexBuffer(SubMesh &theSubMesh, XmlReader *Reader, unsigned int NumVertices)
{
DefaultLogger::get()->debug("new Vertex Buffer");
bool ReadPositions=false;
bool ReadNormals=false;
bool ReadTangents=false;
bool ReadUvs=false;
//-------------------- check, what we need to read: --------------------------------
if(Reader->getAttributeValue("positions") && GetAttribute<bool>(Reader, "positions"))
{
ReadPositions=theSubMesh.HasPositions=true;
theSubMesh.Positions.reserve(NumVertices);
DefaultLogger::get()->debug("reading positions");
}
if(Reader->getAttributeValue("normals") && GetAttribute<bool>(Reader, "normals"))
{
ReadNormals=theSubMesh.HasNormals=true;
theSubMesh.Normals.reserve(NumVertices);
DefaultLogger::get()->debug("reading positions");
}
if(Reader->getAttributeValue("tangents") && GetAttribute<bool>(Reader, "tangents"))
{
ReadTangents=theSubMesh.HasTangents=true;
theSubMesh.Tangents.reserve(NumVertices);
DefaultLogger::get()->debug("reading positions");
}
//we can have 1 or 0 uv channels, and if the mesh has no uvs, it also doesn't have the attribute
if(!Reader->getAttributeValue("texture_coords"))
theSubMesh.NumUvs=0;
else
{
ReadUvs=theSubMesh.NumUvs=GetAttribute<int>(Reader, "texture_coords");
theSubMesh.Uvs.reserve(NumVertices);
DefaultLogger::get()->debug("reading texture coords");
}
if(theSubMesh.NumUvs>1)
DefaultLogger::get()->warn("too many texcoords (just 1 supported!), no texcoords will be loaded!");
//___________________________________________________________________
//check if we will load anything
if(!(ReadPositions || ReadNormals || ReadTangents || ReadUvs))
DefaultLogger::get()->warn("vertexbuffer seams to be empty!");
//read all the vertices:
XmlRead(Reader);
/*it might happen, that we have more than one attribute per vertex (they are not splitted to different buffers)
so the break condition is a bit tricky (well, IrrXML just sucks :( )*/
while(Reader->getNodeName()==string("vertex")
||Reader->getNodeName()==string("position")
||Reader->getNodeName()==string("normal")
||Reader->getNodeName()==string("tangent")
||Reader->getNodeName()==string("texcoord"))
{
if(Reader->getNodeName()==string("vertex"))
XmlRead(Reader);//Read an attribute tag
//Position
if(ReadPositions && Reader->getNodeName()==string("position"))
{
aiVector3D NewPos;
NewPos.x=GetAttribute<float>(Reader, "x");
NewPos.y=GetAttribute<float>(Reader, "y");
NewPos.z=GetAttribute<float>(Reader, "z");
theSubMesh.Positions.push_back(NewPos);
}
//Normal
else if(ReadNormals && Reader->getNodeName()==string("normal"))
{
aiVector3D NewNormal;
NewNormal.x=GetAttribute<float>(Reader, "x");
NewNormal.y=GetAttribute<float>(Reader, "y");
NewNormal.z=GetAttribute<float>(Reader, "z");
theSubMesh.Normals.push_back(NewNormal);
}
//Tangent
else if(ReadTangents && Reader->getNodeName()==string("tangent"))
{
aiVector3D NewTangent;
NewTangent.x=GetAttribute<float>(Reader, "x");
NewTangent.y=GetAttribute<float>(Reader, "y");
NewTangent.z=GetAttribute<float>(Reader, "z");
theSubMesh.Tangents.push_back(NewTangent);
}
//Uv:
else if(ReadUvs && Reader->getNodeName()==string("texcoord"))
{
aiVector3D NewUv;
NewUv.x=GetAttribute<float>(Reader, "u");
NewUv.y=GetAttribute<float>(Reader, "v")*(-1)+1;//flip the uv vertikal, blender exports them so!
theSubMesh.Uvs.push_back(NewUv);
}
//Attribute could not be read
else
{
DefaultLogger::get()->warn(string("Attribute was not read: ")+Reader->getNodeName());
}
XmlRead(Reader);//Read the Vertex tag
}
}
aiMesh* OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vector<Bone>& Bones) const aiMesh* OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vector<Bone>& Bones) const
{ {
const aiScene* const m_CurrentScene=this->m_CurrentScene;//make sure, that we can access but not change the scene const aiScene* const m_CurrentScene=this->m_CurrentScene;//make sure, that we can access but not change the scene
@ -418,8 +510,18 @@ aiMesh* OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vecto
NewAiMesh->mNumVertices=theSubMesh.Positions.size(); NewAiMesh->mNumVertices=theSubMesh.Positions.size();
//Normals //Normals
NewAiMesh->mNormals=new aiVector3D[theSubMesh.Normals.size()]; if(theSubMesh.HasNormals)
memcpy(NewAiMesh->mNormals, &theSubMesh.Normals[0], theSubMesh.Normals.size()*sizeof(aiVector3D)); {
NewAiMesh->mNormals=new aiVector3D[theSubMesh.Normals.size()];
memcpy(NewAiMesh->mNormals, &theSubMesh.Normals[0], theSubMesh.Normals.size()*sizeof(aiVector3D));
}
//Tangents
if(theSubMesh.HasTangents)
{
NewAiMesh->mTangents=new aiVector3D[theSubMesh.Tangents.size()];
memcpy(NewAiMesh->mTangents, &theSubMesh.Tangents[0], theSubMesh.Tangents.size()*sizeof(aiVector3D));
}
//Uvs //Uvs
if(0!=theSubMesh.NumUvs) if(0!=theSubMesh.NumUvs)
@ -816,12 +918,8 @@ void OgreImporter::PutAnimationsInScene(const std::vector<Bone> &Bones, const st
} }
aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode)
aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode) const
{ {
const aiScene* const m_CurrentScene=this->m_CurrentScene;//make sure, that we can access but not change the scene
(void)m_CurrentScene;
//----Create the node for this bone and set its values----- //----Create the node for this bone and set its values-----
aiNode* NewNode=new aiNode(Bones[BoneId].Name); aiNode* NewNode=new aiNode(Bones[BoneId].Name);
NewNode->mParent=ParentNode; NewNode->mParent=ParentNode;

View File

@ -1,151 +1,159 @@
#include "BaseImporter.h" #include "BaseImporter.h"
#include <vector> #include <vector>
#include "OgreXmlHelper.h" #include "OgreXmlHelper.hpp"
#include "irrXMLWrapper.h" #include "irrXMLWrapper.h"
namespace Assimp namespace Assimp
{ {
namespace Ogre namespace Ogre
{ {
//Forward declarations: //Forward declarations:
struct SubMesh; struct SubMesh;
struct Face; struct Face;
struct Weight; struct Weight;
struct Bone; struct Bone;
struct Animation; struct Animation;
struct Track; struct Track;
struct Keyframe; struct Keyframe;
///The Main Ogre Importer Class ///The Main Ogre Importer Class
class OgreImporter : public BaseImporter class OgreImporter : public BaseImporter
{ {
public: public:
virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
virtual void GetExtensionList(std::set<std::string>& extensions); virtual void GetExtensionList(std::set<std::string>& extensions);
virtual void SetupProperties(const Importer* pImp); virtual void SetupProperties(const Importer* pImp);
private: private:
/// Helper Functions to read parts of the XML File /// Helper Functions to read parts of the XML File
void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);//the submesh reference is the result value void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);//the submesh reference is the result value
/// writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it! /// Reads a single Vertexbuffer and writes its data in the Submesh
void LoadSkeleton(std::string FileName, std::vector<Bone> &Bones, std::vector<Animation> &Animations) const; static void ReadVertexBuffer(SubMesh &theSubMesh, XmlReader *Reader, unsigned int NumVertices);
/// converts the animations in aiAnimations and puts them into the scene /// writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it!
void PutAnimationsInScene(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations); void LoadSkeleton(std::string FileName, std::vector<Bone> &Bones, std::vector<Animation> &Animations) const;
/// uses the bone data to convert a SubMesh into a aiMesh which will be created and returned /// converts the animations in aiAnimations and puts them into the scene
aiMesh* CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector<Bone>& Bones) const; void PutAnimationsInScene(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
//creates the aiskeleton in current scene /// uses the bone data to convert a SubMesh into a aiMesh which will be created and returned
void CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations); aiMesh* CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector<Bone>& Bones) const;
aiMaterial* LoadMaterial(const std::string MaterialName) const; //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
aiNode* CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode) const; aiMaterial* LoadMaterial(const std::string MaterialName) const;
static void ReadTechnique(std::stringstream &ss, aiMaterial* NewMaterial);
//Now we don't have to give theses parameters to all functions
std::string m_CurrentFilename; ///Recursivly creates a filled aiNode from a given root bone
std::string m_MaterialLibFilename; static aiNode* CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode);
IOSystem* m_CurrentIOHandler;
aiScene *m_CurrentScene; //Now we don't have to give theses parameters to all functions
}; std::string m_CurrentFilename;
std::string m_MaterialLibFilename;
///A submesh from Ogre IOSystem* m_CurrentIOHandler;
struct SubMesh aiScene *m_CurrentScene;
{ };
std::string Name;
std::string MaterialName; ///A submesh from Ogre
std::vector<Face> FaceList; struct SubMesh
std::vector<aiVector3D> Positions; bool HasPositions; {
std::vector<aiVector3D> Normals; bool HasNormals; std::string Name;
std::vector<aiVector3D> Uvs; unsigned int NumUvs;//nearly always 2d, but assimp has always 3d texcoords std::string MaterialName;
std::vector< std::vector<Weight> > Weights;//a list of bones for each vertex std::vector<Face> FaceList;
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) std::vector<aiVector3D> Positions; bool HasPositions;
std::vector<aiVector3D> Normals; bool HasNormals;
SubMesh(): HasPositions(false), HasNormals(false), NumUvs(0), MaterialIndex(-1), BonesUsed(0) {}//initialize everything std::vector<aiVector3D> Tangents; bool HasTangents;
}; std::vector<aiVector3D> Uvs; unsigned int NumUvs;//nearly always 2d, but assimp has always 3d texcoords
///For the moment just triangles, no other polygon types! std::vector< std::vector<Weight> > Weights;//a list of bones for each vertex
struct Face 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)
unsigned int VertexIndices[3];
}; SubMesh(): HasPositions(false), HasNormals(false), HasTangents(false),
NumUvs(0), MaterialIndex(-1), BonesUsed(0) {}//initialize everything
struct BoneAssignment };
{
unsigned int BoneId;//this is, what we get from ogre ///For the moment just triangles, no other polygon types!
std::string BoneName;//this is, what we need for assimp struct Face
}; {
unsigned int VertexIndices[3];
///for a vertex->bone structur };
struct Weight
{ struct BoneAssignment
unsigned int BoneId; {
float Value; unsigned int BoneId;//this is, what we get from ogre
}; std::string BoneName;//this is, what we need for assimp
};
/// Helper Class to describe an ogre-bone for the skeleton: ///for a vertex->bone structur
/** 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 Weight
struct Bone {
{ unsigned int BoneId;
int Id; float Value;
int ParentId; };
std::string Name;
aiVector3D Position;
float RotationAngle; /// Helper Class to describe an ogre-bone for the skeleton:
aiVector3D RotationAxis; /** 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!*/
std::vector<int> Children; struct Bone
aiMatrix4x4 BoneToWorldSpace; {
int Id;
///ctor int ParentId;
Bone(): Id(-1), ParentId(-1), RotationAngle(0.0f) {} std::string Name;
///this operator is needed to sort the bones after Id's aiVector3D Position;
bool operator<(const Bone& rval) const float RotationAngle;
{return Id<rval.Id; } aiVector3D RotationAxis;
///this operator is needed to find a bone by its name in a vector<Bone> std::vector<int> Children;
bool operator==(const std::string& rval) const aiMatrix4x4 BoneToWorldSpace;
{return Name==rval; }
bool operator==(const aiString& rval) const ///ctor
{return Name==std::string(rval.data); } Bone(): Id(-1), ParentId(-1), RotationAngle(0.0f) {}
///this operator is needed to sort the bones after Id's
void CalculateBoneToWorldSpaceMatrix(std::vector<Bone>& Bones); bool operator<(const Bone& rval) const
{return Id<rval.Id; }
}; ///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; }
bool operator==(const aiString& rval) const
///Describes an Ogre Animation {return Name==std::string(rval.data); }
struct Animation
{ void CalculateBoneToWorldSpaceMatrix(std::vector<Bone>& Bones);
std::string Name;
float Length; };
std::vector<Track> Tracks;
};
///a track (keyframes for one bone) from an animation ///Describes an Ogre Animation
struct Track struct Animation
{ {
std::string BoneName; std::string Name;
std::vector<Keyframe> Keyframes; float Length;
}; std::vector<Track> Tracks;
};
/// keyframe (bone transformation) from a track from a animation
struct Keyframe ///a track (keyframes for one bone) from an animation
{ struct Track
float Time; {
aiVector3D Position; std::string BoneName;
aiQuaternion Rotation; std::vector<Keyframe> Keyframes;
aiVector3D Scaling; };
};
/// keyframe (bone transformation) from a track from a animation
}//namespace Ogre struct Keyframe
}//namespace Assimp {
float Time;
aiVector3D Position;
aiQuaternion Rotation;
aiVector3D Scaling;
};
}//namespace Ogre
}//namespace Assimp

View File

@ -55,7 +55,7 @@ using namespace std;
//#include "boost/foreach.hpp" //#include "boost/foreach.hpp"
//using namespace boost; //using namespace boost;
#include "OgreImporter.h" #include "OgreImporter.hpp"
#include "irrXMLWrapper.h" #include "irrXMLWrapper.h"
#include "TinyFormatter.h" #include "TinyFormatter.h"
@ -71,10 +71,6 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
const aiScene* const m_CurrentScene=this->m_CurrentScene;//make sure, that we can access but not change the scene const aiScene* const m_CurrentScene=this->m_CurrentScene;//make sure, that we can access but not change the scene
(void)m_CurrentScene; (void)m_CurrentScene;
aiMaterial *NewMaterial=new aiMaterial();
aiString ts(MaterialName.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_NAME);
/*For bettetr understanding of the material parser, here is a material example file: /*For bettetr understanding of the material parser, here is a material example file:
material Sarg material Sarg
@ -100,9 +96,39 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
*/ */
/*and here is another one:
const string MaterialFileName=m_CurrentFilename.substr(0, m_CurrentFilename.find('.'))+".material"; import * from abstract_base_passes_depth.material
DefaultLogger::get()->info("Trying to load " +MaterialFileName); import * from abstract_base.material
import * from mat_shadow_caster.material
import * from mat_character_singlepass.material
material hero/hair/caster : mat_shadow_caster_skin_areject
{
set $diffuse_map "hero_hair_alpha_c.dds"
}
material hero/hair_alpha : mat_char_cns_singlepass_areject_4weights
{
set $diffuse_map "hero_hair_alpha_c.dds"
set $specular_map "hero_hair_alpha_s.dds"
set $normal_map "hero_hair_alpha_n.dds"
set $light_map "black_lightmap.dds"
set $shadow_caster_material "hero/hair/caster"
}
*/
//the filename typically ends with .mesh or .mesh.xml
const string MaterialFileName=m_CurrentFilename.substr(0, m_CurrentFilename.rfind(".mesh"))+".material";
DefaultLogger::get()->info("Trying to load " + MaterialFileName);
aiMaterial *NewMaterial=new aiMaterial();
aiString ts(MaterialName.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_NAME);
//Read the file into memory and put it in a stringstream //Read the file into memory and put it in a stringstream
stringstream ss; stringstream ss;
@ -110,11 +136,17 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
IOStream* MatFilePtr=m_CurrentIOHandler->Open(MaterialFileName); IOStream* MatFilePtr=m_CurrentIOHandler->Open(MaterialFileName);
if(NULL==MatFilePtr) if(NULL==MatFilePtr)
{ {
MatFilePtr=m_CurrentIOHandler->Open(m_MaterialLibFilename); //try the default mat Library
if(NULL==MatFilePtr) if(NULL==MatFilePtr)
{ {
DefaultLogger::get()->error(m_MaterialLibFilename+" and "+MaterialFileName + " could not be opened, Material will not be loaded!");
return NewMaterial; MatFilePtr=m_CurrentIOHandler->Open(m_MaterialLibFilename);
if(NULL==MatFilePtr)
{
DefaultLogger::get()->error(m_MaterialLibFilename+" and "+MaterialFileName + " could not be opened, Material will not be loaded!");
delete NewMaterial;
return NULL;
}
} }
} }
boost::scoped_ptr<IOStream> MaterialFile(MatFilePtr); boost::scoped_ptr<IOStream> MaterialFile(MatFilePtr);
@ -135,7 +167,10 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
ss >> Line; ss >> Line;
if(Line==MaterialName)//Load the next material if(Line==MaterialName)//Load the next material
{ {
string RestOfLine;
getline(ss, RestOfLine);//ignore the rest of the line
ss >> Line; ss >> Line;
if(Line!="{") if(Line!="{")
throw DeadlyImportError("empty material!"); throw DeadlyImportError("empty material!");
@ -145,72 +180,9 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
ss >> Line; ss >> Line;
if(Line=="technique") if(Line=="technique")
{ {
ss >> Line; ReadTechnique(ss, NewMaterial);
if(Line!="{")
throw DeadlyImportError("empty technique!");
while(Line!="}")//read until the end of the technique
{
ss >> Line;
if(Line=="pass")
{
ss >> Line;
if(Line!="{")
throw DeadlyImportError("empty pass!");
while(Line!="}")//read until the end of the pass
{
ss >> Line;
if(Line=="ambient")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_AMBIENT);
}
else if(Line=="diffuse")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_DIFFUSE);
}
else if(Line=="specular")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_SPECULAR);
}
else if(Line=="emmisive")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_EMISSIVE);
}
else if(Line=="texture_unit")
{
ss >> Line;
if(Line!="{")
throw DeadlyImportError("empty texture unit!");
while(Line!="}")//read until the end of the texture_unit
{
ss >> Line;
if(Line=="texture")
{
ss >> Line;
aiString ts(Line.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
}
}//end of texture unit
}
}
}
}//end of technique
} }
DefaultLogger::get()->info(Line); DefaultLogger::get()->info(Line);
//read informations from a custom material: //read informations from a custom material:
if(Line=="set") if(Line=="set")
@ -237,6 +209,54 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
aiString ts(Line.c_str()); aiString ts(Line.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0)); NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
} }
if(Line=="$shininess_strength")
{
ss >> Line;
float Shininess=fast_atof(Line.c_str());
NewMaterial->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS_STRENGTH);
}
if(Line=="$shininess_exponent")
{
ss >> Line;
float Shininess=fast_atof(Line.c_str());
NewMaterial->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS);
}
//Properties from Venetica:
if(Line=="$diffuse_map")
{
ss >> Line;
if(Line[0]=='"')// "file" -> file
Line=Line.substr(1, Line.size()-2);
aiString ts(Line.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
}
if(Line=="$specular_map")
{
ss >> Line;
if(Line[0]=='"')// "file" -> file
Line=Line.substr(1, Line.size()-2);
aiString ts(Line.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_SHININESS, 0));
}
if(Line=="$normal_map")
{
ss >> Line;
if(Line[0]=='"')// "file" -> file
Line=Line.substr(1, Line.size()-2);
aiString ts(Line.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
}
if(Line=="$light_map")
{
ss >> Line;
if(Line[0]=='"')// "file" -> file
Line=Line.substr(1, Line.size()-2);
aiString ts(Line.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0));
}
} }
}//end of material }//end of material
} }
@ -248,6 +268,71 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
return NewMaterial; return NewMaterial;
} }
void OgreImporter::ReadTechnique(stringstream &ss, aiMaterial* NewMaterial)
{
string Line;
ss >> Line;
if(Line!="{")
throw DeadlyImportError("empty technique!");
while(Line!="}")//read until the end of the technique
{
ss >> Line;
if(Line=="pass")
{
ss >> Line;
if(Line!="{")
throw DeadlyImportError("empty pass!");
while(Line!="}")//read until the end of the pass
{
ss >> Line;
if(Line=="ambient")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_AMBIENT);
}
else if(Line=="diffuse")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_DIFFUSE);
}
else if(Line=="specular")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_SPECULAR);
}
else if(Line=="emmisive")
{
float r,g,b;
ss >> r >> g >> b;
const aiColor3D Color(r,g,b);
NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_EMISSIVE);
}
else if(Line=="texture_unit")
{
ss >> Line;
if(Line!="{")
throw DeadlyImportError("empty texture unit!");
while(Line!="}")//read until the end of the texture_unit
{
ss >> Line;
if(Line=="texture")
{
ss >> Line;
aiString ts(Line.c_str());
NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
}
}//end of texture unit
}
}
}
}//end of technique
}
}//namespace Ogre }//namespace Ogre

View File

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

View File

@ -1457,9 +1457,10 @@ try to find the appendant material and skeleton file.
The skeleton file must have the same name as the mesh file, e.g. fish.mesh.xml and fish.skeleton.xml. The skeleton file must have the same name as the mesh file, e.g. fish.mesh.xml and fish.skeleton.xml.
@subsection material Materials @subsection material Materials
The material file can have the same name as the mesh file, or you can use The material file can have the same name as the mesh file (if the file is model.mesh or model.mesh.xml the
Importer::Importer::SetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "materiafile.material") to specify loader will try to load model.material),
the name of the material file. This is especially usefull if multiply materials a stored in a single file. or you can use Importer::Importer::SetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "materiafile.material")
to specify the name of the material file. This is especially usefull if multiply materials a stored in a single file.
The importer will first try to load the material with the same name as the mesh and only if this can't be open try The importer will first try to load the material with the same name as the mesh and only if this can't be open try
to load the alternate material file. The default material filename is "Scene.material". to load the alternate material file. The default material filename is "Scene.material".
@ -1468,6 +1469,7 @@ should read the custom material sektion in the Ogre Blender exporter Help File,
can find in scripts/OgreImpoter/Assimp.tlp in the assimp source. If you don't set all values, don't worry, they will be ignored during import. can find in scripts/OgreImpoter/Assimp.tlp in the assimp source. If you don't set all values, don't worry, they will be ignored during import.
If you want more properties in custom materials, you can easily expand the ogre material loader, it will be just a few lines for each property. If you want more properties in custom materials, you can easily expand the ogre material loader, it will be just a few lines for each property.
Just look in OgreImporterMaterial.cpp
@subsection todo Todo @subsection todo Todo
- Load colors in custom materials - Load colors in custom materials