Heavy refactoring of the OBJ export

The recent material attribute changes had some issue when exporting
mesh newly created.
This commit is contained in:
Paolo Cignoni 2017-05-12 16:22:08 +02:00
parent 64a40f10c6
commit 43f114d237
3 changed files with 149 additions and 142 deletions

View File

@ -60,8 +60,9 @@ public:
E_UNESPECTEDEOF, // 3 E_UNESPECTEDEOF, // 3
E_ABORTED, // 4 E_ABORTED, // 4
E_NOTDEFINITION, // 5 E_NOTDEFINITION, // 5
E_NOTVEXTEXVALID, // 6 E_NO_VERTICES, // 6
E_NOTFACESVALID // 7 E_NOTFACESVALID, // 7
E_NO_VALID_MATERIAL
}; };
/* /*
@ -78,7 +79,8 @@ public:
"File saving aborted", // 4 "File saving aborted", // 4
"Function not defined", // 5 "Function not defined", // 5
"Vertices not valid", // 6 "Vertices not valid", // 6
"Faces not valid" // 7 "Faces not valid", // 7
"The mesh has not a attribute containing the vector of materials" // 8
}; };
if(error>7 || error<0) return "Unknown error"; if(error>7 || error<0) return "Unknown error";
@ -107,13 +109,20 @@ public:
return capability; return capability;
} }
/*
function which saves in OBJ file format
*/
static int Save(SaveMeshType &m, const char * filename, int mask, CallBackPos *cb=0) static int Save(SaveMeshType &m, const char * filename, int mask, CallBackPos *cb=0)
{ {
// texture coord and normal: cannot be saved BOTH per vertex and per wedge return Save(m,filename,mask,false,cb);
}
/**
* main function to export a mesh in OBJ file format
*
* if you enable the useMaterialAttribute flag, the exporter will assume that the mesh has a consistent per mesh attribute and a per face attribute containing the index of the material
*/
static int Save(SaveMeshType &m, const char * filename, int mask, bool useMaterialAttribute ,CallBackPos *cb=0)
{
// texture coord and color: in obj we cannot save BOTH per vertex and per wedge information. We default on wedge
if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD && if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD &&
mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD ) { mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD ) {
mask &= ~vcg::tri::io::Mask::IOM_VERTTEXCOORD; mask &= ~vcg::tri::io::Mask::IOM_VERTTEXCOORD;
@ -122,39 +131,40 @@ public:
mask & vcg::tri::io::Mask::IOM_VERTCOLOR ) { mask & vcg::tri::io::Mask::IOM_VERTCOLOR ) {
mask &= ~vcg::tri::io::Mask::IOM_VERTCOLOR; mask &= ~vcg::tri::io::Mask::IOM_VERTCOLOR;
} }
if(m.vn == 0) return E_NOTVEXTEXVALID; if(m.vn == 0) return E_NO_VERTICES;
// Commented out this control. You should be allowed to save a point cloud.
// if(m.fn == 0) return E_NOTFACESVALID; typename SaveMeshType::template PerMeshAttributeHandle<std::vector<Material> > materialVecHandle =
vcg::tri::Allocator<SaveMeshType>::template FindPerMeshAttribute<std::vector<Material> >(m, "materialVector");
typename SaveMeshType::template PerFaceAttributeHandle<int> materialIndexHandle =
vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<int>(m, "materialIndex");
if(useMaterialAttribute && (!Allocator<SaveMeshType>::IsValidHandle(m,materialVecHandle)) &&
(!Allocator<SaveMeshType>::IsValidHandle(m,materialIndexHandle)) )
return E_NO_VALID_MATERIAL;
int current = 0; FILE *fp = fopen(filename,"w");
int totalPrimitives = m.vn+m.fn;
typename SaveMeshType::template PerMeshAttributeHandle<std::vector<Material> > materialsHandle =
vcg::tri::Allocator<SaveMeshType>::template FindPerMeshAttribute<std::vector<Material> >(m, "materials");
std::string fn(filename);
int LastSlash=fn.size()-1;
while(LastSlash>=0 && fn[LastSlash]!='/')
--LastSlash;
FILE *fp;
fp = fopen(filename,"w");
if(fp == NULL) return E_CANTOPENFILE; if(fp == NULL) return E_CANTOPENFILE;
std::string shortFilename(filename);
int LastSlash=shortFilename.size()-1;
while(LastSlash>=0 && shortFilename[LastSlash]!='/')
--LastSlash;
shortFilename = shortFilename.substr(LastSlash+1);
fprintf(fp,"####\n#\n# OBJ File Generated by Meshlab\n#\n####\n"); fprintf(fp,"####\n#\n# OBJ File Generated by Meshlab\n#\n####\n");
fprintf(fp,"# Object %s\n#\n# Vertices: %d\n# Faces: %d\n#\n####\n",fn.substr(LastSlash+1).c_str(),m.vn,m.fn); fprintf(fp,"# Object %s\n#\n# Vertices: %d\n# Faces: %d\n#\n####\n",shortFilename.c_str(),m.vn,m.fn);
//library materialVec //library materialVec
if( (mask & vcg::tri::io::Mask::IOM_FACECOLOR) || (mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_VERTTEXCOORD) ) if( (mask & vcg::tri::io::Mask::IOM_FACECOLOR) || (mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_VERTTEXCOORD) )
fprintf(fp,"mtllib ./%s.mtl\n\n",fn.substr(LastSlash+1).c_str()); fprintf(fp,"mtllib ./%s.mtl\n\n",shortFilename.c_str());
//vertexs + normal
VertexIterator vi;
std::map<CoordType,int> NormalVertex; std::map<CoordType,int> NormalVertex;
std::vector<int> VertexId(m.vert.size()); std::vector<int> VertexId(m.vert.size());
int numvert = 0; int numvert = 0;
int curNormalIndex = 1; int curNormalIndex = 1;
for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if( !(*vi).IsD() ) int current = 0;
const int totalPrimitives = m.vn+m.fn;
/*********************************** VERTICES *********************************/
for(auto vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if( !(*vi).IsD() )
{ {
VertexId[vi-m.vert.begin()]=numvert; VertexId[vi-m.vert.begin()]=numvert;
//saves normal per vertex //saves normal per vertex
@ -169,17 +179,14 @@ public:
if (mask & Mask::IOM_VERTNORMAL ) { if (mask & Mask::IOM_VERTNORMAL ) {
fprintf(fp,"vn %f %f %f\n",(*vi).N()[0],(*vi).N()[1],(*vi).N()[2]); fprintf(fp,"vn %f %f %f\n",(*vi).N()[0],(*vi).N()[1],(*vi).N()[2]);
} }
if (mask & Mask::IOM_VERTTEXCOORD ) { if (mask & Mask::IOM_VERTTEXCOORD ) {
fprintf(fp,"vt %f %f\n",(*vi).T().P()[0],(*vi).T().P()[1]); fprintf(fp,"vt %f %f\n",(*vi).T().P()[0],(*vi).T().P()[1]);
} }
//if (mask & Mask::IOM_VERTCOLOR ) {
// fprintf(fp,"vc %f %f %f\n",(*vi).T().P()[0],(*vi).T().P()[1]);
//}
//saves vertex
fprintf(fp,"v %f %f %f",(*vi).P()[0],(*vi).P()[1],(*vi).P()[2]); fprintf(fp,"v %f %f %f",(*vi).P()[0],(*vi).P()[1],(*vi).P()[2]);
if(mask & Mask::IOM_VERTCOLOR)
if(mask & Mask::IOM_VERTCOLOR) // the socially accepted extension to the obj format.
fprintf(fp," %f %f %f",double((*vi).C()[0])/255.,double((*vi).C()[1])/255.,double((*vi).C()[2])/255.); fprintf(fp," %f %f %f",double((*vi).C()[0])/255.,double((*vi).C()[1])/255.,double((*vi).C()[2])/255.);
fprintf(fp,"\n"); fprintf(fp,"\n");
@ -194,20 +201,23 @@ public:
numvert++; numvert++;
} }
assert(numvert == m.vn); assert(numvert == m.vn);
fprintf(fp,"# %d vertices, %d vertices normals\n\n",m.vn,int(NormalVertex.size())); fprintf(fp,"# %d vertices, %d vertices normals\n\n",m.vn,int(NormalVertex.size()));
/********************* FACES ************************/
//faces + texture coords //faces + texture coords
typename SaveMeshType::template PerFaceAttributeHandle<int> mIndHandle =
vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<int>(m, "mInd");
std::map<TexCoordType,int> CoordIndexTexture; std::map<TexCoordType,int> CoordIndexTexture;
int curTexCoordIndex = 1; int curTexCoordIndex = 1;
int curMatIndex = -1; int curMatIndex = -1;
std::vector<Material> materialVec; //used if we do not have material attributes
for(FaceIterator fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() ) for(FaceIterator fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() )
{ {
if((mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_VERTTEXCOORD)) if((mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_VERTTEXCOORD))
{ {
int index = mIndHandle[fi]; int index=-1;
if(useMaterialAttribute) index = materialIndexHandle[fi];
else index = Materials<SaveMeshType>::CreateNewMaterial(m,materialVec,fi);
if(index != curMatIndex) { if(index != curMatIndex) {
fprintf(fp,"\nusemtl material_%d\n", index); fprintf(fp,"\nusemtl material_%d\n", index);
curMatIndex = index; curMatIndex = index;
@ -225,7 +235,6 @@ public:
} }
} }
fprintf(fp,"f "); fprintf(fp,"f ");
for(int k=0;k<(*fi).VN();k++) for(int k=0;k<(*fi).VN();k++)
{ {
@ -256,7 +265,7 @@ public:
{ fclose(fp); return E_ABORTED;} { fclose(fp); return E_ABORTED;}
} }
}//for faces } // end for faces
for(EdgeIterator ei=m.edge.begin(); ei!=m.edge.end(); ++ei) if( !(*ei).IsD() ) for(EdgeIterator ei=m.edge.begin(); ei!=m.edge.end(); ++ei) if( !(*ei).IsD() )
{ {
@ -272,7 +281,10 @@ public:
int errCode = E_NOERROR; int errCode = E_NOERROR;
if((mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_VERTTEXCOORD) ) if((mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_VERTTEXCOORD) )
errCode = WriteMaterials(materialsHandle(), filename,cb);//write material {
if(useMaterialAttribute) errCode = WriteMaterials(materialVecHandle(), filename,cb);
else errCode = WriteMaterials(materialVec, filename,cb);
}
if(errCode!= E_NOERROR) if(errCode!= E_NOERROR)
return errCode; return errCode;

View File

@ -257,9 +257,9 @@ namespace vcg {
} }
typename OpenMeshType::template PerMeshAttributeHandle<std::vector<Material> > materialsHandle = typename OpenMeshType::template PerMeshAttributeHandle<std::vector<Material> > materialsHandle =
vcg::tri::Allocator<OpenMeshType>:: template GetPerMeshAttribute<std::vector<Material> >(m, std::string("materials")); vcg::tri::Allocator<OpenMeshType>:: template GetPerMeshAttribute<std::vector<Material> >(m, std::string("materialVector"));
typename OpenMeshType::template PerFaceAttributeHandle<int> mIndHandle = typename OpenMeshType::template PerFaceAttributeHandle<int> mIndHandle =
vcg::tri::Allocator<OpenMeshType>:: template GetPerFaceAttribute<int>(m, std::string("mInd")); vcg::tri::Allocator<OpenMeshType>:: template GetPerFaceAttribute<int>(m, std::string("materialIndex"));
std::vector<Material>& materials = materialsHandle(); // materials vector std::vector<Material>& materials = materialsHandle(); // materials vector
std::vector<ObjTexCoord> texCoords; // texture coordinates std::vector<ObjTexCoord> texCoords; // texture coordinates
std::vector<CoordType> normals; // vertex normals std::vector<CoordType> normals; // vertex normals

View File

@ -23,30 +23,30 @@
/**************************************************************************** /****************************************************************************
History History
$Log: not supported by cvs2svn $ $Log: not supported by cvs2svn $
Revision 1.5 2008/02/27 00:34:43 cignoni Revision 1.5 2008/02/27 00:34:43 cignoni
corrected various bugs in the export of texture coords corrected various bugs in the export of texture coords
Revision 1.4 2007/06/20 10:28:04 tarini Revision 1.4 2007/06/20 10:28:04 tarini
"newline at end of file" and "endif" warnings fixed "newline at end of file" and "endif" warnings fixed
Revision 1.3 2006/11/09 07:51:44 cignoni Revision 1.3 2006/11/09 07:51:44 cignoni
bug due to wrong access to eventually unexistent FaceColor bug due to wrong access to eventually unexistent FaceColor
Revision 1.2 2006/10/09 19:58:08 cignoni Revision 1.2 2006/10/09 19:58:08 cignoni
Added casts to remove warnings Added casts to remove warnings
Revision 1.1 2006/03/07 13:19:29 cignoni Revision 1.1 2006/03/07 13:19:29 cignoni
First Release with OBJ import support First Release with OBJ import support
Revision 1.1 2006/02/16 19:28:36 fmazzant Revision 1.1 2006/02/16 19:28:36 fmazzant
transfer of Export_3ds.h, Export_obj.h, Io_3ds_obj_material.h from Meshlab to vcg transfer of Export_3ds.h, Export_obj.h, Io_3ds_obj_material.h from Meshlab to vcg
Revision 1.1 2006/02/06 11:04:40 fmazzant Revision 1.1 2006/02/06 11:04:40 fmazzant
added file material.h. it include struct Material, CreateNewMaterial(...) and MaterialsCompare(...) added file material.h. it include struct Material, CreateNewMaterial(...) and MaterialsCompare(...)
****************************************************************************/ ****************************************************************************/
#ifndef __VCGLIB_MATERIAL #ifndef __VCGLIB_MATERIAL
@ -59,96 +59,91 @@
namespace vcg { namespace vcg {
namespace tri { namespace tri {
namespace io { namespace io {
/*
structures material
*/
struct Material
{
unsigned int index;//index of material
std::string materialName;
Point3f Ka;//ambient /*
Point3f Kd;//diffuse structures material
Point3f Ks;//specular */
struct Material
float d;//alpha {
float Tr;//alpha unsigned int index;//index of material
std::string materialName;
int illum;//specular illumination
float Ns; Point3f Ka;//ambient
Point3f Kd;//diffuse
Point3f Ks;//specular
float d;//alpha
float Tr;//alpha
int illum;//specular illumination
float Ns;
std::string map_Kd; //filename texture
};
std::string map_Kd; //filename texture
};
template <class SaveMeshType>
template <class SaveMeshType> class Materials
class Materials {
{ public:
public: typedef typename SaveMeshType::FaceIterator FaceIterator;
typedef typename SaveMeshType::FaceIterator FaceIterator; typedef typename SaveMeshType::VertexIterator VertexIterator;
typedef typename SaveMeshType::VertexIterator VertexIterator; typedef typename SaveMeshType::VertexType VertexType;
typedef typename SaveMeshType::VertexType VertexType;
/*
/* creates a new meterial
creates a new meterial */
*/ inline static int CreateNewMaterial(SaveMeshType &m, std::vector<Material> &materials, FaceIterator &fi)
inline static int CreateNewMaterial(SaveMeshType &m, std::vector<Material> &materials, unsigned int index, FaceIterator &fi) {
{ Material mtl;
Point3f diffuse(1,1,1); mtl.index = -1; // index of materials
float Transp = 1; mtl.Ka = Point3f(0.2f,0.2f,0.2f); // ambient
if(HasPerFaceColor(m)){ mtl.Kd = Point3f(1,1,1); // diffuse
diffuse = Point3f((float)((*fi).C()[0])/255.0f,(float)((*fi).C()[1])/255.0f,(float)((*fi).C()[2])/255.0f);//diffuse mtl.Ks = Point3f(1.0f,1.0f,1.0f); // specular
Transp = (float)((*fi).C()[3])/255.0f;//alpha mtl.Tr = 1.0f; // alpha
} mtl.Ns = 0.0f;
mtl.illum = 2; // illumination
int illum = 2; //default not use Ks!
float ns = 0.0; //default if(HasPerFaceColor(m)){
mtl.Kd = Point3f((float)((*fi).C()[0])/255.0f,(float)((*fi).C()[1])/255.0f,(float)((*fi).C()[2])/255.0f);//diffuse
Material mtl; mtl.Tr = (float)((*fi).C()[3])/255.0f;//alpha
}
mtl.index = index;//index of materials
mtl.Ka = Point3f(0.2f,0.2f,0.2f);//ambient if(m.textures.size() && (*fi).WT(0).n() >=0 )
mtl.Kd = diffuse;//diffuse mtl.map_Kd = m.textures[(*fi).WT(0).n()];
mtl.Ks = Point3f(1.0f,1.0f,1.0f);//specular else
mtl.Tr = Transp;//alpha mtl.map_Kd = "";
mtl.Ns = ns;
mtl.illum = illum;//illumination int matInd = MaterialsCompare(materials,mtl);
if(matInd == -1)
if(m.textures.size() && (*fi).WT(0).n() >=0 ) {
mtl.map_Kd = m.textures[(*fi).WT(0).n()]; mtl.index = int(materials.size());
else materials.push_back(mtl);
mtl.map_Kd = ""; return mtl.index;
}
int i = -1; return matInd;
if((i = MaterialsCompare(materials,mtl)) == -1) }
{
materials.push_back(mtl); /*
return materials.size(); returns the index of the material if it exists inside the list of the materials,
} otherwise it returns -1.
return i; */
} inline static int MaterialsCompare(std::vector<Material> &materials, Material mtl)
{
/* for(unsigned int i=0;i<materials.size();i++)
returns the index of the material if it exists inside the list of the materials, {
otherwise it returns -1. if(materials[i].Kd != mtl.Kd ) continue;
*/ if(materials[i].Ka != mtl.Ka ) continue;
inline static int MaterialsCompare(std::vector<Material> &materials, Material mtl) if(materials[i].Ks != mtl.Ks ) continue;
{ if(materials[i].Tr != mtl.Tr ) continue;
for(unsigned int i=0;i<materials.size();i++) if(materials[i].illum != mtl.illum ) continue;
{ if(materials[i].Ns != mtl.Ns ) continue;
if(materials[i].Kd != mtl.Kd ) continue; if(materials[i].map_Kd != mtl.map_Kd) continue;
if(materials[i].Ka != mtl.Ka ) continue; return i;
if(materials[i].Ks != mtl.Ks ) continue; }
if(materials[i].Tr != mtl.Tr ) continue; return -1;
if(materials[i].illum != mtl.illum ) continue; }
if(materials[i].Ns != mtl.Ns ) continue; };
if(materials[i].map_Kd != mtl.map_Kd) continue;
return i;
}
return -1;
}
};
} }
} }
} }