From 3e7f2feb6b9d79ca5be3c190dfc980ec559805fa Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 15 Jan 2014 15:33:42 +0100 Subject: [PATCH 1/9] Identify files in object cache by filename and optional provided options. Objects with the same filename may be different from others based on the provided plugin options. Using filename *and* the provided options as object cache key helps to avoid fetching the wrong object. (cherry picked from commit 85cd1c456f5752628ab43c206f83b263fc04504c) --- include/osgDB/ObjectCache | 11 ++++++----- include/osgDB/Options | 6 ++++-- include/osgDB/Registry | 8 ++++---- src/osgDB/ObjectCache.cpp | 39 +++++++++++++++++++++++++++------------ src/osgDB/Options.cpp | 14 ++++++++++++++ src/osgDB/Registry.cpp | 26 +++++++++++++------------- 6 files changed, 68 insertions(+), 36 deletions(-) diff --git a/include/osgDB/ObjectCache b/include/osgDB/ObjectCache index 624356d14..d6179b51a 100644 --- a/include/osgDB/ObjectCache +++ b/include/osgDB/ObjectCache @@ -50,16 +50,16 @@ class OSGDB_EXPORT ObjectCache : public osg::Referenced void addObjectCache(ObjectCache* object); /** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/ - void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0); + void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0, const Options *options = NULL); /** Remove Object from cache.*/ - void removeFromObjectCache(const std::string& fileName); + void removeFromObjectCache(const std::string& fileName, const Options *options = NULL); /** Get an Object from the object cache*/ - osg::Object* getFromObjectCache(const std::string& fileName); + osg::Object* getFromObjectCache(const std::string& fileName, const Options *options = NULL); /** Get an ref_ptr from the object cache*/ - osg::ref_ptr getRefFromObjectCache(const std::string& fileName); + osg::ref_ptr getRefFromObjectCache(const std::string& fileName, const Options *options = NULL); /** call rleaseGLObjects on all objects attached to the object cache.*/ void releaseGLObjects(osg::State* state); @@ -69,7 +69,8 @@ class OSGDB_EXPORT ObjectCache : public osg::Referenced virtual ~ObjectCache(); typedef std::pair, double > ObjectTimeStampPair; - typedef std::map ObjectCacheMap; + typedef std::pair > FileNameOptionsPair; + typedef std::map ObjectCacheMap; ObjectCacheMap _objectCache; OpenThreads::Mutex _objectCacheMutex; diff --git a/include/osgDB/Options b/include/osgDB/Options index 972221686..0790161de 100644 --- a/include/osgDB/Options +++ b/include/osgDB/Options @@ -255,10 +255,12 @@ class OSGDB_EXPORT Options : public osg::Object /** Get the parentGroup observer_ptr, where the loaded model is intended to be added */ const osg::observer_ptr& getParentGroup() const { return _parentGroup; } - protected: - + bool operator < (const Options &rhs) const; + bool operator == (const Options &rhs) const; virtual ~Options() {} + protected: + std::string _str; FilePathList _databasePaths; diff --git a/include/osgDB/Registry b/include/osgDB/Registry index 6851ccc55..62d4ac884 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -452,16 +452,16 @@ class OSGDB_EXPORT Registry : public osg::Referenced void clearObjectCache(); /** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/ - void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0); + void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0, Options *options = NULL); /** Remove Object from cache.*/ - void removeFromObjectCache(const std::string& fileName); + void removeFromObjectCache(const std::string& fileName, Options *options = NULL); /** Get an Object from the object cache*/ - osg::Object* getFromObjectCache(const std::string& fileName); + osg::Object* getFromObjectCache(const std::string& fileName, Options *options = NULL); /** Get an ref_ptr from the object cache*/ - osg::ref_ptr getRefFromObjectCache(const std::string& fileName); + osg::ref_ptr getRefFromObjectCache(const std::string& fileName, Options *options = NULL); diff --git a/src/osgDB/ObjectCache.cpp b/src/osgDB/ObjectCache.cpp index 8779711e2..856b3d434 100644 --- a/src/osgDB/ObjectCache.cpp +++ b/src/osgDB/ObjectCache.cpp @@ -12,6 +12,7 @@ */ #include +#include using namespace osgDB; @@ -39,34 +40,48 @@ void ObjectCache::addObjectCache(ObjectCache* objectCache) OpenThreads::ScopedLock lock1(_objectCacheMutex); OpenThreads::ScopedLock lock2(objectCache->_objectCacheMutex); - // OSG_NOTICE<<"Inserting objects to main ObjectCache "<_objectCache.size()<_objectCache.size()<_objectCache.begin(), objectCache->_objectCache.end()); } -void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) +void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp, const Options *options) { OpenThreads::ScopedLock lock(_objectCacheMutex); - _objectCache[filename]=ObjectTimeStampPair(object,timestamp); + _objectCache[FileNameOptionsPair(filename, osg::clone(options))] = ObjectTimeStampPair(object,timestamp); + OSG_DEBUG<<"Adding "<getOptionString() : "")<<"' to ObjectCache "< lock(_objectCacheMutex); - ObjectCacheMap::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) return itr->second.first.get(); + ObjectCacheMap::iterator itr = _objectCache.find(FileNameOptionsPair(fileName, options)); + if (itr!=_objectCache.end()) + { + osg::ref_ptr o = itr->first.second; + if (o.valid()) + OSG_DEBUG<<"Found "<getOptionString()<< "' in ObjectCache "<second.first.get(); + } else return 0; } -osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName) +osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName, const Options *options) { OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCacheMap::iterator itr = _objectCache.find(fileName); + ObjectCacheMap::iterator itr; + itr = _objectCache.find(FileNameOptionsPair(fileName, options)); if (itr!=_objectCache.end()) { - // OSG_NOTICE<<"Found "<second.first; + osg::ref_ptr o = itr->first.second; + if (o.valid()) + OSG_DEBUG<<"Found "<getOptionString()<< "' in ObjectCache "<second.first.get(); } else return 0; } @@ -108,10 +123,10 @@ void ObjectCache::removeExpiredObjectsInCache(double expiryTime) } } -void ObjectCache::removeFromObjectCache(const std::string& fileName) +void ObjectCache::removeFromObjectCache(const std::string& fileName, const Options *options) { OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCacheMap::iterator itr = _objectCache.find(fileName); + ObjectCacheMap::iterator itr = _objectCache.find(FileNameOptionsPair(fileName, options)); if (itr!=_objectCache.end()) _objectCache.erase(itr); } diff --git a/src/osgDB/Options.cpp b/src/osgDB/Options.cpp index 1b963b801..1841fcaf2 100644 --- a/src/osgDB/Options.cpp +++ b/src/osgDB/Options.cpp @@ -56,3 +56,17 @@ void Options::parsePluginStringData(const std::string& str, char separator1, cha } } } + +bool Options::operator <(const Options &rhs) const +{ + // TODO add better compare + //OSG_DEBUG << "comparing <'" << _str << "' with '" << rhs._str << "'" << std::endl; + return _str.compare(rhs._str) < 0; +} + +bool Options::operator ==(const Options &rhs) const +{ + // TODO add better compare + //OSG_DEBUG << "comparing == '" << _str << "' with '" << rhs._str << "'" << std::endl; + return _str.compare(rhs._str) == 0; +} diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index f3817a971..d54580e5a 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -1267,9 +1267,9 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun if (useObjectCache) { // search for entry in the object cache. - osg::ref_ptr object = optionsCache ? optionsCache->getRefFromObjectCache(file) : 0; + osg::ref_ptr object = optionsCache ? optionsCache->getRefFromObjectCache(file, options) : 0; - if (!object && _objectCache.valid()) object = _objectCache->getRefFromObjectCache(file); + if (!object && _objectCache.valid()) object = _objectCache->getRefFromObjectCache(file, options); if (object.valid()) { @@ -1281,7 +1281,7 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun if (rr.validObject()) { // search AGAIN for entry in the object cache. - object = _objectCache->getRefFromObjectCache(file); + object = _objectCache->getRefFromObjectCache(file, options); if (object.valid()) { if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); @@ -1292,8 +1292,8 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun } // update cache with new entry. - if (optionsCache) optionsCache->addEntryToObjectCache(file, rr.getObject(), 0.0); - else if (_objectCache.valid()) _objectCache->addEntryToObjectCache(file, rr.getObject(), 0.0); + if (optionsCache) optionsCache->addEntryToObjectCache(file, rr.getObject(), 0.0, options); + else if (_objectCache.valid()) _objectCache->addEntryToObjectCache(file, rr.getObject(), 0.0, options); } else { @@ -1673,19 +1673,19 @@ ReaderWriter::WriteResult Registry::writeScriptImplementation(const Script& imag return result; } -void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) +void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp, Options *options) { - if (_objectCache.valid()) _objectCache->addEntryToObjectCache(filename, object, timestamp); + if (_objectCache.valid()) _objectCache->addEntryToObjectCache(filename, object, timestamp, options); } -osg::Object* Registry::getFromObjectCache(const std::string& filename) +osg::Object* Registry::getFromObjectCache(const std::string& filename, Options *options) { - return _objectCache.valid() ? _objectCache->getFromObjectCache(filename) : 0; + return _objectCache.valid() ? _objectCache->getFromObjectCache(filename, options) : 0; } -osg::ref_ptr Registry::getRefFromObjectCache(const std::string& filename) +osg::ref_ptr Registry::getRefFromObjectCache(const std::string& filename, Options *options) { - return _objectCache.valid() ? _objectCache->getRefFromObjectCache(filename) : 0; + return _objectCache.valid() ? _objectCache->getRefFromObjectCache(filename, options) : 0; } void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(const osg::FrameStamp& frameStamp) @@ -1699,9 +1699,9 @@ void Registry::removeExpiredObjectsInCache(const osg::FrameStamp& frameStamp) if (_objectCache.valid()) _objectCache->removeExpiredObjectsInCache(expiryTime); } -void Registry::removeFromObjectCache(const std::string& filename) +void Registry::removeFromObjectCache(const std::string& filename, Options *options) { - if (_objectCache.valid()) _objectCache->removeFromObjectCache(filename); + if (_objectCache.valid()) _objectCache->removeFromObjectCache(filename, options); } void Registry::clearObjectCache() From 5cc53e1aa2891a4db7491b8ff8373177fa5c67f9 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Fri, 17 Jun 2016 17:48:31 +0200 Subject: [PATCH 2/9] Fix finding object cache entries. (cherry picked from commit 69929f596f4e1db9eefb6092d377466b9674974d) --- include/osgDB/ObjectCache | 10 ++++++++-- src/osgDB/ObjectCache.cpp | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/osgDB/ObjectCache b/include/osgDB/ObjectCache index d6179b51a..01b3f0581 100644 --- a/include/osgDB/ObjectCache +++ b/include/osgDB/ObjectCache @@ -68,9 +68,15 @@ class OSGDB_EXPORT ObjectCache : public osg::Referenced virtual ~ObjectCache(); - typedef std::pair, double > ObjectTimeStampPair; typedef std::pair > FileNameOptionsPair; - typedef std::map ObjectCacheMap; + + class ClassComp { + public: + bool operator() (const ObjectCache::FileNameOptionsPair& lhs, const ObjectCache::FileNameOptionsPair& rhs); + }; + + typedef std::pair, double > ObjectTimeStampPair; + typedef std::map ObjectCacheMap; ObjectCacheMap _objectCache; OpenThreads::Mutex _objectCacheMutex; diff --git a/src/osgDB/ObjectCache.cpp b/src/osgDB/ObjectCache.cpp index 856b3d434..42fe0e752 100644 --- a/src/osgDB/ObjectCache.cpp +++ b/src/osgDB/ObjectCache.cpp @@ -16,6 +16,11 @@ using namespace osgDB; +bool ObjectCache::ClassComp::operator() (const ObjectCache::FileNameOptionsPair& lhs, const ObjectCache::FileNameOptionsPair& rhs) +{ + return lhs.first < rhs.first || *lhs.second < *rhs.second; +} + //////////////////////////////////////////////////////////////////////////////////////////// // // ObjectCache From aa95d3f9bfb9c3d9a4f39d923b04a1c90ba7098b Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Thu, 28 Sep 2017 12:03:30 +0200 Subject: [PATCH 3/9] example_osgobjectcache: Add a check that we really get the correct nodes. (cherry picked from commit 67e6f675e6cf7d5a4f3180c52430cf66aa14be3e) --- examples/osgobjectcache/osgobjectcache.cpp | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/osgobjectcache/osgobjectcache.cpp diff --git a/examples/osgobjectcache/osgobjectcache.cpp b/examples/osgobjectcache/osgobjectcache.cpp new file mode 100644 index 000000000..e894513ae --- /dev/null +++ b/examples/osgobjectcache/osgobjectcache.cpp @@ -0,0 +1,97 @@ +/* OpenSceneGraph example, osgobjectcache. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include +#include + +#include + +#include + +osg::Group* createObjectCache() +{ + osg::Group* group = new osg::Group(); + + if (osgDB::Registry::instance()->getOptions()==0) + osgDB::Registry::instance()->setOptions(new osgDB::Options()); + + osgDB::Registry::instance()->getOptions()->setObjectCacheHint(osgDB::Options::CACHE_ALL); + + osg::ref_ptr options1 = new osgDB::Options("a=1 b=2 c=3"); + options1->setObjectCacheHint(osgDB::Options::CACHE_ALL); + + osg::ref_ptr options2 = new osgDB::Options("a=6 b=7 c=8"); + options2->setObjectCacheHint(osgDB::Options::CACHE_ALL); + + osg::ref_ptr options3 = new osgDB::Options("b=7 a=6 c=8"); + options3->setObjectCacheHint(osgDB::Options::CACHE_ALL); + + osg::ref_ptr node1 = osgDB::readRefNodeFile("cessna.osg"); + osg::ref_ptr node2 = osgDB::readRefNodeFile("cessna.osg"); + osg::ref_ptr node3 = osgDB::readRefNodeFile("cessna.osg", options1.get()); + osg::ref_ptr node4 = osgDB::readRefNodeFile("cessna.osg", options2.get()); + osg::ref_ptr node5 = osgDB::readRefNodeFile("cessna.osg", options1.get()); + osg::ref_ptr node6 = osgDB::readRefNodeFile("cessna.osg", options2.get()); + osg::ref_ptr node7 = osgDB::readRefNodeFile("cessna.osg", options3.get()); + osg::ref_ptr node8 = osgDB::readRefNodeFile("cessna.osg", options3.get()); + + // check that we really get the correct nodes + if (node1 != node2) + { + fprintf(stderr, "error reading node from object cache using default options\n"); + exit(1); + } + + if (node3 != node5) + { + fprintf(stderr, "error reading node from object cache stored with options '%s'\n", options1.get()->getOptionString().c_str()); + exit(1); + } + + if (node4 != node6) + { + fprintf(stderr, "error reading node from object cache stored with options '%s'\n", options2.get()->getOptionString().c_str()); + exit(1); + } + + if (node7 != node8) + { + fprintf(stderr, "error reading node from object cache stored with options '%s'\n", options3.get()->getOptionString().c_str()); + exit(1); + } + + group->addChild(node1); + group->addChild(node2); + group->addChild(node3); + group->addChild(node4); + group->addChild(node5); + group->addChild(node6); + return group; +} + +int main(int , char **) +{ + // construct the viewer. + osgViewer::Viewer viewer; + + // add model to viewer. + viewer.setSceneData(createObjectCache()); + + // create the windows and run the threads. + return viewer.run(); +} From 199651ebbd8b0fa395ba4fa780d198a1125a0f37 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 29 Jun 2016 17:06:48 +0100 Subject: [PATCH 4/9] Added handling of the possibility of null Options pointers (cherry picked from commit e3c48d9f4592e42255285f8d2de520342d048ed9) --- src/osgDB/ObjectCache.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/osgDB/ObjectCache.cpp b/src/osgDB/ObjectCache.cpp index 42fe0e752..11ca07c3a 100644 --- a/src/osgDB/ObjectCache.cpp +++ b/src/osgDB/ObjectCache.cpp @@ -18,7 +18,22 @@ using namespace osgDB; bool ObjectCache::ClassComp::operator() (const ObjectCache::FileNameOptionsPair& lhs, const ObjectCache::FileNameOptionsPair& rhs) { - return lhs.first < rhs.first || *lhs.second < *rhs.second; + // check if filename are the same + if (lhs.first < rhs.first) return true; + if (rhs.first < lhs.first) return false; + + // check if Options pointers are the same. + if (lhs.second == rhs.second) return false; + + // need to compare Options pointers + if (lhs.second.valid() && rhs.second.valid()) + { + // lhs & rhs have valid Options objects + return *lhs.second < *rhs.second; + } + + // finally use pointer comparison, expecting at least one will be NULL pointer + return lhs.second < rhs.second; } //////////////////////////////////////////////////////////////////////////////////////////// From 49ad02dffe66a065b49e53a7a854b1acdad87991 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 25 Sep 2017 13:59:13 +0200 Subject: [PATCH 5/9] obj plugin: Fix bug not using specular color (Ks) for illumination mode > 2 See paragraph "Illumination models" at http://paulbourke.net/dataformats/mtl/ for details. --- src/osgPlugins/obj/ReaderWriterOBJ.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osgPlugins/obj/ReaderWriterOBJ.cpp b/src/osgPlugins/obj/ReaderWriterOBJ.cpp index 39d7a1ece..4de71d288 100644 --- a/src/osgPlugins/obj/ReaderWriterOBJ.cpp +++ b/src/osgPlugins/obj/ReaderWriterOBJ.cpp @@ -333,7 +333,7 @@ void ReaderWriterOBJ::buildMaterialToStateSetMap(obj::Model& model, MaterialToSt osg_material->setDiffuse(osg::Material::FRONT_AND_BACK,material.diffuse); osg_material->setEmission(osg::Material::FRONT_AND_BACK,material.emissive); - if (material.illum == 2) { + if (material.illum >= 2) { osg_material->setSpecular(osg::Material::FRONT_AND_BACK,material.specular); } else { osg_material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,1)); From 03bfcf6a7074678ad10f179a5d7c0a673e720c3a Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 22 May 2019 14:18:55 +0200 Subject: [PATCH 6/9] obj plugin: Make ObjOptionsStruct a real class --- src/osgPlugins/obj/ReaderWriterOBJ.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/osgPlugins/obj/ReaderWriterOBJ.cpp b/src/osgPlugins/obj/ReaderWriterOBJ.cpp index 4de71d288..83703089a 100644 --- a/src/osgPlugins/obj/ReaderWriterOBJ.cpp +++ b/src/osgPlugins/obj/ReaderWriterOBJ.cpp @@ -133,7 +133,8 @@ public: protected: - struct ObjOptionsStruct { + class ObjOptionsStruct { + public: bool rotate; bool noTesselateLargePolygons; bool noTriStripPolygons; @@ -144,6 +145,16 @@ protected: // otherwise overriden typedef std::vector< std::pair > TextureAllocationMap; TextureAllocationMap textureUnitAllocation; + + ObjOptionsStruct() + { + rotate = true; + noTesselateLargePolygons = false; + noTriStripPolygons = false; + generateFacetNormals = false; + fixBlackMaterials = true; + noReverseFaces = false; + } }; typedef std::map< std::string, osg::ref_ptr > MaterialToStateSetMap; @@ -820,12 +831,6 @@ osg::Node* ReaderWriterOBJ::convertModelToSceneGraph(obj::Model& model, ObjOptio ReaderWriterOBJ::ObjOptionsStruct ReaderWriterOBJ::parseOptions(const osgDB::ReaderWriter::Options* options) const { ObjOptionsStruct localOptions; - localOptions.rotate = true; - localOptions.noTesselateLargePolygons = false; - localOptions.noTriStripPolygons = false; - localOptions.generateFacetNormals = false; - localOptions.fixBlackMaterials = true; - localOptions.noReverseFaces = false; if (options!=NULL) { From fa0f09ff84abf5304cda6068a427393f0254161f Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 22 May 2019 14:19:32 +0200 Subject: [PATCH 7/9] obj plugin: add option "NsIfNotPresent=" for setting the specular exponent of a material if not present --- src/osgPlugins/obj/ReaderWriterOBJ.cpp | 11 ++++++++++- src/osgPlugins/obj/obj.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/osgPlugins/obj/ReaderWriterOBJ.cpp b/src/osgPlugins/obj/ReaderWriterOBJ.cpp index 83703089a..99964c5c7 100644 --- a/src/osgPlugins/obj/ReaderWriterOBJ.cpp +++ b/src/osgPlugins/obj/ReaderWriterOBJ.cpp @@ -71,6 +71,7 @@ public: supportsOption("BUMP=", "Set texture unit for bumpmap texture"); supportsOption("DISPLACEMENT=", "Set texture unit for displacement texture"); supportsOption("REFLECTION=", "Set texture unit for reflection texture"); + supportsOption("NsIfNotPresent=", "set specular exponent if not present"); } @@ -145,6 +146,7 @@ protected: // otherwise overriden typedef std::vector< std::pair > TextureAllocationMap; TextureAllocationMap textureUnitAllocation; + int specularExponent; ObjOptionsStruct() { @@ -154,6 +156,7 @@ protected: generateFacetNormals = false; fixBlackMaterials = true; noReverseFaces = false; + specularExponent = -1; } }; @@ -349,7 +352,8 @@ void ReaderWriterOBJ::buildMaterialToStateSetMap(obj::Model& model, MaterialToSt } else { osg_material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,1)); } - osg_material->setShininess(osg::Material::FRONT_AND_BACK,(material.Ns/1000.0f)*128.0f ); // note OBJ shiniess is 0..1000. + int ns = material.Ns != -1 ? material.Ns : localOptions.specularExponent != -1 ? localOptions.specularExponent : 0; + osg_material->setShininess(osg::Material::FRONT_AND_BACK,(ns/1000.0f)*128.0f ); // note OBJ shiniess is 0..1000. if (material.ambient[3]!=1.0 || material.diffuse[3]!=1.0 || @@ -873,6 +877,11 @@ ReaderWriterOBJ::ObjOptionsStruct ReaderWriterOBJ::parseOptions(const osgDB::Rea { localOptions.noReverseFaces = true; } + else if (pre_equals == "NsIfNotPresent") + { + int value = atoi(post_equals.c_str()); + localOptions.specularExponent = value ; + } else if (post_equals.length()>0) { obj::Material::Map::TextureMapType type = obj::Material::Map::UNKNOWN; diff --git a/src/osgPlugins/obj/obj.h b/src/osgPlugins/obj/obj.h index b100ac88d..9d79c533a 100644 --- a/src/osgPlugins/obj/obj.h +++ b/src/osgPlugins/obj/obj.h @@ -43,7 +43,7 @@ public: illum(2), Tf(0.0f,0.0f,0.0f,1.0f), Ni(0), - Ns(0), + Ns(-1), // textureReflection(false), alpha(1.0f) {} From 34b9cceca3ea6e02dc1b8c89d13e9551ead1ec10 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Mon, 15 Jan 2018 14:22:18 +0100 Subject: [PATCH 8/9] obj plugin: Fix not writing material shininess --- src/osgPlugins/obj/OBJWriterNodeVisitor.cpp | 4 ++++ src/osgPlugins/obj/OBJWriterNodeVisitor.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp b/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp index ae8ef986f..27ceb62c1 100644 --- a/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp +++ b/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp @@ -411,6 +411,7 @@ OBJWriterNodeVisitor::OBJMaterial::OBJMaterial(osg::Material* mat, osg::Texture* diffuse(1,1,1,1), ambient(0.2,0.2,0.2,1), specular(0,0,0,1), + shininess(-1), image("") { static unsigned int s_objmaterial_id = 0; @@ -423,6 +424,7 @@ OBJWriterNodeVisitor::OBJMaterial::OBJMaterial(osg::Material* mat, osg::Texture* diffuse = mat->getDiffuse(osg::Material::FRONT); ambient = mat->getAmbient(osg::Material::FRONT); specular = mat->getSpecular(osg::Material::FRONT); + shininess = mat->getShininess(osg::Material::FRONT)*1000.0f/128.0f; } if (tex) { @@ -440,6 +442,8 @@ std::ostream& operator<<(std::ostream& fout, const OBJWriterNodeVisitor::OBJMate fout << " " << "Ka " << mat.ambient << std::endl; fout << " " << "Kd " << mat.diffuse << std::endl; fout << " " << "Ks " << mat.specular << std::endl; + if (mat.shininess != -1) + fout << " " << "Ns " << mat.shininess<< std::endl; if(!mat.image.empty()) fout << " " << "map_Kd " << mat.image << std::endl; diff --git a/src/osgPlugins/obj/OBJWriterNodeVisitor.h b/src/osgPlugins/obj/OBJWriterNodeVisitor.h index 8ef33e614..574effe17 100644 --- a/src/osgPlugins/obj/OBJWriterNodeVisitor.h +++ b/src/osgPlugins/obj/OBJWriterNodeVisitor.h @@ -116,6 +116,7 @@ class OBJWriterNodeVisitor: public osg::NodeVisitor { OBJMaterial(osg::Material* mat, osg::Texture* tex); osg::Vec4 diffuse, ambient, specular; + float shininess; std::string image; std::string name; }; From 6b9e8d85e449045088fc207286393690eb5f7378 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Tue, 16 Jan 2018 10:23:36 +0100 Subject: [PATCH 9/9] obj plugin: Fix bug not adding first vertex index on writing GL_LINExxx array types --- src/osgPlugins/obj/OBJWriterNodeVisitor.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp b/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp index 27ceb62c1..3603e636a 100644 --- a/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp +++ b/src/osgPlugins/obj/OBJWriterNodeVisitor.cpp @@ -370,7 +370,7 @@ void ObjPrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count) for(GLsizei i=0;i