WS30: Initial photoscenery work

Hack for hackathon
This commit is contained in:
Stuart Buchanan 2021-11-06 14:42:23 +00:00
parent 6ea99e43f1
commit 7a7b26e75d
5 changed files with 137 additions and 48 deletions

View File

@ -230,6 +230,53 @@ std::string SGBucket::gen_vpb_base() const {
return raw_path; 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 // Build the path name for this bucket
std::string SGBucket::gen_base_path() const { std::string SGBucket::gen_base_path() const {
// long int index; // long int index;

View File

@ -215,6 +215,7 @@ public:
*/ */
std::string gen_vpb_base() const; std::string gen_vpb_base() const;
std::string gen_vpb_base_alt() 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. * @return the center lon of a tile.

View File

@ -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 // 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->setSampleRatio(features->getVPBSampleRatio());
terrain->setVerticalScale(features->getVPBVerticalScale()); terrain->setVerticalScale(features->getVPBVerticalScale());
terrain->setTerrainTechniquePrototype(new VPBTechnique(sgopt)); terrain->setTerrainTechniquePrototype(new VPBTechnique(sgopt, fileName));
if (terrainTile != NULL) { if (terrainTile != NULL) {
terrainTile->setTerrainTechnique(new VPBTechnique(sgopt)); terrainTile->setTerrainTechnique(new VPBTechnique(sgopt, fileName));
terrainTile->setDirty(true); terrainTile->setDirty(true);
} else { } else {
SG_LOG(SG_TERRAIN, SG_ALERT, "VPB TerrainTile not found"); SG_LOG(SG_TERRAIN, SG_ALERT, "VPB TerrainTile not found");
@ -1039,7 +1039,7 @@ struct OSGOptimizePolicy : public OptimizeModelPolicy {
terrain = new osgTerrain::Terrain; terrain = new osgTerrain::Terrain;
terrain->setSampleRatio(features->getVPBSampleRatio()); terrain->setSampleRatio(features->getVPBSampleRatio());
terrain->setVerticalScale(features->getVPBVerticalScale()); 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. // if CoordinateSystemNode is present copy it's contents into the Terrain, and discard it.
osg::CoordinateSystemNode* csn = findTopMostNodeOfType<osg::CoordinateSystemNode>(optimized.get()); osg::CoordinateSystemNode* csn = findTopMostNodeOfType<osg::CoordinateSystemNode>(optimized.get());

View File

@ -56,7 +56,8 @@
using namespace osgTerrain; using namespace osgTerrain;
using namespace simgear; using namespace simgear;
VPBTechnique::VPBTechnique() VPBTechnique::VPBTechnique():
_fileName("")
{ {
setFilterBias(0); setFilterBias(0);
setFilterWidth(0.1); setFilterWidth(0.1);
@ -64,17 +65,20 @@ VPBTechnique::VPBTechnique()
_randomObjectsConstraintGroup = new osg::Group(); _randomObjectsConstraintGroup = new osg::Group();
} }
VPBTechnique::VPBTechnique(const SGReaderWriterOptions* options) VPBTechnique::VPBTechnique(const SGReaderWriterOptions* options, const string& fileName):
_fileName(fileName)
{ {
setFilterBias(0); setFilterBias(0);
setFilterWidth(0.1); setFilterWidth(0.1);
setFilterMatrixAs(GAUSSIAN); setFilterMatrixAs(GAUSSIAN);
setOptions(options); setOptions(options);
_randomObjectsConstraintGroup = new osg::Group(); _randomObjectsConstraintGroup = new osg::Group();
SG_LOG(SG_TERRAIN, SG_ALERT, "VPBTechnique for " << _fileName);
} }
VPBTechnique::VPBTechnique(const VPBTechnique& gt,const osg::CopyOp& copyop): VPBTechnique::VPBTechnique(const VPBTechnique& gt,const osg::CopyOp& copyop):
TerrainTechnique(gt,copyop) TerrainTechnique(gt,copyop),
_fileName(gt._fileName)
{ {
setFilterBias(gt._filterBias); setFilterBias(gt._filterBias);
setFilterWidth(gt._filterWidth); setFilterWidth(gt._filterWidth);
@ -1279,55 +1283,91 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator,
void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
{ {
SGMaterialLibPtr matlib = _options->getMaterialLib();
if (!matlib) return;
osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(0); const SGPropertyNode* propertyNode = _options->getPropertyNode().get();
if (!colorLayer) return; bool photoScenery = false;
osg::Image* image = colorLayer->getImage(); if (propertyNode) {
if (!image || ! image->valid()) return; photoScenery = _options->getPropertyNode()->getBoolValue("/sim/rendering/photoscenery/enabled");
// 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()); if (photoScenery) {
osg::ref_ptr<osg::Texture2D> texture2D = new osg::Texture2D; // Firstly, we need to work out the texture file we want to load. Fortunately this follows the same
texture2D->setImage(image); // naming convention as the VPB scenery itself.
texture2D->setMaxAnisotropy(16.0f); auto tileID = _terrainTile->getTileID();
texture2D->setResizeNonPowerOfTwoHint(false); 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 const osg::Vec3d world = buffer._transform->getMatrix().getTrans();
// in bad interpolation of boundaries between landclasses const SGGeod loc = SGGeod::fromCart(toSG(world));
texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST); const SGBucket bucket = SGBucket(loc);
texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
texture2D->setWrap(osg::Texture::WRAP_S,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.
texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); 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(); if (orthotexture.exists()) {
stateset->setTextureAttributeAndModes(0, texture2D, osg::StateAttribute::ON); osg::Texture2D* texture = SGLoadTexture2D(SGPath(orthotexture), _options, false, false);
stateset->setTextureAttributeAndModes(1, atlas.image, osg::StateAttribute::ON); osg::StateSet* stateset = buffer._landGeode->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(2, atlas.dimensions, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(0, texture);
stateset->setTextureAttributeAndModes(3, atlas.diffuse, osg::StateAttribute::ON); } else {
stateset->setTextureAttributeAndModes(4, atlas.specular, osg::StateAttribute::ON); 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<osg::Texture2D> 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) double VPBTechnique::det2(const osg::Vec2d a, const osg::Vec2d b)

View File

@ -45,7 +45,7 @@ class VPBTechnique : public TerrainTechnique
public: public:
VPBTechnique(); VPBTechnique();
VPBTechnique(const SGReaderWriterOptions* options); VPBTechnique(const SGReaderWriterOptions* options, const string& fileName);
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/ /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
VPBTechnique(const VPBTechnique&,const osg::CopyOp& copyop=osg::CopyOp::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::Matrix3 _filterMatrix;
osg::ref_ptr<osg::Uniform> _filterMatrixUniform; osg::ref_ptr<osg::Uniform> _filterMatrixUniform;
osg::ref_ptr<SGReaderWriterOptions> _options; osg::ref_ptr<SGReaderWriterOptions> _options;
const string& _fileName;
osg::ref_ptr<osg::Group> _randomObjectsConstraintGroup; osg::ref_ptr<osg::Group> _randomObjectsConstraintGroup;
inline static osg::ref_ptr<osg::Group> _elevationConstraintGroup = new osg::Group(); inline static osg::ref_ptr<osg::Group> _elevationConstraintGroup = new osg::Group();