From 7a7b26e75dee4b5939442ff4fd93aeecf8c86a81 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sat, 6 Nov 2021 14:42:23 +0000 Subject: [PATCH] WS30: Initial photoscenery work Hack for hackathon --- simgear/bucket/newbucket.cxx | 47 ++++++++++ simgear/bucket/newbucket.hxx | 1 + simgear/scene/model/ModelRegistry.cxx | 6 +- simgear/scene/tgdb/VPBTechnique.cxx | 128 +++++++++++++++++--------- simgear/scene/tgdb/VPBTechnique.hxx | 3 +- 5 files changed, 137 insertions(+), 48 deletions(-) diff --git a/simgear/bucket/newbucket.cxx b/simgear/bucket/newbucket.cxx index 6832b423..8ee02b38 100644 --- a/simgear/bucket/newbucket.cxx +++ b/simgear/bucket/newbucket.cxx @@ -230,6 +230,53 @@ std::string SGBucket::gen_vpb_base() const { return raw_path; } +std::string SGBucket::gen_vpb_subtile(int level, int x, int y) const { + // long int index; + int top_lon, top_lat, main_lon, main_lat; + char hem, pole; + char raw_path[256]; + + top_lon = lon / 10; + main_lon = lon; + if ( (lon < 0) && (top_lon * 10 != lon) ) { + top_lon -= 1; + } + top_lon *= 10; + if ( top_lon >= 0 ) { + hem = 'e'; + } else { + hem = 'w'; + top_lon *= -1; + } + if ( main_lon < 0 ) { + main_lon *= -1; + } + + top_lat = lat / 10; + main_lat = lat; + if ( (lat < 0) && (top_lat * 10 != lat) ) { + top_lat -= 1; + } + top_lat *= 10; + if ( top_lat >= 0 ) { + pole = 'n'; + } else { + pole = 's'; + top_lat *= -1; + } + if ( main_lat < 0 ) { + main_lat *= -1; + } + + ::snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d/ws_%c%03d%c%02d_root_L0_X0_Y0/ws_%c%03d%c%02d_L%d_X%d_Y%d_subtile", + hem, top_lon, pole, top_lat, + hem, main_lon, pole, main_lat, + hem, main_lon, pole, main_lat, + hem, main_lon, pole, main_lat, + level, x, y); + + return raw_path; +} // Build the path name for this bucket std::string SGBucket::gen_base_path() const { // long int index; diff --git a/simgear/bucket/newbucket.hxx b/simgear/bucket/newbucket.hxx index 6243b146..41c43e02 100644 --- a/simgear/bucket/newbucket.hxx +++ b/simgear/bucket/newbucket.hxx @@ -215,6 +215,7 @@ public: */ std::string gen_vpb_base() const; std::string gen_vpb_base_alt() const; + std::string gen_vpb_subtile(int level, int x, int y) const; /** * @return the center lon of a tile. diff --git a/simgear/scene/model/ModelRegistry.cxx b/simgear/scene/model/ModelRegistry.cxx index ce7acc54..f48b8710 100644 --- a/simgear/scene/model/ModelRegistry.cxx +++ b/simgear/scene/model/ModelRegistry.cxx @@ -1027,9 +1027,9 @@ struct OSGOptimizePolicy : public OptimizeModelPolicy { // Top level. This is likely to have the default GeometryTechnique already assigned which we need to replace with our own terrain->setSampleRatio(features->getVPBSampleRatio()); terrain->setVerticalScale(features->getVPBVerticalScale()); - terrain->setTerrainTechniquePrototype(new VPBTechnique(sgopt)); + terrain->setTerrainTechniquePrototype(new VPBTechnique(sgopt, fileName)); if (terrainTile != NULL) { - terrainTile->setTerrainTechnique(new VPBTechnique(sgopt)); + terrainTile->setTerrainTechnique(new VPBTechnique(sgopt, fileName)); terrainTile->setDirty(true); } else { SG_LOG(SG_TERRAIN, SG_ALERT, "VPB TerrainTile not found"); @@ -1039,7 +1039,7 @@ struct OSGOptimizePolicy : public OptimizeModelPolicy { terrain = new osgTerrain::Terrain; terrain->setSampleRatio(features->getVPBSampleRatio()); terrain->setVerticalScale(features->getVPBVerticalScale()); - terrain->setTerrainTechniquePrototype(new VPBTechnique(sgopt)); + terrain->setTerrainTechniquePrototype(new VPBTechnique(sgopt, fileName)); // if CoordinateSystemNode is present copy it's contents into the Terrain, and discard it. osg::CoordinateSystemNode* csn = findTopMostNodeOfType(optimized.get()); diff --git a/simgear/scene/tgdb/VPBTechnique.cxx b/simgear/scene/tgdb/VPBTechnique.cxx index b36ad0bb..71f882db 100644 --- a/simgear/scene/tgdb/VPBTechnique.cxx +++ b/simgear/scene/tgdb/VPBTechnique.cxx @@ -56,7 +56,8 @@ using namespace osgTerrain; using namespace simgear; -VPBTechnique::VPBTechnique() +VPBTechnique::VPBTechnique(): + _fileName("") { setFilterBias(0); setFilterWidth(0.1); @@ -64,17 +65,20 @@ VPBTechnique::VPBTechnique() _randomObjectsConstraintGroup = new osg::Group(); } -VPBTechnique::VPBTechnique(const SGReaderWriterOptions* options) +VPBTechnique::VPBTechnique(const SGReaderWriterOptions* options, const string& fileName): + _fileName(fileName) { setFilterBias(0); setFilterWidth(0.1); setFilterMatrixAs(GAUSSIAN); setOptions(options); _randomObjectsConstraintGroup = new osg::Group(); + SG_LOG(SG_TERRAIN, SG_ALERT, "VPBTechnique for " << _fileName); } VPBTechnique::VPBTechnique(const VPBTechnique& gt,const osg::CopyOp& copyop): - TerrainTechnique(gt,copyop) + TerrainTechnique(gt,copyop), + _fileName(gt._fileName) { setFilterBias(gt._filterBias); setFilterWidth(gt._filterWidth); @@ -1279,55 +1283,91 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) { - SGMaterialLibPtr matlib = _options->getMaterialLib(); - if (!matlib) return; - osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(0); - if (!colorLayer) return; + const SGPropertyNode* propertyNode = _options->getPropertyNode().get(); + bool photoScenery = false; - osg::Image* image = colorLayer->getImage(); - if (!image || ! image->valid()) return; - - // First time generating this texture, so process to change landclass IDs to texure indexes. - SGPropertyNode_ptr landEffectProp; - - const SGGeod loc = computeCenterGeod(buffer, masterLocator); - SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc); - - SGMaterialCache::Atlas atlas = matlib->generateMatCache(loc, _options)->getAtlas(); - SGMaterialCache::AtlasIndex atlasIndex = atlas.index; - - // Set the "g" color channel to an index into the atlas index. - for (unsigned int s = 0; s < (unsigned int) image->s(); s++) { - for (unsigned int t = 0; t < (unsigned int) image->t(); t++) { - osg::Vec4d c = image->getColor(s, t); - int i = int(round(c.x() * 255.0)); - c.set(c.x(), (double) (atlasIndex[i] / 255.0), c.z(), c.w() ); - image->setColor(c, s, t); - } + if (propertyNode) { + photoScenery = _options->getPropertyNode()->getBoolValue("/sim/rendering/photoscenery/enabled"); } - SG_LOG(SG_TERRAIN, SG_DEBUG, "VPB Image level:" << _terrainTile->getTileID().level << " " << image->s() << "x" << image->t() << " mipmaps:" << image->getNumMipmapLevels() << " format:" << image->getInternalTextureFormat()); + if (photoScenery) { - osg::ref_ptr texture2D = new osg::Texture2D; - texture2D->setImage(image); - texture2D->setMaxAnisotropy(16.0f); - texture2D->setResizeNonPowerOfTwoHint(false); + // Firstly, we need to work out the texture file we want to load. Fortunately this follows the same + // naming convention as the VPB scenery itself. + auto tileID = _terrainTile->getTileID(); + SG_LOG(SG_TERRAIN, SG_ALERT, "Using Photoscenery for " << tileID.level << " X" << tileID.x << " Y" << tileID.y); - // Use mipmaps only in the minimization case because on magnification this results - // in bad interpolation of boundaries between landclasses - texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST); - texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); + const osg::Vec3d world = buffer._transform->getMatrix().getTrans(); + const SGGeod loc = SGGeod::fromCart(toSG(world)); + const SGBucket bucket = SGBucket(loc); - texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); - texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); + // Bit of a hack - we assume the Orthophotos are in the same FG_SCENERY top level as the .osgb tiles. + string base = _fileName.substr(0, _fileName.find("vpb")); + SGPath orthotexture = SGPath(base); + orthotexture.append("Orthophotos"); + orthotexture.append(bucket.gen_vpb_subtile(tileID.level, tileID.x, tileID.y) + ".dds"); + SG_LOG(SG_TERRAIN, SG_ALERT, "Using " << orthotexture); - osg::StateSet* stateset = buffer._landGeode->getOrCreateStateSet(); - stateset->setTextureAttributeAndModes(0, texture2D, osg::StateAttribute::ON); - stateset->setTextureAttributeAndModes(1, atlas.image, osg::StateAttribute::ON); - stateset->setTextureAttributeAndModes(2, atlas.dimensions, osg::StateAttribute::ON); - stateset->setTextureAttributeAndModes(3, atlas.diffuse, osg::StateAttribute::ON); - stateset->setTextureAttributeAndModes(4, atlas.specular, osg::StateAttribute::ON); + if (orthotexture.exists()) { + osg::Texture2D* texture = SGLoadTexture2D(SGPath(orthotexture), _options, false, false); + osg::StateSet* stateset = buffer._landGeode->getOrCreateStateSet(); + stateset->setTextureAttributeAndModes(0, texture); + } else { + SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to find " << orthotexture); + } + + } else { + SGMaterialLibPtr matlib = _options->getMaterialLib(); + if (!matlib) return; + + osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(0); + if (!colorLayer) return; + + osg::Image* image = colorLayer->getImage(); + if (!image || ! image->valid()) return; + + // First time generating this texture, so process to change landclass IDs to texure indexes. + SGPropertyNode_ptr landEffectProp; + + const SGGeod loc = computeCenterGeod(buffer, masterLocator); + SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc); + + SGMaterialCache::Atlas atlas = matlib->generateMatCache(loc, _options)->getAtlas(); + SGMaterialCache::AtlasIndex atlasIndex = atlas.index; + + // Set the "g" color channel to an index into the atlas index. + for (unsigned int s = 0; s < (unsigned int) image->s(); s++) { + for (unsigned int t = 0; t < (unsigned int) image->t(); t++) { + osg::Vec4d c = image->getColor(s, t); + int i = int(round(c.x() * 255.0)); + c.set(c.x(), (double) (atlasIndex[i] / 255.0), c.z(), c.w() ); + image->setColor(c, s, t); + } + } + + SG_LOG(SG_TERRAIN, SG_DEBUG, "VPB Image level:" << _terrainTile->getTileID().level << " " << image->s() << "x" << image->t() << " mipmaps:" << image->getNumMipmapLevels() << " format:" << image->getInternalTextureFormat()); + + osg::ref_ptr texture2D = new osg::Texture2D; + texture2D->setImage(image); + texture2D->setMaxAnisotropy(16.0f); + texture2D->setResizeNonPowerOfTwoHint(false); + + // Use mipmaps only in the minimization case because on magnification this results + // in bad interpolation of boundaries between landclasses + texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST); + texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); + + texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); + texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); + + osg::StateSet* stateset = buffer._landGeode->getOrCreateStateSet(); + stateset->setTextureAttributeAndModes(0, texture2D, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(1, atlas.image, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(2, atlas.dimensions, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(3, atlas.diffuse, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(4, atlas.specular, osg::StateAttribute::ON); + } } double VPBTechnique::det2(const osg::Vec2d a, const osg::Vec2d b) diff --git a/simgear/scene/tgdb/VPBTechnique.hxx b/simgear/scene/tgdb/VPBTechnique.hxx index 18f14f2a..ff5d9395 100644 --- a/simgear/scene/tgdb/VPBTechnique.hxx +++ b/simgear/scene/tgdb/VPBTechnique.hxx @@ -45,7 +45,7 @@ class VPBTechnique : public TerrainTechnique public: VPBTechnique(); - VPBTechnique(const SGReaderWriterOptions* options); + VPBTechnique(const SGReaderWriterOptions* options, const string& fileName); /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ VPBTechnique(const VPBTechnique&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); @@ -199,6 +199,7 @@ class VPBTechnique : public TerrainTechnique osg::Matrix3 _filterMatrix; osg::ref_ptr _filterMatrixUniform; osg::ref_ptr _options; + const string& _fileName; osg::ref_ptr _randomObjectsConstraintGroup; inline static osg::ref_ptr _elevationConstraintGroup = new osg::Group();