From Marc Helbling, Clément Léger, Aurélien Chatelain, Paul Cheyrou-Lagrèze :

"a last submission for the obj plugin
* supports vertex color definition after vertex position by Clément Léger
* supports zbrush vertex color definition (as #MRGB comment) by Aurélien Chatelain
* adds a noReverseFace option to not mess with face definition by Aurélien Chatelain
* makes material parsing case insensitive (by Paul Cheyrou-Lagrèze and me)
* makes the plugin resilient to faulty vertex uv/normal definition (i.e. when a too big index is referenced) by Aurélien hatelain
"


git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14641 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
Robert Osfield
2014-12-24 11:25:46 +00:00
parent 50203023c7
commit 78729e28fd
3 changed files with 135 additions and 34 deletions

View File

@@ -61,6 +61,7 @@ public:
supportsOption("noTesselateLargePolygons","Do not do the default tesselation of large polygons");
supportsOption("noTriStripPolygons","Do not do the default tri stripping of polygons");
supportsOption("generateFacetNormals","generate facet normals for verticies without normals");
supportsOption("noReverseFaces","avoid to reverse faces when normals and triangles orientation are reversed");
supportsOption("DIFFUSE=<unit>", "Set texture unit for diffuse texture");
supportsOption("AMBIENT=<unit>", "Set texture unit for ambient texture");
@@ -138,6 +139,7 @@ protected:
bool noTriStripPolygons;
bool generateFacetNormals;
bool fixBlackMaterials;
bool noReverseFaces;
// This is the order in which the materials will be assigned to texture maps, unless
// otherwise overriden
typedef std::vector< std::pair<int,obj::Material::Map::TextureMapType> > TextureAllocationMap;
@@ -486,10 +488,13 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
osg::Vec3Array* vertices = numVertexIndices ? new osg::Vec3Array : 0;
osg::Vec3Array* normals = numNormalIndices ? new osg::Vec3Array : 0;
osg::Vec2Array* texcoords = numTexCoordIndices ? new osg::Vec2Array : 0;
osg::Vec4Array* colors = (!model.colors.empty()) ? new osg::Vec4Array : 0;
if (vertices) vertices->reserve(numVertexIndices);
if (normals) normals->reserve(numNormalIndices);
if (texcoords) texcoords->reserve(numTexCoordIndices);
if (colors) colors->reserve(numVertexIndices);
osg::Geometry* geometry = new osg::Geometry;
if (vertices) geometry->setVertexArray(vertices);
@@ -497,11 +502,17 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
{
geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
}
if (texcoords)
{
geometry->setTexCoordArray(0,texcoords);
}
if (colors)
{
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (numPointElements>0)
{
@@ -518,6 +529,11 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
index_itr != element.vertexIndices.end();
++index_itr)
{
// if use color extension ( not standard but used by meshlab)
if (colors)
{
colors->push_back(model.colors[*index_itr]);
}
vertices->push_back(transformVertex(model.vertices[*index_itr],localOptions.rotate));
++numPoints;
}
@@ -564,6 +580,12 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
index_itr != element.vertexIndices.end();
++index_itr)
{
// if use color extension ( not standard but used by meshlab)
if (colors)
{
colors->push_back(model.colors[*index_itr]);
}
vertices->push_back(transformVertex(model.vertices[*index_itr],localOptions.rotate));
}
if (numNormalIndices)
@@ -592,7 +614,7 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
}
// #define USE_DRAWARRAYLENGTHS
bool hasReversedFaces = false ;
if (numPolygonElements>0)
{
unsigned int startPos = vertices->size();
@@ -633,13 +655,20 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
#endif
if (model.needReverse(element))
if (model.needReverse(element) && !localOptions.noReverseFaces)
{
hasReversedFaces = true;
// need to reverse so add to OSG arrays in same order as in OBJ, as OSG assume anticlockwise ordering.
for(obj::Element::IndexList::reverse_iterator index_itr = element.vertexIndices.rbegin();
index_itr != element.vertexIndices.rend();
++index_itr)
{
// if use color extension ( not standard but used by meshlab)
if (colors)
{
colors->push_back(model.colors[*index_itr]);
}
vertices->push_back(transformVertex(model.vertices[*index_itr],localOptions.rotate));
}
if (numNormalIndices)
@@ -670,6 +699,12 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
index_itr != element.vertexIndices.end();
++index_itr)
{
// if use color extension ( not standard but used by meshlab)
if (colors)
{
colors->push_back(model.colors[*index_itr]);
}
vertices->push_back(transformVertex(model.vertices[*index_itr],localOptions.rotate));
}
if (numNormalIndices)
@@ -693,8 +728,11 @@ osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model,
}
}
}
}
if(hasReversedFaces)
{
OSG_WARN << "Warning: [ReaderWriterOBJ::convertElementListToGeometry] Some faces from geometry '" << geometry->getName() << "' were reversed by the plugin" << std::endl;
}
return geometry;
@@ -787,6 +825,7 @@ ReaderWriterOBJ::ObjOptionsStruct ReaderWriterOBJ::parseOptions(const osgDB::Rea
localOptions.noTriStripPolygons = false;
localOptions.generateFacetNormals = false;
localOptions.fixBlackMaterials = true;
localOptions.noReverseFaces = false;
if (options!=NULL)
{
@@ -825,6 +864,10 @@ ReaderWriterOBJ::ObjOptionsStruct ReaderWriterOBJ::parseOptions(const osgDB::Rea
{
localOptions.generateFacetNormals = true;
}
else if (pre_equals == "noReverseFaces")
{
localOptions.noReverseFaces = true;
}
else if (post_equals.length()>0)
{
obj::Material::Map::TextureMapType type = obj::Material::Map::UNKNOWN;

View File

@@ -29,6 +29,12 @@
using namespace obj;
#ifdef _MSC_VER
#define strncasecmp strnicmp
#endif
static std::string strip( const std::string& ss )
{
std::string result;
@@ -237,7 +243,7 @@ bool Model::readMTL(std::istream& fin)
}
else if (strlen(line)>0)
{
if (strncmp(line,"newmtl ",7)==0)
if (strncasecmp(line,"newmtl ",7)==0)
{
// get material name and left- and right-trim all the white-space
std::string materialName(strip(line+7));
@@ -247,7 +253,7 @@ bool Model::readMTL(std::istream& fin)
}
else if (material)
{
if (strncmp(line,"Ka ",3)==0)
if (strncasecmp(line,"Ka ",3)==0)
{
unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
@@ -274,7 +280,7 @@ bool Model::readMTL(std::istream& fin)
material->ambient[ 3 ] = a;
}
}
else if (strncmp(line,"Kd ",3)==0)
else if (strncasecmp(line,"Kd ",3)==0)
{
unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
@@ -301,7 +307,7 @@ bool Model::readMTL(std::istream& fin)
material->diffuse[ 3 ] = a;
}
}
else if (strncmp(line,"Ks ",3)==0)
else if (strncasecmp(line,"Ks ",3)==0)
{
unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
@@ -328,7 +334,7 @@ bool Model::readMTL(std::istream& fin)
material->specular[ 3 ] = a;
}
}
else if (strncmp(line,"Ke ",3)==0)
else if (strncasecmp(line,"Ke ",3)==0)
{
unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
@@ -355,7 +361,7 @@ bool Model::readMTL(std::istream& fin)
material->emissive[ 3 ] = a;
}
}
else if (strncmp(line,"Tf ",3)==0)
else if (strncasecmp(line,"Tf ",3)==0)
{
unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
@@ -382,28 +388,28 @@ bool Model::readMTL(std::istream& fin)
material->Tf[ 3 ] = a;
}
}
else if (strncmp(line,"sharpness ",10)==0)
else if (strncasecmp(line,"sharpness ",10)==0)
{
float sharpness = 0.0f;
unsigned int fieldsRead = sscanf(line+10,"%f", &sharpness);
if (fieldsRead==1) material->sharpness = sharpness;
}
else if (strncmp(line,"illum ",6)==0)
else if (strncasecmp(line,"illum ",6)==0)
{
int illum = 0;
unsigned int fieldsRead = sscanf(line+6,"%d", &illum);
if (fieldsRead==1) material->illum = illum;
}
else if (strncmp(line,"Ns ",3)==0)
else if (strncasecmp(line,"Ns ",3)==0)
{
int Ns = 0;
unsigned int fieldsRead = sscanf(line+3,"%d", &Ns);
if (fieldsRead==1) material->Ns = Ns;
}
else if (strncmp(line,"Ni ",3)==0)
else if (strncasecmp(line,"Ni ",3)==0)
{
int Ni = 0;
unsigned int fieldsRead = sscanf(line+3,"%d", &Ni);
@@ -431,7 +437,7 @@ bool Model::readMTL(std::istream& fin)
// the value 0 and value 1 for Tr, we will rely on d (dissolve) parameter instead
// whenever it is present. This seems to fix the problem on large number of models.
//
else if (strncmp(line,"Tr ",3)==0)
else if (strncasecmp(line,"Tr ",3)==0)
{
if( !usingDissolve )
{
@@ -456,7 +462,7 @@ bool Model::readMTL(std::istream& fin)
// To be compatible with 3D Max obj exporter,
// d takes precedence over Tr (handled through usingDissolve variable).
//
else if (strncmp(line,"d ",2)==0)
else if (strncasecmp(line,"d ",2)==0)
{
float alpha=1.0f;
unsigned int fieldsRead = sscanf(line+2,"%f", &alpha);
@@ -470,58 +476,58 @@ bool Model::readMTL(std::istream& fin)
usingDissolve = true;
}
}
else if (strncmp(line,"map_Ka ",7)==0)
else if (strncasecmp(line,"map_Ka ",7)==0)
{
material->maps.push_back(parseTextureMap(strip(line+7),Material::Map::AMBIENT));
}
// diffuse map
else if (strncmp(line,"map_Kd ",7)==0)
else if (strncasecmp(line,"map_Kd ",7)==0)
{
material->maps.push_back(parseTextureMap(strip(line+7),Material::Map::DIFFUSE));
}
// specular colour/level map
else if (strncmp(line,"map_Ks ",7)==0)
else if (strncasecmp(line,"map_Ks ",7)==0)
{
material->maps.push_back(parseTextureMap(strip(line+7),Material::Map::SPECULAR));
}
// map_opacity doesn't exist in the spec, but was already in the plugin
// so leave it or plugin will break for some users
else if (strncmp(line,"map_opacity ",12)==0)
else if (strncasecmp(line,"map_opacity ",12)==0)
{
material->maps.push_back(parseTextureMap(strip(line+12),Material::Map::OPACITY));
}
// proper dissolve/opacity map
else if (strncmp(line,"map_d ",6)==0)
else if (strncasecmp(line,"map_d ",6)==0)
{
material->maps.push_back(parseTextureMap(strip(line+6),Material::Map::OPACITY));
}
// specular exponent map
else if (strncmp(line,"map_Ns ",7)==0)
else if (strncasecmp(line,"map_Ns ",7)==0)
{
material->maps.push_back(parseTextureMap(strip(line+7),Material::Map::SPECULAR_EXPONENT));
}
// modelling tools and convertors variously produce bump, map_bump, and map_Bump so parse them all
else if (strncmp(line,"bump ",5)==0)
else if (strncasecmp(line,"bump ",5)==0 || strncasecmp(line,"map_bump ",9)==0)
{
material->maps.push_back(parseTextureMap(strip(line+5),Material::Map::BUMP));
}
else if (strncmp(line,"map_bump ",9)==0)
else if (strncasecmp(line,"map_bump ",9)==0)
{
material->maps.push_back(parseTextureMap(strip(line+9),Material::Map::BUMP));
}
else if (strncmp(line,"map_Bump ",9)==0)
else if (strncasecmp(line,"map_Bump ",9)==0)
{
material->maps.push_back(parseTextureMap(strip(line+9),Material::Map::BUMP));
}
// displacement map
else if (strncmp(line,"disp ",5)==0)
else if (strncasecmp(line,"disp ",5)==0)
{
material->maps.push_back(parseTextureMap(strip(line+5),Material::Map::DISPLACEMENT));
}
// reflection map (the original code had the possibility of a blank "refl" line
// which isn't correct according to the spec, so this bit might break for some
// modelling packages...
else if (strncmp(line,"refl ",5)==0)
else if (strncasecmp(line,"refl ",5)==0)
{
material->maps.push_back(parseTextureMap(strip(line+5),Material::Map::REFLECTION));
}
@@ -553,6 +559,11 @@ std::string trim(const std::string& s)
return std::string(s, b, e - b + 1);
}
inline bool isZBrushColorField(char* line)
{
return strncmp(line, "#MRGB", 5) == 0;
}
bool Model::readOBJ(std::istream& fin, const osgDB::ReaderWriter::Options* options)
{
OSG_INFO<<"Reading OBJ file"<<std::endl;
@@ -560,25 +571,67 @@ bool Model::readOBJ(std::istream& fin, const osgDB::ReaderWriter::Options* optio
const int LINE_SIZE = 4096;
char line[LINE_SIZE];
float x = 0.0f, y = 0.0f, z = 0.0f, w = 0.0f;
float r,g,b,a;
while (fin)
{
readline(fin,line,LINE_SIZE);
if (line[0]=='#' || line[0]=='$')
if ((line[0]=='#' && !isZBrushColorField(line)) || line[0]=='$')
{
// comment line
// OSG_NOTICE <<"Comment: "<<line<<std::endl;
}
else if(isZBrushColorField(line))
{
// Get the zBrush vertex colors given in comments under the form :
// * #MRGB MMRRGGBB MMRRGGBB ... (up to 64 hexadecimal color fields)
std::string colorFields(line + 6);
while (colorFields.size() >= 8)
{
std::string currentValue;
// Skipping the MM component
colorFields = colorFields.substr(2);
currentValue = colorFields.substr(0,2);
r = static_cast<float>(strtol(currentValue.c_str(), NULL, 16)) / 255.;
colorFields = colorFields.substr(2);
currentValue = colorFields.substr(0,2);
g = static_cast<float>(strtol(currentValue.c_str(), NULL, 16)) / 255.;
colorFields = colorFields.substr(2);
currentValue = colorFields.substr(0,2);
b = static_cast<float>(strtol(currentValue.c_str(), NULL, 16)) / 255.;
colorFields = colorFields.substr(2);
colors.push_back(osg::Vec4(r, g, b, 1.0));
}
}
else if (strlen(line)>0)
{
if (strncmp(line,"v ",2)==0)
{
unsigned int fieldsRead = sscanf(line+2,"%f %f %f %f", &x, &y, &z, &w);
unsigned int fieldsRead = sscanf(line+2,"%f %f %f %f %f %f %f", &x, &y, &z, &w, &g, &b, &a);
if (fieldsRead==1) vertices.push_back(osg::Vec3(x,0.0f,0.0f));
else if (fieldsRead==2) vertices.push_back(osg::Vec3(x,y,0.0f));
else if (fieldsRead==3) vertices.push_back(osg::Vec3(x,y,z));
else if (fieldsRead>=4) vertices.push_back(osg::Vec3(x/w,y/w,z/w));
if (fieldsRead==1)
vertices.push_back(osg::Vec3(x,0.0f,0.0f));
else if (fieldsRead==2)
vertices.push_back(osg::Vec3(x,y,0.0f));
else if (fieldsRead==3)
vertices.push_back(osg::Vec3(x,y,z));
else if (fieldsRead == 4)
vertices.push_back(osg::Vec3(x/w,y/w,z/w));
else if (fieldsRead == 6)
{
vertices.push_back(osg::Vec3(x,y,z));
colors.push_back(osg::Vec4(w, g, b, 1.0));
}
else if ( fieldsRead == 7 )
{
vertices.push_back(osg::Vec3(x,y,z));
colors.push_back(osg::Vec4(w, g, b, a));
}
}
else if (strncmp(line,"vn ",3)==0)
{
@@ -625,13 +678,15 @@ bool Model::readOBJ(std::istream& fin, const osgDB::ReaderWriter::Options* optio
{
// OSG_NOTICE<<" vi="<<vi<<"//ni="<<ni<<std::endl;
element->vertexIndices.push_back(remapVertexIndex(vi));
element->normalIndices.push_back(remapNormalIndex(ni));
if (remapNormalIndex(ni) < static_cast<int>(normals.size()))
element->normalIndices.push_back(remapNormalIndex(ni));
}
else if (sscanf(ptr, "%d/%d", &vi, &ti) == 2)
{
// OSG_NOTICE<<" vi="<<vi<<"/ti="<<ti<<std::endl;
element->vertexIndices.push_back(remapVertexIndex(vi));
element->texCoordIndices.push_back(remapTexCoordIndex(ti));
if (remapTexCoordIndex(ti) < static_cast<int>(texcoords.size()))
element->texCoordIndices.push_back(remapTexCoordIndex(ti));
}
else if (sscanf(ptr, "%d", &vi) == 1)
{

View File

@@ -149,6 +149,7 @@ public:
IndexList vertexIndices;
IndexList normalIndices;
IndexList texCoordIndices;
IndexList colorsIndices;
};
class ElementState
@@ -211,6 +212,7 @@ public:
typedef std::map<std::string,Material> MaterialMap;
typedef std::vector< osg::Vec2 > Vec2Array;
typedef std::vector< osg::Vec3 > Vec3Array;
typedef std::vector< osg::Vec4 > Vec4Array;
typedef std::vector< osg::ref_ptr<Element> > ElementList;
typedef std::map< ElementState,ElementList > ElementStateMap;
@@ -219,6 +221,7 @@ public:
MaterialMap materialMap;
Vec3Array vertices;
Vec4Array colors;
Vec3Array normals;
Vec2Array texcoords;