From 0a59de8c46fccd97eaa7caa147825b8e8833a3ad Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Wed, 13 Jan 2021 20:26:28 +0000 Subject: [PATCH] WS3.0: Add elevation constraints for airports Previously if the elevation of the terrain vertices was higher than the airport, the terrain pushed through the airport, looking ugly. This adds the concept of elevation constraint models, which the VPBTechnique applies when generating terrain vertices. Simply add a scenery model to the contraints on the technique, and terrain won't poke through it. --- simgear/io/untar.cxx | 5 +- simgear/scene/tgdb/ReaderWriterSTG.cxx | 13 +++++ simgear/scene/tgdb/VPBTechnique.cxx | 79 +++++++++++++++++++++++++- simgear/scene/tgdb/VPBTechnique.hxx | 10 +++- 4 files changed, 102 insertions(+), 5 deletions(-) diff --git a/simgear/io/untar.cxx b/simgear/io/untar.cxx index f73bbfa3..4cf66372 100644 --- a/simgear/io/untar.cxx +++ b/simgear/io/untar.cxx @@ -730,10 +730,11 @@ ArchiveExtractor::DetermineResult ArchiveExtractor::determineType(const uint8_t* } auto r = isTarData(bytes, count); - if ((r == TarData) || (r == InsufficientData) || (r == GZData)) + if ((r == TarData) || (r == InsufficientData) || (r == GZData)) { return r; + } - return Invalid; + return Invalid; } diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index 36816ed3..b9a0cb95 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -662,6 +662,19 @@ struct ReaderWriterSTG::_ModelBin { SG_LOG(SG_TERRAIN, SG_INFO, "Loading: " << filename); } } + + // OBJECTs include airports + for (auto stgObject : _objectList) { + osg::ref_ptr node; + node = osgDB::readRefNodeFile(stgObject._name, stgObject._options.get()); + + if (!node.valid()) { + SG_LOG(SG_TERRAIN, SG_ALERT, stgObject._errorLocation << ": Failed to load " + << stgObject._token << " '" << stgObject._name << "'"); + continue; + } + terrainGroup->addChild(node.get()); + } } else if (_foundBase) { for (auto stgObject : _objectList) { osg::ref_ptr node; diff --git a/simgear/scene/tgdb/VPBTechnique.cxx b/simgear/scene/tgdb/VPBTechnique.cxx index 669b757b..2756b1b2 100644 --- a/simgear/scene/tgdb/VPBTechnique.cxx +++ b/simgear/scene/tgdb/VPBTechnique.cxx @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include @@ -57,7 +59,6 @@ VPBTechnique::VPBTechnique(const SGReaderWriterOptions* options) setFilterWidth(0.1); setFilterMatrixAs(GAUSSIAN); setOptions(options); - } VPBTechnique::VPBTechnique(const VPBTechnique& gt,const osg::CopyOp& copyop): @@ -505,8 +506,12 @@ void VertexNormalGenerator::populateCenter(osgTerrain::Layer* elevationLayer, La if (validValue) { osg::Vec3d model; + osg::Vec3d origin; + _masterLocator->convertLocalToModel(osg::Vec3d(ndc.x(), ndc.y(), -1000), origin); _masterLocator->convertLocalToModel(ndc, model); + model = VPBTechnique::checkAgainstElevationConstraints(origin, model); + for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin(); itr != layerToTexCoordMap.end(); ++itr) @@ -1447,6 +1452,7 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) atlas = _matcache->getAtlas(); SGMaterialCache::AtlasIndex atlasIndex = atlas.index; + // Set the "g" color channel to an index into the atlas index. for (int s = 0; s < image->s(); s++) { for (int t = 0; t < image->t(); t++) { osg::Vec4 c = image->getColor(s, t); @@ -1614,7 +1620,6 @@ void VPBTechnique::traverse(osg::NodeVisitor& nv) } } - void VPBTechnique::cleanSceneGraph() { } @@ -1625,3 +1630,73 @@ 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) +class TerrainVisitor : public osg::NodeVisitor { + public: + osg::ref_ptr _constraint; // Object to flatten the terrain under. + TerrainVisitor( osg::ref_ptr node) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _constraint(node) + { } + virtual ~TerrainVisitor() + { } + + void apply(osg::Node& node) + { + osgTerrain::TerrainTile* tile = dynamic_cast(&node); + if (tile) + { + // 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); + } + } else { + traverse(node); + } + } +}; + +// Add an osg object representing a contraint on the terrain mesh. The generated terrain mesh will not include any vertices that +// lie above the constraint model. (Note that geometry may result in edges intersecting the constraint model in cases where there +// are significantly higher vertices that lie just outside the constraint model. +void VPBTechnique::addElevationConstraint(osg::ref_ptr constraint, osg::Group* terrain) +{ + const std::lock_guard lock(VPBTechnique::_constraint_mutex); // Lock the _constraintGroup for this scope + _constraintGroup->addChild(constraint.get()); + + TerrainVisitor ftv(constraint); + terrain->accept(ftv); +} + +// Remove a previously added constraint. E.g on model unload. +void VPBTechnique::removeElevationConstraint(osg::ref_ptr constraint) +{ + const std::lock_guard lock(VPBTechnique::_constraint_mutex); // Lock the _constraintGroup for this scope + _constraintGroup->removeChild(constraint.get()); +} + +// Check a given vertex against any elevation constraints E.g. to ensure the terrain mesh doesn't +// poke through any airport meshes. If such a constraint exists, the function will return a replacement +// vertex displaces such that it lies 1m below the contraint relative to the passed in origin. +osg::Vec3d VPBTechnique::checkAgainstElevationConstraints(osg::Vec3d origin, osg::Vec3d vertex) +{ + const std::lock_guard lock(VPBTechnique::_constraint_mutex); // Lock the _constraintGroup for this scope + osg::ref_ptr intersector; + intersector = new osgUtil::LineSegmentIntersector(origin, vertex); + osgUtil::IntersectionVisitor visitor(intersector.get()); + _constraintGroup->accept(visitor); + + if (intersector->containsIntersections()) { + // We have an intersection with our constraints model, so move the terrain vertex to 1m below the intersection point + osg::Vec3d ray = intersector->getFirstIntersection().getWorldIntersectPoint() - origin; + ray.normalize(); + return intersector->getFirstIntersection().getWorldIntersectPoint() - ray*1.0; + } else { + return vertex; + } +} + diff --git a/simgear/scene/tgdb/VPBTechnique.hxx b/simgear/scene/tgdb/VPBTechnique.hxx index 244dcde5..dd8d7f7d 100644 --- a/simgear/scene/tgdb/VPBTechnique.hxx +++ b/simgear/scene/tgdb/VPBTechnique.hxx @@ -19,6 +19,8 @@ #ifndef VPBTECHNIQUE #define VPBTECHNIQUE 1 +#include + #include #include #include @@ -27,6 +29,7 @@ #include #include +#include using namespace osgTerrain; @@ -84,6 +87,9 @@ class VPBTechnique : public TerrainTechnique * for all graphics contexts. */ virtual void releaseGLObjects(osg::State* = 0) const; + static void addElevationConstraint(osg::ref_ptr constraint, osg::Group* terrain); + static void removeElevationConstraint(osg::ref_ptr constraint); + static osg::Vec3d checkAgainstElevationConstraints(osg::Vec3d origin, osg::Vec3d vertex); protected: @@ -111,7 +117,6 @@ class VPBTechnique : public TerrainTechnique virtual void applyTransparency(BufferData& buffer); - OpenThreads::Mutex _writeBufferMutex; osg::ref_ptr _currentBufferData; osg::ref_ptr _newBufferData; @@ -125,6 +130,9 @@ class VPBTechnique : public TerrainTechnique osg::ref_ptr _options; osg::ref_ptr _atlas; osg::ref_ptr _matcache; + + inline static osg::ref_ptr _constraintGroup = new osg::Group();; + inline static std::mutex _constraint_mutex; // protects the _constraintGroup; }; }