Refactored a bit the obj importer to remove bug caused by meshes with and without textures

This commit is contained in:
Paolo Cignoni 2018-04-06 10:33:53 +02:00
parent 524f8e8a61
commit 95a2c62104
1 changed files with 1039 additions and 1070 deletions

View File

@ -48,6 +48,7 @@ namespace vcg {
This class encapsulate a filter for importing obj (Alias Wavefront) meshes. This class encapsulate a filter for importing obj (Alias Wavefront) meshes.
Warning: this code assume little endian (PC) architecture!!! Warning: this code assume little endian (PC) architecture!!!
*/ */
template <class OpenMeshType> template <class OpenMeshType>
class ImporterOBJ class ImporterOBJ
{ {
@ -67,43 +68,23 @@ namespace vcg {
{ {
public: public:
Info() Info() {}
{
mask = 0;
cb = 0;
numTexCoords=0;
}
/// It returns a bit mask describing the field preesnt in the ply file /// It returns a bit mask describing the field present in the obj file
int mask; int mask=0;
/// a Simple callback that can be used for long obj parsing. /// a Simple callback that can be used for long obj parsing.
// it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...) CallBackPos *cb=nullptr;
CallBackPos *cb;
/// number of vertices
int numVertices; int numVertices;
/// number of edges
int numEdges; int numEdges;
/// number of faces (the number of triangles could be int numFaces; // Note that numFaces can be different from the final number of triangles
/// larger in presence of polygonal faces int numTexCoords=0;
int numFaces;
/// number of texture coords indexes
int numTexCoords;
/// number of normals
int numNormals; int numNormals;
}; // end class }; // end class
//struct OBJFacet
//{
// CoordType n;
// CoordType t;
// CoordType v[3];
//
// short attr; // material index
//};
struct ObjIndexedFace struct ObjIndexedFace
{ {
void set(const int & num){v.resize(num);n.resize(num); t.resize(num);} void set(const int & num){v.resize(num);n.resize(num); t.resize(num);}
@ -244,11 +225,6 @@ namespace vcg {
if (oi.numVertices == 0) if (oi.numVertices == 0)
return E_NO_VERTEX; return E_NO_VERTEX;
// Commented out this test. You should be allowed to load point clouds.
//if (oi.numFaces == 0)
// return E_NO_FACE;
std::ifstream stream(filename); std::ifstream stream(filename);
if (stream.fail()) if (stream.fail())
{ {
@ -420,7 +396,7 @@ namespace vcg {
if( (vertexesPerFace>3) && OpenMeshType::FaceType::HasPolyInfo() ) if( (vertexesPerFace>3) && OpenMeshType::FaceType::HasPolyInfo() )
{ {
//_BEGIN___ if you are loading a GENERIC POLYGON mesh //_BEGIN___ if you are filling a vcg mesh with GENERIC POLYGON
ff.set(vertexesPerFace); ff.set(vertexesPerFace);
for(int i=0;i<vertexesPerFace;++i) { // remember index starts from 1 instead of 0 for(int i=0;i<vertexesPerFace;++i) { // remember index starts from 1 instead of 0
SplitToken(tokens[i+1], ff.v[i], ff.n[i], ff.t[i], inputMask); SplitToken(tokens[i+1], ff.v[i], ff.n[i], ff.t[i], inputMask);
@ -474,11 +450,11 @@ namespace vcg {
++numTriangles; ++numTriangles;
indexedFaces.push_back(ff); indexedFaces.push_back(ff);
//_END ___ if you are loading a GENERIC POLYGON mesh //_END ___ if you are filling a vcg mesh with GENERIC POLYGON
} }
else else
{ {
//_BEGIN___ if you are loading a TRIMESH mesh //_BEGIN___ if you are filling a vcg mesh with TRIANGLES
std::vector<std::vector<vcg::Point3f> > polygonVect(1); // it is a vector of polygon loops std::vector<std::vector<vcg::Point3f> > polygonVect(1); // it is a vector of polygon loops
polygonVect[0].resize(vertexesPerFace); polygonVect[0].resize(vertexesPerFace);
std::vector<int> indexVVect(vertexesPerFace); std::vector<int> indexVVect(vertexesPerFace);
@ -599,7 +575,7 @@ namespace vcg {
indexedFaces.push_back(ff); indexedFaces.push_back(ff);
} }
} } //_END ___ if you are filling a vcg mesh with TRIANGLES
} }
else if ((header.compare("mtllib")==0) && (tokens.size() > 1)) // material library else if ((header.compare("mtllib")==0) && (tokens.size() > 1)) // material library
{ {
@ -615,7 +591,7 @@ namespace vcg {
} }
else if ((header.compare("usemtl")==0) && (tokens.size() > 1)) // material usage else if ((header.compare("usemtl")==0) && (tokens.size() > 1)) // material usage
{ {
// emergency check. If there are no materials, the materail library failed to load or was not specified // emergency check. If there are no materials, the material library failed to load or was not specified
// but there are tools that save the material library with the same name of the file, but do not add the // but there are tools that save the material library with the same name of the file, but do not add the
// "mtllib" definition in the header. So, we can try to see if this is the case // "mtllib" definition in the header. So, we can try to see if this is the case
if ((materials.size() == 1)&&(materials[0].materialName == "")){ if ((materials.size() == 1)&&(materials[0].materialName == "")){
@ -860,7 +836,16 @@ namespace vcg {
if (hasNormal) if (hasNormal)
nId = atoi(token.substr(secondSep + 1).c_str()) - 1; nId = atoi(token.substr(secondSep + 1).c_str()) - 1;
} }
/** returns a Point3f done from (tokens[pos],tokens[pos+1],tokens[pos+2])
*/
static Point3f Point3fFrom3Tokens(std::vector< std::string > &tokens, int pos)
{
float r = (float) atof(tokens[pos+0].c_str());
float g = (float) atof(tokens[pos+1].c_str());
float b = (float) atof(tokens[pos+2].c_str());
return Point3f(r, g, b);
}
/*! /*!
* Retrieves infos about kind of data stored into the file and fills a mask appropriately * Retrieves infos about kind of data stored into the file and fills a mask appropriately
@ -1028,54 +1013,34 @@ namespace vcg {
} }
else if (header.compare("Ka")==0) else if (header.compare("Ka")==0)
{ {
if (tokens.size() < 4) if (tokens.size() < 4) return false;
return false; currentMaterial.Ka = Point3fFrom3Tokens(tokens,1);
float r = (float) atof(tokens[1].c_str());
float g = (float) atof(tokens[2].c_str());
float b = (float) atof(tokens[3].c_str());
currentMaterial.Ka = Point3f(r, g, b);
} }
else if (header.compare("Kd")==0) else if (header.compare("Kd")==0)
{ {
if (tokens.size() < 4) if (tokens.size() < 4) return false;
return false; currentMaterial.Kd = Point3fFrom3Tokens(tokens,1);
float r = (float) atof(tokens[1].c_str());
float g = (float) atof(tokens[2].c_str());
float b = (float) atof(tokens[3].c_str());
currentMaterial.Kd = Point3f(r, g, b);
} }
else if (header.compare("Ks")==0) else if (header.compare("Ks")==0)
{ {
if (tokens.size() < 4) if (tokens.size() < 4) return false;
return false; currentMaterial.Ks = Point3fFrom3Tokens(tokens,1);
float r = (float) atof(tokens[1].c_str());
float g = (float) atof(tokens[2].c_str());
float b = (float) atof(tokens[3].c_str());
currentMaterial.Ks = Point3f(r, g, b);
} }
else if ( (header.compare("d")==0) || else if ( (header.compare("d")==0) ||
(header.compare("Tr")==0) ) // alpha (header.compare("Tr")==0) ) // alpha
{ {
if (tokens.size() < 2) if (tokens.size() < 2) return false;
return false;
currentMaterial.Tr = (float) atof(tokens[1].c_str()); currentMaterial.Tr = (float) atof(tokens[1].c_str());
} }
else if (header.compare("Ns")==0) // shininess else if (header.compare("Ns")==0) // shininess
{ {
if (tokens.size() < 2) if (tokens.size() < 2) return false;
return false;
currentMaterial.Ns = float(atoi(tokens[1].c_str())); currentMaterial.Ns = float(atoi(tokens[1].c_str()));
} }
else if (header.compare("illum")==0) // specular illumination on/off else if (header.compare("illum")==0) // specular illumination on/off
{ {
if (tokens.size() < 2) if (tokens.size() < 2) return false;
return false; currentMaterial.illum = atoi(tokens[1].c_str());;
int illumination = atoi(tokens[1].c_str());
//currentMaterial.bSpecular = (illumination == 2);
currentMaterial.illum = illumination;
} }
else if(header.compare("map_Kd")==0) // texture name else if(header.compare("map_Kd")==0) // texture name
{ {
@ -1091,22 +1056,12 @@ namespace vcg {
// adding texture name into textures vector (if not already present) // adding texture name into textures vector (if not already present)
// avoid adding the same name twice // avoid adding the same name twice
bool found = false; auto it = std::find(textures.begin(), textures.end(), textureName);
unsigned int size = static_cast<unsigned int>(textures.size()); if(it==textures.end()) {
unsigned j = 0; currentMaterial.index = textures.size();
while (!found && (j < size))
{
if (textureName.compare(textures[j])==0)
{
currentMaterial.index = (int)j;
found = true;
}
++j;
}
if (!found)
{
textures.push_back(textureName); textures.push_back(textureName);
currentMaterial.index = (int)size; } else {
currentMaterial.index = std::distance(textures.begin(),it);
} }
} }
// we simply ignore other situations // we simply ignore other situations
@ -1115,6 +1070,20 @@ namespace vcg {
materials.push_back(currentMaterial); // add last read material materials.push_back(currentMaterial); // add last read material
stream.close(); stream.close();
// Sometimes some materials have texture and no texture
// in this case for sake of uniformity we just use the first texture.
if(!textures.empty())
{
for(size_t i=0;i<materials.size();++i)
{
if(materials[i].map_Kd.empty())
{
materials[i].map_Kd=textures[0];
materials[i].index=0;
}
}
}
return true; return true;
} }