From ce197ea828f50e3c49a5e8022874bedd5ec4037b Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Thu, 4 Mar 2021 20:20:41 +0000 Subject: [PATCH] WS30 - Improve line feature loading - Mark tiles that require re-loading after .STG loading, removing a race condition - Only re-build line features rather than the entire tile --- simgear/scene/tgdb/LineFeatureBin.cxx | 2 +- simgear/scene/tgdb/ReaderWriterSTG.cxx | 19 +++++-- simgear/scene/tgdb/VPBTechnique.cxx | 72 ++++++++++++++++++++------ simgear/scene/tgdb/VPBTechnique.hxx | 2 +- 4 files changed, 71 insertions(+), 24 deletions(-) diff --git a/simgear/scene/tgdb/LineFeatureBin.cxx b/simgear/scene/tgdb/LineFeatureBin.cxx index b5bd4803..ddf9fbe3 100644 --- a/simgear/scene/tgdb/LineFeatureBin.cxx +++ b/simgear/scene/tgdb/LineFeatureBin.cxx @@ -82,7 +82,7 @@ LineFeatureBin::LineFeatureBin(const SGPath& absoluteFileName, const std::string } while (true) { - float lon = 0.0f, lat=0.0f; + double lon = 0.0f, lat=0.0f; in >> lon >> lat; if (in.bad() || in.fail()) { diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index 496635ca..7eebc870 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -331,7 +331,7 @@ struct ReaderWriterSTG::_ModelBin { lineFeatures.push_back(LineFeatureBin(path, b._material)); } - VPBTechnique::addLineFeatureList(_bucket, lineFeatures); + VPBTechnique::addLineFeatureList(_bucket, lineFeatures, _terrainNode); } return group.release(); @@ -343,6 +343,7 @@ struct ReaderWriterSTG::_ModelBin { std::list<_BuildingList> _buildingList; std::list<_TreeList> _treeList; std::list<_LineFeatureList> _lineFeatureList; + osg::ref_ptr _terrainNode; /// The original options to use for this bunch of models osg::ref_ptr _options; @@ -673,11 +674,12 @@ struct ReaderWriterSTG::_ModelBin { return true; } - std::map tile_map; + std::map > tile_map; osg::Node* load(const SGBucket& bucket, const osgDB::Options* opt) { osg::ref_ptr options; + osg::ref_ptr vpb_node; options = SGReaderWriterOptions::copyOrCreate(opt); float pagedLODExpiry = atoi(options->getPluginStringData("SimGear::PAGED_LOD_EXPIRY").c_str()); @@ -692,15 +694,17 @@ struct ReaderWriterSTG::_ModelBin { if (vpb_active) { std::string filename = "vpb/" + bucket.gen_vpb_base() + ".osgb"; if (tile_map.count(filename) == 0) { - auto vpb_node = osgDB::readRefNodeFile(filename, options); + vpb_node = osgDB::readRefNodeFile(filename, options); if (!vpb_node.valid()) { SG_LOG(SG_TERRAIN, SG_WARN, "Failure to load: " <addChild(vpb_node); - tile_map[filename] = true; + tile_map[filename] = vpb_node; SG_LOG(SG_TERRAIN, SG_INFO, "Loading: " << filename); } + } else { + vpb_node = tile_map[filename]; } // OBJECTs include airports @@ -777,10 +781,15 @@ struct ReaderWriterSTG::_ModelBin { readFileCallback->_objectStaticList = _objectStaticList; readFileCallback->_buildingList = _buildingListList; readFileCallback->_treeList = _treeListList; - readFileCallback->_lineFeatureList = _lineFeatureListList; readFileCallback->_signList = _signList; readFileCallback->_options = options; readFileCallback->_bucket = bucket; + + if (vpb_active) { + readFileCallback->_lineFeatureList = _lineFeatureListList; + readFileCallback->_terrainNode = vpb_node; + } + osg::ref_ptr callbackOptions = new osgDB::Options; callbackOptions->setReadFileCallback(readFileCallback.get()); pagedLOD->setDatabaseOptions(callbackOptions.get()); diff --git a/simgear/scene/tgdb/VPBTechnique.cxx b/simgear/scene/tgdb/VPBTechnique.cxx index 0561dfdc..f76af7c0 100644 --- a/simgear/scene/tgdb/VPBTechnique.cxx +++ b/simgear/scene/tgdb/VPBTechnique.cxx @@ -46,7 +46,7 @@ #include #include #include - +#include #include "VPBTechnique.hxx" #include "TreeBin.hxx" @@ -150,6 +150,20 @@ void VPBTechnique::init(int dirtyMask, bool assumeMultiThreaded) osg::Vec3d centerModel = computeCenterModel(*buffer, masterLocator); + // We use TerrainTile::IMAGERY_DIRTY to (re-)generate features from a .STG file, such as line features + // We use TerrainTile::ELEVATION_DIRTY to regenerate the geometry + if (dirtyMask & TerrainTile::ELEVATION_DIRTY) { + generateGeometry(*buffer, masterLocator, centerModel); + applyColorLayers(*buffer, masterLocator); + applyTrees(*buffer, masterLocator); + } + + if (dirtyMask & TerrainTile::IMAGERY_DIRTY) { + applyLineFeatures(*buffer, masterLocator); + } + + +/* if ((dirtyMask & TerrainTile::IMAGERY_DIRTY)==0) { generateGeometry(*buffer, masterLocator, centerModel); @@ -175,7 +189,7 @@ void VPBTechnique::init(int dirtyMask, bool assumeMultiThreaded) applyTrees(*buffer, masterLocator); applyLineFeatures(*buffer, masterLocator); } - +*/ if (buffer->_transform.valid()) buffer->_transform->setThreadSafeRefUnref(true); if (!_currentBufferData || !assumeMultiThreaded) @@ -1749,17 +1763,16 @@ void VPBTechnique::applyTrees(BufferData& buffer, Locator* masterLocator) void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator) { - int roads_lod_range = 6; + int line_features_lod_range = 6; SGPropertyNode* propertyNode = _options->getPropertyNode().get(); if (propertyNode) { - roads_lod_range = propertyNode->getIntValue("/sim/rendering/static-lod/roads-lod-range", roads_lod_range); + line_features_lod_range = propertyNode->getIntValue("/sim/rendering/static-lod/line-features-lod-range", line_features_lod_range); } // Do not generate vegetation for tiles too far away - //if (_terrainTile->getTileID().level < roads_lod_range) { - if (_terrainTile->getTileID().level < roads_lod_range) { + if (_terrainTile->getTileID().level < line_features_lod_range) { return; } @@ -1835,6 +1848,7 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator) geode->setMaterial(mat); geode->setEffect(mat->get_one_effect(0)); + geode->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) ); buffer._transform->addChild(geode); } } @@ -1853,6 +1867,7 @@ void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocato auto road_iter = road._nodes.begin(); + // This is expensive. SGGeodesy::SGGeodToCart(SGGeod(*road_iter), tmp); ma = toOsg(tmp) - modelCenter; @@ -1864,6 +1879,8 @@ void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocato road_iter++; for (; road_iter != road._nodes.end(); road_iter++) { + + // This is expensive. SGGeodesy::SGGeodToCart(SGGeod(*road_iter), tmp); mb = toOsg(tmp) - modelCenter; @@ -2029,14 +2046,16 @@ void VPBTechnique::releaseGLObjects(osg::State* state) const if (_newBufferData.valid() && _newBufferData->_transform.valid()) _newBufferData->_transform->releaseGLObjects(state); } -// Simple vistor to check for any underlying terrain meshes that contain a given constraint and therefore may need to be modified -// (e.g elevation lowered to ensure the terrain doesn't poke through an airport mesh) +// Simple vistor to check for any underlying terrain meshes that intersect with a given constraint therefore may need to be modified +// (e.g elevation lowered to ensure the terrain doesn't poke through an airport mesh, orn roads generated) class TerrainVisitor : public osg::NodeVisitor { public: osg::ref_ptr _constraint; // Object to flatten the terrain under. - TerrainVisitor( osg::ref_ptr node) : + int _dirtyMask; // Dirty mask to apply. + TerrainVisitor( osg::ref_ptr node, int mask) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), - _constraint(node) + _constraint(node), + _dirtyMask(mask) { } virtual ~TerrainVisitor() { } @@ -2049,9 +2068,8 @@ class TerrainVisitor : public osg::NodeVisitor { // Determine if the constraint should affect this tile. const osg::BoundingSphere tileBB = tile->getBound(); if (tileBB.intersects(_constraint->getBound())) { - // Dirty any existing terrain tiles containing this constraint, which will force regeneration of the elevation mesh. - tile->setDirty(true); - //tile->init(tile->getDirtyMask(), true); + // Dirty any existing terrain tiles containing this constraint, which will force regeneration + tile->setDirtyMask(_dirtyMask); } } else { traverse(node); @@ -2067,7 +2085,7 @@ void VPBTechnique::addElevationConstraint(osg::ref_ptr constraint, os const std::lock_guard lock(VPBTechnique::_constraint_mutex); // Lock the _constraintGroup for this scope _constraintGroup->addChild(constraint.get()); - TerrainVisitor ftv(constraint); + TerrainVisitor ftv(constraint, TerrainTile::ALL_DIRTY); terrain->accept(ftv); } @@ -2099,10 +2117,30 @@ osg::Vec3d VPBTechnique::checkAgainstElevationConstraints(osg::Vec3d origin, osg } } -void VPBTechnique::addLineFeatureList(SGBucket bucket, LineFeatureBinList roadList) +void VPBTechnique::addLineFeatureList(SGBucket bucket, LineFeatureBinList roadList, osg::ref_ptr terrainNode) { - const std::lock_guard lock(VPBTechnique::_lineFeatureLists_mutex); // Lock the _lineFeatureLists for this scope - _lineFeatureLists.push_back(std::pair(bucket, roadList)); + // Block to mutex the List alone + { + const std::lock_guard lock(VPBTechnique::_lineFeatureLists_mutex); // Lock the _lineFeatureLists for this scope + _lineFeatureLists.push_back(std::pair(bucket, roadList)); + } + + // We need to trigger a re-build of the appropriate Terrain tile, so create a pretend node and run the TerrainVisitor to + // "dirty" the TerrainTile that it intersects with. + osg::ref_ptr n = new osg::Node(); + SGVec3d coord1, coord2; + + SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon() -0.5*bucket.get_width(), bucket.get_center_lat() -0.5*bucket.get_height(), 0.0), coord1); + SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon() +0.5*bucket.get_width(), bucket.get_center_lat() +0.5*bucket.get_height(), 0.0), coord2); + //SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon(), bucket.get_center_lat(), 0.0), coord); + //n->setInitialBound(osg::BoundingSphere(toOsg(coord), max(bucket.get_width_m(), bucket.get_height_m()))); + + osg::BoundingBox bbox = osg::BoundingBox(toOsg(coord1), toOsg(coord2)); + n->setInitialBound(bbox); + + SG_LOG(SG_TERRAIN, SG_DEBUG, "Adding line features to " << bucket.gen_index_str()); + TerrainVisitor ftv(n, TerrainTile::IMAGERY_DIRTY); + terrainNode->accept(ftv); } void VPBTechnique::unloadLineFeatures(SGBucket bucket) diff --git a/simgear/scene/tgdb/VPBTechnique.hxx b/simgear/scene/tgdb/VPBTechnique.hxx index f77015ed..fd27aa70 100644 --- a/simgear/scene/tgdb/VPBTechnique.hxx +++ b/simgear/scene/tgdb/VPBTechnique.hxx @@ -95,7 +95,7 @@ class VPBTechnique : public TerrainTechnique static osg::Vec3d checkAgainstElevationConstraints(osg::Vec3d origin, osg::Vec3d vertex, float vertex_gap); // LineFeatures are draped over the underlying mesh. - static void addLineFeatureList(SGBucket bucket, LineFeatureBinList roadList); + static void addLineFeatureList(SGBucket bucket, LineFeatureBinList roadList, osg::ref_ptr terrainNode); static void unloadLineFeatures(SGBucket bucket); protected: