Heavy refactoring of the OBJ export
The recent material attribute changes had some issue when exporting mesh newly created.
This commit is contained in:
parent
64a40f10c6
commit
43f114d237
|
|
@ -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";
|
||||||
|
|
@ -108,12 +110,19 @@ 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;
|
|
||||||
|
|
||||||
int current = 0;
|
typename SaveMeshType::template PerMeshAttributeHandle<std::vector<Material> > materialVecHandle =
|
||||||
int totalPrimitives = m.vn+m.fn;
|
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");
|
||||||
|
|
||||||
typename SaveMeshType::template PerMeshAttributeHandle<std::vector<Material> > materialsHandle =
|
if(useMaterialAttribute && (!Allocator<SaveMeshType>::IsValidHandle(m,materialVecHandle)) &&
|
||||||
vcg::tri::Allocator<SaveMeshType>::template FindPerMeshAttribute<std::vector<Material> >(m, "materials");
|
(!Allocator<SaveMeshType>::IsValidHandle(m,materialIndexHandle)) )
|
||||||
|
return E_NO_VALID_MATERIAL;
|
||||||
|
|
||||||
std::string fn(filename);
|
FILE *fp = fopen(filename,"w");
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -60,95 +60,90 @@ namespace vcg {
|
||||||
namespace tri {
|
namespace tri {
|
||||||
namespace io {
|
namespace io {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
structures material
|
structures material
|
||||||
*/
|
*/
|
||||||
struct Material
|
struct Material
|
||||||
{
|
{
|
||||||
unsigned int index;//index of material
|
unsigned int index;//index of material
|
||||||
std::string materialName;
|
std::string materialName;
|
||||||
|
|
||||||
Point3f Ka;//ambient
|
Point3f Ka;//ambient
|
||||||
Point3f Kd;//diffuse
|
Point3f Kd;//diffuse
|
||||||
Point3f Ks;//specular
|
Point3f Ks;//specular
|
||||||
|
|
||||||
float d;//alpha
|
float d;//alpha
|
||||||
float Tr;//alpha
|
float Tr;//alpha
|
||||||
|
|
||||||
int illum;//specular illumination
|
int illum;//specular illumination
|
||||||
float Ns;
|
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, unsigned int index, FaceIterator &fi)
|
inline static int CreateNewMaterial(SaveMeshType &m, std::vector<Material> &materials, FaceIterator &fi)
|
||||||
{
|
{
|
||||||
Point3f diffuse(1,1,1);
|
Material mtl;
|
||||||
float Transp = 1;
|
mtl.index = -1; // index of materials
|
||||||
if(HasPerFaceColor(m)){
|
mtl.Ka = Point3f(0.2f,0.2f,0.2f); // ambient
|
||||||
diffuse = Point3f((float)((*fi).C()[0])/255.0f,(float)((*fi).C()[1])/255.0f,(float)((*fi).C()[2])/255.0f);//diffuse
|
mtl.Kd = Point3f(1,1,1); // diffuse
|
||||||
Transp = (float)((*fi).C()[3])/255.0f;//alpha
|
mtl.Ks = Point3f(1.0f,1.0f,1.0f); // specular
|
||||||
}
|
mtl.Tr = 1.0f; // alpha
|
||||||
|
mtl.Ns = 0.0f;
|
||||||
|
mtl.illum = 2; // illumination
|
||||||
|
|
||||||
int illum = 2; //default not use Ks!
|
if(HasPerFaceColor(m)){
|
||||||
float ns = 0.0; //default
|
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
|
||||||
|
}
|
||||||
|
|
||||||
Material mtl;
|
if(m.textures.size() && (*fi).WT(0).n() >=0 )
|
||||||
|
mtl.map_Kd = m.textures[(*fi).WT(0).n()];
|
||||||
|
else
|
||||||
|
mtl.map_Kd = "";
|
||||||
|
|
||||||
mtl.index = index;//index of materials
|
int matInd = MaterialsCompare(materials,mtl);
|
||||||
mtl.Ka = Point3f(0.2f,0.2f,0.2f);//ambient
|
if(matInd == -1)
|
||||||
mtl.Kd = diffuse;//diffuse
|
{
|
||||||
mtl.Ks = Point3f(1.0f,1.0f,1.0f);//specular
|
mtl.index = int(materials.size());
|
||||||
mtl.Tr = Transp;//alpha
|
materials.push_back(mtl);
|
||||||
mtl.Ns = ns;
|
return mtl.index;
|
||||||
mtl.illum = illum;//illumination
|
}
|
||||||
|
return matInd;
|
||||||
|
}
|
||||||
|
|
||||||
if(m.textures.size() && (*fi).WT(0).n() >=0 )
|
/*
|
||||||
mtl.map_Kd = m.textures[(*fi).WT(0).n()];
|
returns the index of the material if it exists inside the list of the materials,
|
||||||
else
|
otherwise it returns -1.
|
||||||
mtl.map_Kd = "";
|
*/
|
||||||
|
inline static int MaterialsCompare(std::vector<Material> &materials, Material mtl)
|
||||||
int i = -1;
|
{
|
||||||
if((i = MaterialsCompare(materials,mtl)) == -1)
|
for(unsigned int i=0;i<materials.size();i++)
|
||||||
{
|
{
|
||||||
materials.push_back(mtl);
|
if(materials[i].Kd != mtl.Kd ) continue;
|
||||||
return materials.size();
|
if(materials[i].Ka != mtl.Ka ) continue;
|
||||||
}
|
if(materials[i].Ks != mtl.Ks ) continue;
|
||||||
return i;
|
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;
|
||||||
returns the index of the material if it exists inside the list of the materials,
|
return i;
|
||||||
otherwise it returns -1.
|
}
|
||||||
*/
|
return -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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue