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.
This commit is contained in:
Stuart Buchanan 2021-01-13 20:26:28 +00:00
parent d54e9b7675
commit 0a59de8c46
4 changed files with 102 additions and 5 deletions

View File

@ -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;
}

View File

@ -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<osg::Node> 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<osg::Node> node;

View File

@ -21,6 +21,8 @@
#include <osgTerrain/TerrainTile>
#include <osgTerrain/Terrain>
#include <osgUtil/LineSegmentIntersector>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/MeshOptimizers>
#include <osgDB/FileUtils>
@ -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<osg::Node> _constraint; // Object to flatten the terrain under.
TerrainVisitor( osg::ref_ptr<osg::Node> node) :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_constraint(node)
{ }
virtual ~TerrainVisitor()
{ }
void apply(osg::Node& node)
{
osgTerrain::TerrainTile* tile = dynamic_cast<osgTerrain::TerrainTile*>(&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<osg::Node> constraint, osg::Group* terrain)
{
const std::lock_guard<std::mutex> 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<osg::Node> constraint)
{
const std::lock_guard<std::mutex> 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<std::mutex> lock(VPBTechnique::_constraint_mutex); // Lock the _constraintGroup for this scope
osg::ref_ptr<osgUtil::LineSegmentIntersector> 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;
}
}

View File

@ -19,6 +19,8 @@
#ifndef VPBTECHNIQUE
#define VPBTECHNIQUE 1
#include <mutex>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osg/Geometry>
@ -27,6 +29,7 @@
#include <osgTerrain/Locator>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/matlib.hxx>
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<osg::Node> constraint, osg::Group* terrain);
static void removeElevationConstraint(osg::ref_ptr<osg::Node> 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<BufferData> _currentBufferData;
osg::ref_ptr<BufferData> _newBufferData;
@ -125,6 +130,9 @@ class VPBTechnique : public TerrainTechnique
osg::ref_ptr<SGReaderWriterOptions> _options;
osg::ref_ptr<osg::Image> _atlas;
osg::ref_ptr<SGMaterialCache> _matcache;
inline static osg::ref_ptr<osg::Group> _constraintGroup = new osg::Group();;
inline static std::mutex _constraint_mutex; // protects the _constraintGroup;
};
}