From a7dee1164df4b073d2d68e1cf1b9fa4334610b5c Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Tue, 9 May 2017 14:30:57 +0100 Subject: [PATCH] materials.xml support for osm2city Buildings etc. --- simgear/scene/material/mat.hxx | 79 +++++++++++--------- simgear/scene/model/ModelRegistry.cxx | 11 ++- simgear/scene/model/model.cxx | 30 ++++++++ simgear/scene/model/model.hxx | 12 +++ simgear/scene/tgdb/ReaderWriterSTG.cxx | 64 +++++++++++----- simgear/scene/util/SGReaderWriterOptions.hxx | 30 +++++++- 6 files changed, 165 insertions(+), 61 deletions(-) diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index ee094fa6..ca70bd65 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -122,6 +122,11 @@ public: simgear::Effect* get_one_effect(int texIndex); simgear::Effect* get_effect(); + /** + * Get the Effect Name. + */ + std::string get_effect_name() const { return effect; } + /** * Get the textured state. */ @@ -154,7 +159,7 @@ public: * @return The area (m^2) covered by each light. */ inline double get_light_coverage () const { return light_coverage; } - + /** * Get the building coverage. * @@ -190,12 +195,12 @@ public: * @return The lightmap for auto-generated buildings. */ inline std::string get_building_lightmap () const { return building_lightmap; } - + // Ratio of the 3 random building sizes inline double get_building_small_fraction () const { return building_small_ratio / (building_small_ratio + building_medium_ratio + building_large_ratio); } inline double get_building_medium_fraction () const { return building_medium_ratio / (building_small_ratio + building_medium_ratio + building_large_ratio); } inline double get_building_large_fraction () const { return building_large_ratio / (building_small_ratio + building_medium_ratio + building_large_ratio); } - + // Proportion of buildings with pitched roofs inline double get_building_small_pitch () const { return building_small_pitch; } inline double get_building_medium_pitch () const { return building_medium_pitch; } @@ -208,25 +213,25 @@ public: inline int get_building_medium_max_floors () const { return building_medium_max_floors; } inline int get_building_large_min_floors () const { return building_large_min_floors; } inline int get_building_large_max_floors () const { return building_large_max_floors; } - + // Minimum width and depth for each size inline double get_building_small_min_width () const { return building_small_min_width; } inline double get_building_small_max_width () const { return building_small_max_width; } inline double get_building_small_min_depth () const { return building_small_min_depth; } inline double get_building_small_max_depth () const { return building_small_max_depth; } - + inline double get_building_medium_min_width () const { return building_medium_min_width; } inline double get_building_medium_max_width () const { return building_medium_max_width; } inline double get_building_medium_min_depth () const { return building_medium_min_depth; } inline double get_building_medium_max_depth () const { return building_medium_max_depth; } - + inline double get_building_large_min_width () const { return building_large_min_width; } inline double get_building_large_max_width () const { return building_large_max_width; } inline double get_building_large_min_depth () const { return building_large_min_depth; } inline double get_building_large_max_depth () const { return building_large_max_depth; } - + inline double get_building_range () const { return building_range; } - + inline double get_cos_object_max_density_slope_angle () const { return cos_object_max_density_slope_angle; } inline double get_cos_object_zero_density_slope_angle () const { return cos_object_zero_density_slope_angle; } @@ -238,7 +243,7 @@ public: * @return The area (m^2) covered by each wood. */ inline double get_wood_coverage () const { return wood_coverage; } - + /** * Get the tree height. * @@ -259,14 +264,14 @@ public: * @return The LoD range for the trees. */ inline double get_tree_range () const { return tree_range; } - + /** * Get the number of tree varieties available * * @return the number of different trees defined in the texture strip */ inline int get_tree_varieties () const { return tree_varieties; } - + /** * Get the texture strip to use for trees * @@ -281,25 +286,25 @@ public: * @return the effect to use for this set of trees. */ inline std::string get_tree_effect () const { return tree_effect; } - + /** * Get the cosine of the maximum tree density slope angle. We * use the cosine as it can be compared directly to the z component * of a triangle normal. - * + * * @return the cosine of the maximum tree density slope angle. */ inline double get_cos_tree_max_density_slope_angle () const { return cos_tree_max_density_slope_angle; } - + /** * Get the cosine of the maximum tree density slope angle. We * use the cosine as it can be compared directly to the z component * of a triangle normal. - * + * * @return the cosine of the maximum tree density slope angle. */ inline double get_cos_tree_zero_density_slope_angle () const { return cos_tree_zero_density_slope_angle; } - + /** * Get the list of names for this material */ @@ -321,7 +326,7 @@ public: SGMatModelGroup * get_object_group (int index) const { return object_groups[index]; } - + /** * Evaluate whether this material is valid given the current global * property state and the tile location. @@ -346,7 +351,7 @@ public: return SGVec2f((0 < tex_width) ? 1000.0f/tex_width : 1.0f, (0 < tex_height) ? 1000.0f/tex_height : 1.0f); } - + protected: @@ -394,13 +399,13 @@ private: // coverage of night lighting. double light_coverage; - + // coverage of buildings double building_coverage; - + // building spacing double building_spacing; - + // building texture & lightmap std::string building_texture; std::string building_lightmap; @@ -409,44 +414,44 @@ private: double building_small_ratio; double building_medium_ratio; double building_large_ratio; - + // Proportion of buildings with pitched roofs double building_small_pitch; double building_medium_pitch; double building_large_pitch; // Min/Max number of floors for each size - int building_small_min_floors; + int building_small_min_floors; int building_small_max_floors; int building_medium_min_floors; int building_medium_max_floors; int building_large_min_floors; int building_large_max_floors; - + // Minimum width and depth for each size double building_small_min_width; double building_small_max_width; double building_small_min_depth; double building_small_max_depth; - + double building_medium_min_width; double building_medium_max_width; double building_medium_min_depth; double building_medium_max_depth; - + double building_large_min_width; double building_large_max_width; double building_large_min_depth; double building_large_max_depth; - + double building_range; - - // Cosine of the angle of maximum and zero density, - // used to stop buildings and random objects from being + + // Cosine of the angle of maximum and zero density, + // used to stop buildings and random objects from being // created on too steep a slope. double cos_object_max_density_slope_angle; double cos_object_zero_density_slope_angle; - + // coverage of woods double wood_coverage; @@ -461,7 +466,7 @@ private: // Number of varieties of tree texture int tree_varieties; - + // cosine of the tile angle of maximum and zero density, // used to stop trees from being created on too steep a slope. double cos_tree_max_density_slope_angle; @@ -481,20 +486,20 @@ private: // taxiway-/runway-sign texture elements std::map > glyphs; - + // Tree texture, typically a strip of applicable tree textures std::string tree_texture; // Tree effect to be used for a particular material std::string tree_effect; - + // Object mask, a simple RGB texture used as a mask when placing // random vegetation, objects and buildings std::vector _masks; - + // Condition, indicating when this material is active SGSharedPtr condition; - + // List of geographical rectangles for this material AreaList* areas; @@ -547,4 +552,4 @@ SGSetTextureFilter( int max); int SGGetTextureFilter(); -#endif // _SG_MAT_HXX +#endif // _SG_MAT_HXX diff --git a/simgear/scene/model/ModelRegistry.cxx b/simgear/scene/model/ModelRegistry.cxx index 3eb399d4..f788162a 100644 --- a/simgear/scene/model/ModelRegistry.cxx +++ b/simgear/scene/model/ModelRegistry.cxx @@ -417,8 +417,8 @@ public: // XXX I understand why we want this, but this seems like a weird // place to set this option. #if OSG_VERSION_LESS_THAN(3,5,4) - //RJH - see OSG 11ddd53eb46d15903d036b594bfa3826d9e89393 - - // Removed redundent Referenced::s/getThreadSafeReferenceCounting() and associated static and env vars + //RJH - see OSG 11ddd53eb46d15903d036b594bfa3826d9e89393 - + // Removed redundent Referenced::s/getThreadSafeReferenceCounting() and associated static and env vars // as there are now inapprorpiate and no longer supported Referenced::setThreadSafeReferenceCounting(true); #endif @@ -463,8 +463,13 @@ struct ACOptimizePolicy : public OptimizeModelPolicy { } const SGReaderWriterOptions* sgopt = dynamic_cast(opt); - if (sgopt && sgopt->getInstantiateEffects()) + + if (sgopt && sgopt->getInstantiateMaterialEffects()) { + optimized = instantiateMaterialEffects(optimized.get(), sgopt); + } else if (sgopt && sgopt->getInstantiateEffects()) { optimized = instantiateEffects(optimized.get(), sgopt); + } + return optimized.release(); } }; diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index a7deb4a4..6b34ea9c 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -336,5 +336,35 @@ ref_ptr instantiateEffects(osg::Node* modelGroup, osg::NodeList& result = visitor.getResults(); return ref_ptr(result[0].get()); } + +ref_ptr instantiateMaterialEffects(osg::Node* modelGroup, + const SGReaderWriterOptions* options) +{ + + SGPropertyNode_ptr effect; + PropertyList effectProps; + + if (options->getMaterialLib()) { + const SGGeod loc = SGGeod(options->getLocation()); + SGMaterialCache* matcache = options->getMaterialLib()->generateMatCache(loc); + SGMaterial* mat = matcache->find(options->getMaterialName()); + delete matcache; + + if (mat) { + effect = new SGPropertyNode(); + makeChild(effect, "inherits-from")->setStringValue(mat->get_effect_name()); + } else { + effect = DefaultEffect::instance()->getEffect(); + SG_LOG( SG_TERRAIN, SG_ALERT, "Unable to get effect for " << options->getMaterialName()); + } + } else { + effect = DefaultEffect::instance()->getEffect(); + } + + effect->addChild("default")->setBoolValue(true); + effectProps.push_back(effect); + return instantiateEffects(modelGroup, effectProps, options); +} + } // end of model.cxx diff --git a/simgear/scene/model/model.hxx b/simgear/scene/model/model.hxx index d11ecd16..956d329b 100644 --- a/simgear/scene/model/model.hxx +++ b/simgear/scene/model/model.hxx @@ -104,6 +104,18 @@ instantiateEffects(osg::Node* model, PropertyList& effectProps, const SGReaderWriterOptions* options); +/** + * Apply a set of material-defined effects to a model + * Transform an OSG subgraph by substituting Effects and EffectGeodes + * for osg::Geodes with osg::StateSets. This is only guaranteed to + * work for models prouced by the .ac loader. + * + * returns a copy if any nodes are changed + */ + osg::ref_ptr + instantiateMaterialEffects(osg::Node* model, + const SGReaderWriterOptions* options); + /** * Transform an OSG subgraph by substituting the Effects and * EffectGeodes for osg::Geodes with osg::StateSets, inheriting from diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index 47ab1bf6..dbd1f991 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -53,6 +53,13 @@ #include "SGOceanTile.hxx" +#define BUILDING_ROUGH "OBJECT_BUILDING_MESH_ROUGH" +#define BUILDING_DETAILED "OBJECT_BUILDING_MESH_DETAILED" +#define ROAD_ROUGH "OBJECT_ROAD_ROUGH" +#define ROAD_DETAILED "OBJECT_ROAD_DETAILED" +#define RAILWAY_ROUGH "OBJECT_RAILWAY_ROUGH" +#define RAILWAY_DETAILED "OBJECT_RAILWAY_DETAILED" + namespace simgear { /// Ok, this is a hack - we do not exactly know if it's an airport or not. @@ -393,6 +400,7 @@ struct ReaderWriterSTG::_ModelBin { else opt->setInstantiateEffects(false); _ObjectStatic obj; + obj._errorLocation = absoluteFileName; obj._token = token; obj._name = name; @@ -428,31 +436,51 @@ struct ReaderWriterSTG::_ModelBin { sign._agl = (token == "OBJECT_SIGN_AGL"); in >> sign._lon >> sign._lat >> sign._elev >> sign._hdg >> sign._size; _signList.push_back(sign); - } else if (token == "OBJECT_BUILDING_MESH_ROUGH" || token == "OBJECT_BUILDING_MESH_DETAILED") { - osg::ref_ptr opt; - opt = staticOptions(filePath, options); - if (SGPath(name).lower_extension() == "ac") - opt->setInstantiateEffects(true); - else - opt->setInstantiateEffects(false); - _ObjectStatic obj; - obj._errorLocation = absoluteFileName; - obj._token = token; - obj._name = name; - obj._agl = false; - obj._proxy = true; - in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; + } else if (token == BUILDING_ROUGH || token == BUILDING_DETAILED || + token == ROAD_ROUGH || token == ROAD_DETAILED || + token == RAILWAY_ROUGH || token == RAILWAY_DETAILED) { + osg::ref_ptr opt; + opt = staticOptions(filePath, options); + _ObjectStatic obj; - if (token == "OBJECT_BUILDING_MESH_DETAILED") { - // Apply a lower LOD range if this is a detailed building + opt->setInstantiateEffects(false); + if (SGPath(name).lower_extension() == "ac") { + // Generate material/Effects lookups for raw models, i.e. + // those not wrapped in an XML while will include Effects + opt->setInstantiateMaterialEffects(true); + + if (token == BUILDING_ROUGH || token == BUILDING_DETAILED) { + opt->setMaterialName("OSM_Building"); + } else if (token == ROAD_ROUGH || token == ROAD_DETAILED) { + opt->setMaterialName("OSM_Road"); + } else if (token == RAILWAY_ROUGH || token == RAILWAY_DETAILED) { + opt->setMaterialName("OSM_Railway"); + } else { + // Programming error. If we get here then someone has added a verb to the list of + // tokens above but not in this set of if-else statements. + SG_LOG(SG_TERRAIN, SG_ALERT, "Programming Error - STG token without material branch"); + } + } + + obj._errorLocation = absoluteFileName; + obj._token = token; + obj._name = name; + obj._agl = false; + obj._proxy = true; + in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll; + + opt->setLocation(obj._lon, obj._lat); + if (token == BUILDING_DETAILED || token == ROAD_DETAILED || token == RAILWAY_DETAILED ) { + // Apply a lower LOD range if this is a detailed mesh range = _object_range_detailed; double lrand = mt_rand(&seed); if (lrand < 0.1) range = range * 2.0; else if (lrand < 0.4) range = range * 1.5; } - obj._range = range; - obj._options = opt; + obj._range = range; + + obj._options = opt; checkInsideBucket(absoluteFileName, obj._lon, obj._lat); _objectStaticList.push_back(obj); } else { diff --git a/simgear/scene/util/SGReaderWriterOptions.hxx b/simgear/scene/util/SGReaderWriterOptions.hxx index ce48dce9..10e12732 100644 --- a/simgear/scene/util/SGReaderWriterOptions.hxx +++ b/simgear/scene/util/SGReaderWriterOptions.hxx @@ -42,14 +42,16 @@ public: _materialLib(0), _load_panel(0), _model_data(0), - _instantiateEffects(false) + _instantiateEffects(false), + _instantiateMaterialEffects(false) { } SGReaderWriterOptions(const std::string& str) : osgDB::Options(str), _materialLib(0), _load_panel(0), _model_data(0), - _instantiateEffects(false) + _instantiateEffects(false), + _instantiateMaterialEffects(false) { } SGReaderWriterOptions(const osgDB::Options& options, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : @@ -57,7 +59,8 @@ public: _materialLib(0), _load_panel(0), _model_data(0), - _instantiateEffects(false) + _instantiateEffects(false), + _instantiateMaterialEffects(false) { } SGReaderWriterOptions(const SGReaderWriterOptions& options, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : @@ -70,6 +73,8 @@ public: _load_panel(options._load_panel), _model_data(options._model_data), _instantiateEffects(options._instantiateEffects), + _instantiateMaterialEffects(options._instantiateMaterialEffects), + _materialName(options._materialName), _sceneryPathSuffixes(options._sceneryPathSuffixes) { } @@ -109,6 +114,16 @@ public: void setInstantiateEffects(bool instantiateEffects) { _instantiateEffects = instantiateEffects; } + bool getInstantiateMaterialEffects() const + { return _instantiateMaterialEffects; } + void setInstantiateMaterialEffects(bool instantiateMaterialEffects) + { _instantiateMaterialEffects = instantiateMaterialEffects; } + + string getMaterialName() const + { return _materialName; } + void setMaterialName(string materialName) + { _materialName = materialName; } + const string_list& getSceneryPathSuffixes() const { return _sceneryPathSuffixes; } @@ -118,6 +133,12 @@ public: static SGReaderWriterOptions* copyOrCreate(const osgDB::Options* options); static SGReaderWriterOptions* fromPath(const std::string& path); + void setLocation(double lon, double lat) + { _geod = SGGeod::fromDeg(lon, lat); } + + const SGGeod& getLocation() const + { return _geod; } + protected: virtual ~SGReaderWriterOptions(); @@ -131,7 +152,10 @@ private: osg::Node *(*_load_panel)(SGPropertyNode *); osg::ref_ptr _model_data; bool _instantiateEffects; + bool _instantiateMaterialEffects; + string _materialName; string_list _sceneryPathSuffixes; + SGGeod _geod; }; }