From 78729e28fd33a8112c90e621db9e6448d22725cf Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 24 Dec 2014 11:25:46 +0000 Subject: [PATCH] =?UTF-8?q?From=20Marc=20Helbling,=20=20Cl=C3=A9ment=20L?= =?UTF-8?q?=C3=A9ger,=20Aur=C3=A9lien=20Chatelain,=20Paul=20Cheyrou-Lagr?= =?UTF-8?q?=C3=A8ze=20:=20"a=20last=20submission=20for=20the=20obj=20plugi?= =?UTF-8?q?n=20*=20supports=20vertex=20color=20definition=20after=20vertex?= =?UTF-8?q?=20position=20by=20Cl=C3=A9ment=20L=C3=A9ger=20*=20supports=20z?= =?UTF-8?q?brush=20vertex=20color=20definition=20(as=20#MRGB=20comment)=20?= =?UTF-8?q?by=20Aur=C3=A9lien=20Chatelain=20*=20adds=20a=20noReverseFace?= =?UTF-8?q?=20option=20to=20not=20mess=20with=20face=20definition=20by=20A?= =?UTF-8?q?ur=C3=A9lien=20Chatelain=20*=20makes=20material=20parsing=20cas?= =?UTF-8?q?e=20insensitive=20(by=20Paul=20Cheyrou-Lagr=C3=A8ze=20and=20me)?= =?UTF-8?q?=20*=20makes=20the=20plugin=20resilient=20to=20faulty=20vertex?= =?UTF-8?q?=20uv/normal=20definition=20(i.e.=20when=20a=20too=20big=20inde?= =?UTF-8?q?x=20is=20referenced)=20by=20Aur=C3=A9lien=20hatelain=20"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14641 16af8721-9629-0410-8352-f15c8da7e697 --- src/osgPlugins/obj/ReaderWriterOBJ.cpp | 49 ++++++++++- src/osgPlugins/obj/obj.cpp | 117 ++++++++++++++++++------- src/osgPlugins/obj/obj.h | 3 + 3 files changed, 135 insertions(+), 34 deletions(-) diff --git a/src/osgPlugins/obj/ReaderWriterOBJ.cpp b/src/osgPlugins/obj/ReaderWriterOBJ.cpp index e6f089021..39d7a1ece 100644 --- a/src/osgPlugins/obj/ReaderWriterOBJ.cpp +++ b/src/osgPlugins/obj/ReaderWriterOBJ.cpp @@ -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=", "Set texture unit for diffuse texture"); supportsOption("AMBIENT=", "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 > 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; diff --git a/src/osgPlugins/obj/obj.cpp b/src/osgPlugins/obj/obj.cpp index b9d2c1f14..0f7cd4f98 100644 --- a/src/osgPlugins/obj/obj.cpp +++ b/src/osgPlugins/obj/obj.cpp @@ -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"<= 8) + { + std::string currentValue; + + // Skipping the MM component + colorFields = colorFields.substr(2); + + currentValue = colorFields.substr(0,2); + r = static_cast(strtol(currentValue.c_str(), NULL, 16)) / 255.; + colorFields = colorFields.substr(2); + + currentValue = colorFields.substr(0,2); + g = static_cast(strtol(currentValue.c_str(), NULL, 16)) / 255.; + colorFields = colorFields.substr(2); + + currentValue = colorFields.substr(0,2); + b = static_cast(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="< 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 > ElementList; typedef std::map< ElementState,ElementList > ElementStateMap; @@ -219,6 +221,7 @@ public: MaterialMap materialMap; Vec3Array vertices; + Vec4Array colors; Vec3Array normals; Vec2Array texcoords;