+ first version of OBJ exporter
git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1056 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/2/head
parent
d29dde1646
commit
c58480d608
|
@ -313,6 +313,9 @@ SET( Obj_SRCS
|
|||
ObjFileParser.cpp
|
||||
ObjFileParser.h
|
||||
ObjTools.h
|
||||
|
||||
ObjExporter.h
|
||||
ObjExporter.cpp
|
||||
)
|
||||
SOURCE_GROUP( Obj FILES ${Obj_SRCS})
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "AssimpPCH.h"
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
|
||||
#include "ColladaExporter.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -69,10 +70,13 @@ void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pS
|
|||
// Constructor for a specific scene to export
|
||||
ColladaExporter::ColladaExporter( const aiScene* pScene)
|
||||
{
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
mOutput.imbue( std::locale("C") );
|
||||
|
||||
mScene = pScene;
|
||||
|
||||
// set up strings
|
||||
endstr = "\n"; // std::endl is too complicated for me to insert here.
|
||||
endstr = "\n";
|
||||
|
||||
// start writing
|
||||
WriteFile();
|
||||
|
@ -366,4 +370,5 @@ void ColladaExporter::WriteNode( const aiNode* pNode)
|
|||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace Assimp {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype
|
||||
void ExportSceneCollada(const char*,IOSystem*, const aiScene*);
|
||||
void ExportSceneObj(const char*,IOSystem*, const aiScene*);
|
||||
void ExportScene3DS(const char*, IOSystem*, const aiScene*) {}
|
||||
|
||||
/// Function pointer type of a Export worker function
|
||||
|
@ -95,6 +96,10 @@ ExportFormatEntry gExporters[] =
|
|||
ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
ExportFormatEntry( "3ds", "Autodesk 3DS (legacy format)", "3ds" , &ExportScene3DS),
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2010, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
|
||||
#include "ObjExporter.h"
|
||||
#include "../include/aiVersion.h"
|
||||
|
||||
using namespace Assimp;
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp
|
||||
void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
|
||||
{
|
||||
// invoke the exporter
|
||||
ObjExporter exporter(pFile, pScene);
|
||||
|
||||
// we're still here - export successfully completed. Write both the main OBJ file and the material script
|
||||
{
|
||||
boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
|
||||
outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
|
||||
}
|
||||
{
|
||||
boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(exporter.GetMaterialLibFileName(),"wt"));
|
||||
outfile->Write( exporter.mOutputMat.str().c_str(), static_cast<size_t>(exporter.mOutputMat.tellp()),1);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ObjExporter :: ObjExporter(const char* _filename, const aiScene* pScene)
|
||||
: filename(_filename)
|
||||
, pScene(pScene)
|
||||
, endl("\n")
|
||||
{
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
const std::locale& l = std::locale("C");
|
||||
mOutput.imbue(l);
|
||||
mOutputMat.imbue(l);
|
||||
|
||||
WriteGeometryFile();
|
||||
WriteMaterialFile();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string ObjExporter :: GetMaterialLibName()
|
||||
{
|
||||
// within the Obj file, we use just the relative file name with the path stripped
|
||||
const std::string& s = GetMaterialLibFileName();
|
||||
std::string::size_type il = s.find_last_of("/\\");
|
||||
if (il != std::string::npos) {
|
||||
return s.substr(il + 1);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string ObjExporter :: GetMaterialLibFileName()
|
||||
{
|
||||
return filename + ".mtl";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter :: WriteHeader(std::ostringstream& out)
|
||||
{
|
||||
out << "# File produced by Open Asset Import Library (http://www.assimp.sf.net)" << endl;
|
||||
out << "# (assimp v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' << aiGetVersionRevision() << ")" << endl << endl;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string ObjExporter :: GetMaterialName(unsigned int index)
|
||||
{
|
||||
const aiMaterial* const mat = pScene->mMaterials[index];
|
||||
aiString s;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_NAME,s)) {
|
||||
return std::string(s.data,s.length);
|
||||
}
|
||||
|
||||
char number[ sizeof(unsigned int) * 3 + 1 ];
|
||||
ASSIMP_itoa10(number,index);
|
||||
return "$Material_" + std::string(number);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter :: WriteMaterialFile()
|
||||
{
|
||||
WriteHeader(mOutputMat);
|
||||
|
||||
for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
||||
const aiMaterial* const mat = pScene->mMaterials[i];
|
||||
|
||||
int illum = 1;
|
||||
mOutputMat << "newmtl " << GetMaterialName(i) << endl;
|
||||
|
||||
aiColor4D c;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) {
|
||||
mOutputMat << "kd " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) {
|
||||
mOutputMat << "ka " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
|
||||
mOutputMat << "ks " << c.r << " " << c.g << " " << c.b << endl;
|
||||
}
|
||||
|
||||
float o;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
|
||||
mOutputMat << "d " << o << endl;
|
||||
}
|
||||
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS,o) && o) {
|
||||
mOutputMat << "Ns " << o << endl;
|
||||
illum = 2;
|
||||
}
|
||||
|
||||
mOutputMat << "illum " << illum << endl;
|
||||
|
||||
aiString s;
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) {
|
||||
mOutputMat << "map_kd " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) {
|
||||
mOutputMat << "map_ka " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) {
|
||||
mOutputMat << "map_ks " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) {
|
||||
mOutputMat << "map_ns " << s.data << endl;
|
||||
}
|
||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) {
|
||||
// implementations seem to vary here, so write both variants
|
||||
mOutputMat << "bump " << s.data << endl;
|
||||
mOutputMat << "map_bump " << s.data << endl;
|
||||
}
|
||||
|
||||
mOutputMat << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter :: WriteGeometryFile()
|
||||
{
|
||||
WriteHeader(mOutput);
|
||||
mOutput << "mtllib " << GetMaterialLibName() << endl << endl;
|
||||
|
||||
// collect mesh geometry
|
||||
aiMatrix4x4 mBase;
|
||||
AddNode(pScene->mRootNode,mBase);
|
||||
|
||||
// write vertex positions
|
||||
mOutput << "# " << vp.size() << " vertex positions" << endl;
|
||||
BOOST_FOREACH(const aiVector3D& v, vp) {
|
||||
mOutput << "v " << v.x << " " << v.y << " " << v.z << endl;
|
||||
}
|
||||
mOutput << endl;
|
||||
|
||||
// write uv coordinates
|
||||
mOutput << "# " << vt.size() << " UV coordinates" << endl;
|
||||
BOOST_FOREACH(const aiVector3D& v, vt) {
|
||||
mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl;
|
||||
}
|
||||
mOutput << endl;
|
||||
|
||||
// write vertex normals
|
||||
mOutput << "# " << vn.size() << " vertex normals" << endl;
|
||||
BOOST_FOREACH(const aiVector3D& v, vn) {
|
||||
mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl;
|
||||
}
|
||||
mOutput << endl;
|
||||
|
||||
// now write all mesh instances
|
||||
BOOST_FOREACH(const MeshInstance& m, meshes) {
|
||||
mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl;
|
||||
mOutput << "g " << m.name << endl;
|
||||
mOutput << "usemtl " << m.matname << endl;
|
||||
|
||||
BOOST_FOREACH(const Face& f, m.faces) {
|
||||
mOutput << "f ";
|
||||
BOOST_FOREACH(const FaceVertex& fv, f.indices) {
|
||||
mOutput << " " << fv.vp << "/";
|
||||
if (fv.vt) {
|
||||
mOutput << fv.vt;
|
||||
}
|
||||
mOutput << "/";
|
||||
if (fv.vn) {
|
||||
mOutput << fv.vn;
|
||||
}
|
||||
}
|
||||
|
||||
mOutput << endl;
|
||||
}
|
||||
mOutput << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat)
|
||||
{
|
||||
meshes.push_back(MeshInstance());
|
||||
MeshInstance& mesh = meshes.back();
|
||||
|
||||
mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_"+std::string(m->mName.data,m->mName.length) : "");
|
||||
mesh.matname = GetMaterialName(m->mMaterialIndex);
|
||||
|
||||
mesh.faces.resize(m->mNumFaces);
|
||||
for(unsigned int i = 0; i < m->mNumFaces; ++i) {
|
||||
const aiFace& f = m->mFaces[i];
|
||||
|
||||
Face& face = mesh.faces[i];
|
||||
face.indices.resize(f.mNumIndices);
|
||||
|
||||
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
||||
const unsigned int idx = f.mIndices[a];
|
||||
|
||||
// XXX need a way to check if this is an unique vertex or if we had it already,
|
||||
// in which case we should instead reference the previous occurrence.
|
||||
ai_assert(m->mVertices);
|
||||
vp.push_back( mat * m->mVertices[idx] );
|
||||
face.indices[a].vp = vp.size();
|
||||
|
||||
if (m->mNormals) {
|
||||
vn.push_back( m->mNormals[idx] );
|
||||
}
|
||||
face.indices[a].vn = vn.size();
|
||||
|
||||
if (m->mTextureCoords[0]) {
|
||||
vt.push_back( m->mTextureCoords[0][idx] );
|
||||
}
|
||||
face.indices[a].vt = vt.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ObjExporter :: AddNode(const aiNode* nd, const aiMatrix4x4& mParent)
|
||||
{
|
||||
const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
|
||||
|
||||
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
|
||||
AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]],mAbs);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
|
||||
AddNode(nd->mChildren[i],mAbs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2010, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file ColladaExporter.h
|
||||
* Declares the exporter class to write a scene to a Collada file
|
||||
*/
|
||||
#ifndef AI_OBJEXPORTER_H_INC
|
||||
#define AI_OBJEXPORTER_H_INC
|
||||
|
||||
#include <sstream>
|
||||
|
||||
struct aiScene;
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Helper class to export a given scene to an OBJ file. */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class ASSIMP_API ObjExporter
|
||||
{
|
||||
public:
|
||||
/// Constructor for a specific scene to export
|
||||
ObjExporter(const char* filename, const aiScene* pScene);
|
||||
|
||||
public:
|
||||
|
||||
std::string GetMaterialLibName();
|
||||
std::string GetMaterialLibFileName();
|
||||
|
||||
public:
|
||||
|
||||
/// public stringstreams to write all output into
|
||||
std::ostringstream mOutput, mOutputMat;
|
||||
|
||||
private:
|
||||
|
||||
// intermediate data structures
|
||||
struct FaceVertex
|
||||
{
|
||||
FaceVertex()
|
||||
: vp(),vn(),vt()
|
||||
{
|
||||
}
|
||||
|
||||
// one-based, 0 means: 'does not exist'
|
||||
unsigned int vp,vn,vt;
|
||||
};
|
||||
|
||||
struct Face {
|
||||
std::vector<FaceVertex> indices;
|
||||
};
|
||||
|
||||
struct MeshInstance {
|
||||
|
||||
std::string name, matname;
|
||||
std::vector<Face> faces;
|
||||
};
|
||||
|
||||
void WriteHeader(std::ostringstream& out);
|
||||
|
||||
void WriteMaterialFile();
|
||||
void WriteGeometryFile();
|
||||
|
||||
std::string GetMaterialName(unsigned int index);
|
||||
|
||||
void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat);
|
||||
void AddNode(const aiNode* nd, const aiMatrix4x4& mParent);
|
||||
|
||||
private:
|
||||
|
||||
const std::string filename;
|
||||
const aiScene* const pScene;
|
||||
|
||||
std::vector<aiVector3D> vp, vn, vt;
|
||||
std::vector<MeshInstance> meshes;
|
||||
|
||||
// this endl() doesn't flush() the stream
|
||||
const std::string endl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -4176,6 +4176,18 @@
|
|||
Name="3ds"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="obj"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\ObjExporter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\ObjExporter.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
|
Loading…
Reference in New Issue