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_ABORTED, // 4
E_NOTDEFINITION, // 5
E_NOTVEXTEXVALID, // 6
E_NOTFACESVALID // 7
E_NO_VERTICES, // 6
E_NOTFACESVALID, // 7
E_NO_VALID_MATERIAL
};
/*
@ -78,7 +79,8 @@ public:
"File saving aborted", // 4
"Function not defined", // 5
"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";
@ -107,13 +109,20 @@ public:
return capability;
}
/*
function which saves in OBJ file format
*/
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 &&
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;
}
if(m.vn == 0) return E_NOTVEXTEXVALID;
// Commented out this control. You should be allowed to save a point cloud.
// if(m.fn == 0) return E_NOTFACESVALID;
if(m.vn == 0) return E_NO_VERTICES;
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;
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");
FILE *fp = fopen(filename,"w");
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,"# 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
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::vector<int> VertexId(m.vert.size());
int numvert = 0;
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;
//saves normal per vertex
@ -169,17 +179,14 @@ public:
if (mask & Mask::IOM_VERTNORMAL ) {
fprintf(fp,"vn %f %f %f\n",(*vi).N()[0],(*vi).N()[1],(*vi).N()[2]);
}
if (mask & Mask::IOM_VERTTEXCOORD ) {
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]);
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,"\n");
@ -194,20 +201,23 @@ public:
numvert++;
}
assert(numvert == m.vn);
fprintf(fp,"# %d vertices, %d vertices normals\n\n",m.vn,int(NormalVertex.size()));
/********************* FACES ************************/
//faces + texture coords
typename SaveMeshType::template PerFaceAttributeHandle<int> mIndHandle =
vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<int>(m, "mInd");
std::map<TexCoordType,int> CoordIndexTexture;
int curTexCoordIndex = 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() )
{
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) {
fprintf(fp,"\nusemtl material_%d\n", index);
curMatIndex = index;
@ -225,7 +235,6 @@ public:
}
}
fprintf(fp,"f ");
for(int k=0;k<(*fi).VN();k++)
{
@ -256,7 +265,7 @@ public:
{ fclose(fp); return E_ABORTED;}
}
}//for faces
} // end for faces
for(EdgeIterator ei=m.edge.begin(); ei!=m.edge.end(); ++ei) if( !(*ei).IsD() )
{
@ -272,7 +281,10 @@ public:
int errCode = E_NOERROR;
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)
return errCode;

View File

@ -257,9 +257,9 @@ namespace vcg {
}
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 =
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<ObjTexCoord> texCoords; // texture coordinates
std::vector<CoordType> normals; // vertex normals

View File

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