parent
f9fa95a7c2
commit
692fb216f7
|
@ -38,8 +38,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||||
|
|
||||||
|
@ -53,8 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -90,7 +88,10 @@ ObjExporter :: ObjExporter(const char* _filename, const aiScene* pScene)
|
||||||
: filename(_filename)
|
: filename(_filename)
|
||||||
, pScene(pScene)
|
, pScene(pScene)
|
||||||
, endl("\n")
|
, endl("\n")
|
||||||
{
|
, vp()
|
||||||
|
, vn()
|
||||||
|
, vt()
|
||||||
|
, vc() {
|
||||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
// 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");
|
const std::locale& l = std::locale("C");
|
||||||
mOutput.imbue(l);
|
mOutput.imbue(l);
|
||||||
|
@ -170,7 +171,6 @@ void ObjExporter::WriteMaterialFile()
|
||||||
mOutputMat << "Tf " << c.r << " " << c.g << " " << c.b << endl;
|
mOutputMat << "Tf " << c.r << " " << c.g << " " << c.b << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ai_real o;
|
ai_real o;
|
||||||
if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
|
if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
|
||||||
mOutputMat << "d " << o << endl;
|
mOutputMat << "d " << o << endl;
|
||||||
|
@ -213,8 +213,7 @@ void ObjExporter::WriteMaterialFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ObjExporter :: WriteGeometryFile()
|
void ObjExporter::WriteGeometryFile() {
|
||||||
{
|
|
||||||
WriteHeader(mOutput);
|
WriteHeader(mOutput);
|
||||||
mOutput << "mtllib " << GetMaterialLibName() << endl << endl;
|
mOutput << "mtllib " << GetMaterialLibName() << endl << endl;
|
||||||
|
|
||||||
|
@ -222,12 +221,22 @@ void ObjExporter :: WriteGeometryFile()
|
||||||
aiMatrix4x4 mBase;
|
aiMatrix4x4 mBase;
|
||||||
AddNode(pScene->mRootNode, mBase);
|
AddNode(pScene->mRootNode, mBase);
|
||||||
|
|
||||||
// write vertex positions
|
// write vertex positions with colors, if any
|
||||||
vpMap.getVectors( vp );
|
vpMap.getVectors( vp );
|
||||||
|
vcMap.getColors( vc );
|
||||||
|
if ( vc.empty() ) {
|
||||||
mOutput << "# " << vp.size() << " vertex positions" << endl;
|
mOutput << "# " << vp.size() << " vertex positions" << endl;
|
||||||
for ( const aiVector3D& v : vp ) {
|
for ( const aiVector3D& v : vp ) {
|
||||||
mOutput << "v " << v.x << " " << v.y << " " << v.z << endl;
|
mOutput << "v " << v.x << " " << v.y << " " << v.z << endl;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mOutput << "# " << vp.size() << " vertex positions and colors" << endl;
|
||||||
|
size_t colIdx = 0;
|
||||||
|
for ( const aiVector3D& v : vp ) {
|
||||||
|
mOutput << "v " << v.x << " " << v.y << " " << v.z << " " << vc[ colIdx ].r << " " << vc[ colIdx ].g << " " << vc[ colIdx ].b << endl;
|
||||||
|
colIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
mOutput << endl;
|
mOutput << endl;
|
||||||
|
|
||||||
// write uv coordinates
|
// write uv coordinates
|
||||||
|
@ -279,8 +288,7 @@ void ObjExporter :: WriteGeometryFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec)
|
int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec) {
|
||||||
{
|
|
||||||
vecIndexMap::dataType::iterator vertIt = vecMap.find(vec);
|
vecIndexMap::dataType::iterator vertIt = vecMap.find(vec);
|
||||||
// vertex already exists, so reference it
|
// vertex already exists, so reference it
|
||||||
if(vertIt != vecMap.end()){
|
if(vertIt != vecMap.end()){
|
||||||
|
@ -293,8 +301,7 @@ int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs )
|
void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs ) {
|
||||||
{
|
|
||||||
vecs.resize(vecMap.size());
|
vecs.resize(vecMap.size());
|
||||||
for(vecIndexMap::dataType::iterator it = vecMap.begin(); it != vecMap.end(); ++it){
|
for(vecIndexMap::dataType::iterator it = vecMap.begin(); it != vecMap.end(); ++it){
|
||||||
vecs[it->second-1] = it->first;
|
vecs[it->second-1] = it->first;
|
||||||
|
@ -302,8 +309,29 @@ void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs )
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat)
|
int ObjExporter::colIndexMap::getIndex( const aiColor4D& col ) {
|
||||||
{
|
colIndexMap::dataType::iterator vertIt = colMap.find( col );
|
||||||
|
// vertex already exists, so reference it
|
||||||
|
if ( vertIt != colMap.end() ) {
|
||||||
|
return vertIt->second;
|
||||||
|
}
|
||||||
|
colMap[ col ] = mNextIndex;
|
||||||
|
int ret = mNextIndex;
|
||||||
|
mNextIndex++;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void ObjExporter::colIndexMap::getColors( std::vector<aiColor4D> &colors ) {
|
||||||
|
colors.resize( colMap.size() );
|
||||||
|
for ( colIndexMap::dataType::iterator it = colMap.begin(); it != colMap.end(); ++it ) {
|
||||||
|
colors[ it->second - 1 ] = it->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
|
||||||
meshes.push_back(MeshInstance());
|
meshes.push_back(MeshInstance());
|
||||||
MeshInstance& mesh = meshes.back();
|
MeshInstance& mesh = meshes.back();
|
||||||
|
|
||||||
|
@ -337,15 +365,20 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
|
||||||
if (m->mNormals) {
|
if (m->mNormals) {
|
||||||
aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx];
|
aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx];
|
||||||
face.indices[a].vn = vnMap.getIndex(norm);
|
face.indices[a].vn = vnMap.getIndex(norm);
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
face.indices[a].vn = 0;
|
face.indices[a].vn = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( nullptr != m->mColors[ 0 ] ) {
|
||||||
|
aiColor4D col4 = m->mColors[ 0 ][ idx ];
|
||||||
|
face.indices[ a ].vc = vcMap.getIndex( col4 );
|
||||||
|
} else {
|
||||||
|
face.indices[ a ].vc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ( m->mTextureCoords[ 0 ] ) {
|
if ( m->mTextureCoords[ 0 ] ) {
|
||||||
face.indices[a].vt = vtMap.getIndex(m->mTextureCoords[0][idx]);
|
face.indices[a].vt = vtMap.getIndex(m->mTextureCoords[0][idx]);
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
face.indices[a].vt = 0;
|
face.indices[a].vt = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,34 +59,33 @@ namespace Assimp
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
/** Helper class to export a given scene to an OBJ file. */
|
/** Helper class to export a given scene to an OBJ file. */
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
class ObjExporter
|
class ObjExporter {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
/// Constructor for a specific scene to export
|
/// Constructor for a specific scene to export
|
||||||
ObjExporter(const char* filename, const aiScene* pScene);
|
ObjExporter(const char* filename, const aiScene* pScene);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string GetMaterialLibName();
|
std::string GetMaterialLibName();
|
||||||
std::string GetMaterialLibFileName();
|
std::string GetMaterialLibFileName();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// public string-streams to write all output into
|
||||||
/// public stringstreams to write all output into
|
|
||||||
std::ostringstream mOutput, mOutputMat;
|
std::ostringstream mOutput, mOutputMat;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// intermediate data structures
|
// intermediate data structures
|
||||||
struct FaceVertex
|
struct FaceVertex {
|
||||||
{
|
|
||||||
FaceVertex()
|
FaceVertex()
|
||||||
: vp(),vn(),vt()
|
: vp()
|
||||||
{
|
, vn()
|
||||||
|
, vt()
|
||||||
|
, vc() {
|
||||||
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// one-based, 0 means: 'does not exist'
|
// one-based, 0 means: 'does not exist'
|
||||||
unsigned int vp,vn,vt;
|
unsigned int vp, vn, vt, vc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Face {
|
struct Face {
|
||||||
|
@ -111,17 +110,14 @@ private:
|
||||||
void AddNode(const aiNode* nd, const aiMatrix4x4& mParent);
|
void AddNode(const aiNode* nd, const aiMatrix4x4& mParent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const std::string filename;
|
const std::string filename;
|
||||||
const aiScene* const pScene;
|
const aiScene* const pScene;
|
||||||
|
|
||||||
std::vector<aiVector3D> vp, vn, vt;
|
std::vector<aiVector3D> vp, vn, vt;
|
||||||
|
std::vector<aiColor4D> vc;
|
||||||
|
|
||||||
|
struct aiVectorCompare {
|
||||||
struct aiVectorCompare
|
bool operator() (const aiVector3D& a, const aiVector3D& b) const {
|
||||||
{
|
|
||||||
bool operator() (const aiVector3D& a, const aiVector3D& b) const
|
|
||||||
{
|
|
||||||
if(a.x < b.x) return true;
|
if(a.x < b.x) return true;
|
||||||
if(a.x > b.x) return false;
|
if(a.x > b.x) return false;
|
||||||
if(a.y < b.y) return true;
|
if(a.y < b.y) return true;
|
||||||
|
@ -131,21 +127,52 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class vecIndexMap
|
struct aiColor4Compare {
|
||||||
{
|
bool operator() ( const aiColor4D& a, const aiColor4D& b ) const {
|
||||||
|
if ( a.r < b.r ) return true;
|
||||||
|
if ( a.r > b.r ) return false;
|
||||||
|
if ( a.g < b.g ) return true;
|
||||||
|
if ( a.g > b.g ) return false;
|
||||||
|
if ( a.b < b.b ) return true;
|
||||||
|
if ( a.b > b.b ) return false;
|
||||||
|
if ( a.a < b.a ) return true;
|
||||||
|
if ( a.a > b.a ) return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class vecIndexMap {
|
||||||
int mNextIndex;
|
int mNextIndex;
|
||||||
typedef std::map<aiVector3D, int, aiVectorCompare> dataType;
|
typedef std::map<aiVector3D, int, aiVectorCompare> dataType;
|
||||||
dataType vecMap;
|
dataType vecMap;
|
||||||
public:
|
|
||||||
|
|
||||||
vecIndexMap():mNextIndex(1)
|
public:
|
||||||
{}
|
vecIndexMap()
|
||||||
|
: mNextIndex(1) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
int getIndex(const aiVector3D& vec);
|
int getIndex(const aiVector3D& vec);
|
||||||
void getVectors( std::vector<aiVector3D>& vecs );
|
void getVectors( std::vector<aiVector3D>& vecs );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class colIndexMap {
|
||||||
|
int mNextIndex;
|
||||||
|
typedef std::map<aiColor4D, int, aiColor4Compare> dataType;
|
||||||
|
dataType colMap;
|
||||||
|
|
||||||
|
public:
|
||||||
|
colIndexMap()
|
||||||
|
: mNextIndex( 1 ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
int getIndex( const aiColor4D& col );
|
||||||
|
void getColors( std::vector<aiColor4D> &colors );
|
||||||
|
};
|
||||||
|
|
||||||
vecIndexMap vpMap, vnMap, vtMap;
|
vecIndexMap vpMap, vnMap, vtMap;
|
||||||
|
colIndexMap vcMap;
|
||||||
std::vector<MeshInstance> meshes;
|
std::vector<MeshInstance> meshes;
|
||||||
|
|
||||||
// this endl() doesn't flush() the stream
|
// this endl() doesn't flush() the stream
|
||||||
|
|
|
@ -46,4 +46,10 @@ class AbstractImportExportBase : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
virtual ~AbstractImportExportBase();
|
virtual ~AbstractImportExportBase();
|
||||||
virtual bool importerTest() = 0;
|
virtual bool importerTest() = 0;
|
||||||
|
virtual bool exporterTest();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool AbstractImportExportBase::exporterTest() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "AbstractImportExportBase.h"
|
#include "AbstractImportExportBase.h"
|
||||||
|
|
||||||
#include <assimp/Importer.hpp>
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <assimp/Exporter.hpp>
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -194,6 +195,16 @@ protected:
|
||||||
return nullptr != scene;
|
return nullptr != scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool exporterTest() {
|
||||||
|
Assimp::Importer importer;
|
||||||
|
Assimp::Exporter exporter;
|
||||||
|
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", 0 );
|
||||||
|
EXPECT_NE( nullptr, scene );
|
||||||
|
EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj" ) );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Assimp::Importer *m_im;
|
Assimp::Importer *m_im;
|
||||||
aiScene *m_expectedScene;
|
aiScene *m_expectedScene;
|
||||||
|
@ -203,6 +214,10 @@ TEST_F( utObjImportExport, importObjFromFileTest ) {
|
||||||
EXPECT_TRUE( importerTest() );
|
EXPECT_TRUE( importerTest() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F( utObjImportExport, exportObjFromFileTest ) {
|
||||||
|
EXPECT_TRUE( exporterTest() );
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F( utObjImportExport, obj_import_test ) {
|
TEST_F( utObjImportExport, obj_import_test ) {
|
||||||
const aiScene *scene = m_im->ReadFileFromMemory( (void*) ObjModel.c_str(), ObjModel.size(), 0 );
|
const aiScene *scene = m_im->ReadFileFromMemory( (void*) ObjModel.c_str(), ObjModel.size(), 0 );
|
||||||
aiScene *expected = createScene();
|
aiScene *expected = createScene();
|
||||||
|
@ -219,3 +234,12 @@ TEST_F( utObjImportExport, issue1111_no_mat_name_Test ) {
|
||||||
const aiScene *scene = m_im->ReadFileFromMemory( ( void* ) ObjModel_Issue1111.c_str(), ObjModel_Issue1111.size(), 0 );
|
const aiScene *scene = m_im->ReadFileFromMemory( ( void* ) ObjModel_Issue1111.c_str(), ObjModel_Issue1111.size(), 0 );
|
||||||
EXPECT_NE( nullptr, scene );
|
EXPECT_NE( nullptr, scene );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F( utObjImportExport, issue809_vertex_color_Test ) {
|
||||||
|
Assimp::Importer importer;
|
||||||
|
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/cube_with_vertexcolors.obj", 0 );
|
||||||
|
EXPECT_NE( nullptr, scene );
|
||||||
|
|
||||||
|
Assimp::Exporter exporter;
|
||||||
|
EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/test.obj" ) );
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue