From d74101c72a3d262b0259ed8ab56fa213922c5adf Mon Sep 17 00:00:00 2001 From: Glenn Waldron Date: Thu, 19 Oct 2023 11:19:01 -0400 Subject: [PATCH] Fix issues with terrainoptions api --- .../osgearth_magnify/osgearth_magnify.cpp | 2 +- .../osgearth_minimap/osgearth_minimap.cpp | 2 +- src/osgEarth/FeatureModelGraph.cpp | 3 - src/osgEarth/Geometry.cpp | 2 +- src/osgEarth/ImGui/TerrainGUI | 64 +++--- src/osgEarth/ImageOverlay.cpp | 12 +- src/osgEarth/SDF.cpp | 24 +-- src/osgEarth/TerrainEngineNode | 13 +- src/osgEarth/TerrainEngineNode.cpp | 23 ++- src/osgEarth/TerrainOptions | 15 +- src/osgEarth/TerrainOptions.cpp | 22 ++- src/osgEarthDrivers/engine_rex/EngineContext | 18 +- .../engine_rex/RexTerrainEngineNode | 9 +- .../engine_rex/RexTerrainEngineNode.cpp | 183 +++++------------- src/osgEarthDrivers/engine_rex/TileNode.cpp | 2 +- 15 files changed, 160 insertions(+), 234 deletions(-) diff --git a/src/applications/osgearth_magnify/osgearth_magnify.cpp b/src/applications/osgearth_magnify/osgearth_magnify.cpp index 727ed7d9f8..bfbcc62afc 100644 --- a/src/applications/osgearth_magnify/osgearth_magnify.cpp +++ b/src/applications/osgearth_magnify/osgearth_magnify.cpp @@ -208,7 +208,7 @@ int main(int argc, char** argv) if (arguments.read("--sse")) { app._useLODScale = false; - MapNode::get(node)->getTerrainOptions().setRangeMode(osg::LOD::PIXEL_SIZE_ON_SCREEN); + MapNode::get(node)->getTerrainOptions().setLODMethod(TerrainLODMethod::SCREEN_SPACE); } // Add a UI to the main view: diff --git a/src/applications/osgearth_minimap/osgearth_minimap.cpp b/src/applications/osgearth_minimap/osgearth_minimap.cpp index 2bd2de6370..d6adcaf1ab 100644 --- a/src/applications/osgearth_minimap/osgearth_minimap.cpp +++ b/src/applications/osgearth_minimap/osgearth_minimap.cpp @@ -50,7 +50,7 @@ MapNode* makeMiniMapNode( ) map->addLayer(osm); TerrainOptions terrainOptions; - terrainOptions.rangeMode() = osg::LOD::PIXEL_SIZE_ON_SCREEN; + terrainOptions.lodMethod() = TerrainLODMethod::SCREEN_SPACE; MapNode::Options mapNodeOptions; mapNodeOptions.terrain() = terrainOptions; diff --git a/src/osgEarth/FeatureModelGraph.cpp b/src/osgEarth/FeatureModelGraph.cpp index b68c7cbe42..30b5104e42 100644 --- a/src/osgEarth/FeatureModelGraph.cpp +++ b/src/osgEarth/FeatureModelGraph.cpp @@ -2121,9 +2121,6 @@ FeatureModelGraph::traverse(osg::NodeVisitor& nv) if (nv.getVisitorType() == nv.CULL_VISITOR) { OE_PROFILING_ZONE; - if (!_ownerName.empty()) - OE_PROFILING_ZONE_TEXT(_ownerName); - osg::Group::traverse(nv); } else diff --git a/src/osgEarth/Geometry.cpp b/src/osgEarth/Geometry.cpp index 96cd5436c9..c1b1740d44 100644 --- a/src/osgEarth/Geometry.cpp +++ b/src/osgEarth/Geometry.cpp @@ -820,7 +820,7 @@ Ring::getSignedArea2D() const unsigned int n = size(); double area = 0.0; int j = n - 1; - for (int i = 0; i < n; i++) + for (unsigned i = 0; i < n; i++) { area += ((*this)[j].x() + (*this)[i].x()) * ((*this)[j].y() - (*this)[i].y()); j = i; diff --git a/src/osgEarth/ImGui/TerrainGUI b/src/osgEarth/ImGui/TerrainGUI index 96b2795b2a..f70ccae74e 100644 --- a/src/osgEarth/ImGui/TerrainGUI +++ b/src/osgEarth/ImGui/TerrainGUI @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -94,53 +95,54 @@ namespace osgEarth { ImGuiLTable::Text("Resident Tiles", "%u", _mapNode->getTerrainEngine()->getNumResidentTiles()); - auto terrain_options = _mapNode->getTerrainOptions(); - static int max_max_lod = -1; static unsigned u32_one = 1; - unsigned max_lod = terrain_options.getMaxLOD(); + unsigned max_lod = options.getMaxLOD(); if (max_max_lod < 0) max_max_lod = max_lod; if (ImGuiLTable::InputScalar("Max LOD", ImGuiDataType_U32, &max_lod, &u32_one, nullptr, "%u")) { max_lod = clamp(max_lod, 0u, (unsigned)max_max_lod); - terrain_options.setMaxLOD(max_lod); + options.setMaxLOD(max_lod); } - osg::LOD::RangeMode mode = options.getRangeMode(); - bool mode_b = (mode == osg::LOD::PIXEL_SIZE_ON_SCREEN); - if (ImGuiLTable::Checkbox("Screen space LOD", &mode_b)) + TerrainLODMethod method = options.getLODMethod(); + bool method_b = (method == TerrainLODMethod::SCREEN_SPACE); + if (ImGuiLTable::Checkbox("Screen space LOD", &method_b)) { - _mapNode->getTerrainOptions().setRangeMode(mode_b ? osg::LOD::PIXEL_SIZE_ON_SCREEN : osg::LOD::DISTANCE_FROM_EYE_POINT); + options.setLODMethod(method_b ? TerrainLODMethod::SCREEN_SPACE : TerrainLODMethod::CAMERA_DISTANCE); } - if (_mapNode->getTerrainOptions().getRangeMode() == osg::LOD::PIXEL_SIZE_ON_SCREEN) + if (options.getLODMethod() == TerrainLODMethod::SCREEN_SPACE) { - float tilePixelSize = _mapNode->getTerrainOptions().getTilePixelSize(); - if (ImGuiLTable::SliderFloat("Effective pixel size:", &tilePixelSize, 64.0f, 1024.0f)) + float tilePixelSize = options.getTilePixelSize(); + if (ImGuiLTable::SliderFloat(" Pixels/tile:", &tilePixelSize, 64.0f, 1024.0f)) { - _mapNode->getTerrainOptions().setTilePixelSize(tilePixelSize); + options.setTilePixelSize(tilePixelSize); } } - unsigned maxTex = options.getMaxTextureSize(); - const char* maxTexItems[] = { "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384" }; - unsigned maxTexIndex = 0; - for (maxTexIndex = 0; maxTex > (unsigned)::atoi(maxTexItems[maxTexIndex]) && maxTexIndex < IM_ARRAYSIZE(maxTexItems) - 1; ++maxTexIndex); - if (ImGuiLTable::BeginCombo("Max tex size", maxTexItems[maxTexIndex])) { - for (int n = 0; n < IM_ARRAYSIZE(maxTexItems); n++) { - const bool is_selected = (maxTexIndex == n); - if (ImGui::Selectable(maxTexItems[n], is_selected)) { - maxTexIndex = n; - options.setMaxTextureSize(atoi(maxTexItems[maxTexIndex])); - _mapNode->getTerrainEngine()->dirtyTerrainOptions(); + if (GLUtils::useNVGL()) + { + unsigned maxTex = options.getMaxTextureSize(); + const char* maxTexItems[] = { "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384" }; + unsigned maxTexIndex = 0; + for (maxTexIndex = 0; maxTex > (unsigned)::atoi(maxTexItems[maxTexIndex]) && maxTexIndex < IM_ARRAYSIZE(maxTexItems) - 1; ++maxTexIndex); + if (ImGuiLTable::BeginCombo("Max tex size", maxTexItems[maxTexIndex])) { + for (int n = 0; n < IM_ARRAYSIZE(maxTexItems); n++) { + const bool is_selected = (maxTexIndex == n); + if (ImGui::Selectable(maxTexItems[n], is_selected)) { + maxTexIndex = n; + options.setMaxTextureSize(atoi(maxTexItems[maxTexIndex])); + _mapNode->getTerrainEngine()->dirtyTerrainOptions(); + } + if (is_selected) + ImGui::SetItemDefaultFocus(); } - if (is_selected) - ImGui::SetItemDefaultFocus(); + ImGuiLTable::EndCombo(); } - ImGuiLTable::EndCombo(); } - if (_mapNode->getTerrainOptions().getGPUTessellation()) + if (options.getGPUTessellation()) { ImGui::Separator(); ImGuiLTable::Section("Tessellation"); @@ -154,10 +156,16 @@ namespace osgEarth options.setTessellationRange(range); } + unsigned threads = options.getConcurrency(); + if (ImGuiLTable::SliderInt("Load threads", (int*)&threads, 1, 16)) + { + options.setConcurrency(threads); + _mapNode->getTerrainEngine()->dirtyTerrainOptions(); + } + ImGuiLTable::End(); } - ImGui::Separator(); GeoPoint mp; if (_mapNode->getGeoPointUnderMouse(view(ri), _x, _y, mp)) { diff --git a/src/osgEarth/ImageOverlay.cpp b/src/osgEarth/ImageOverlay.cpp index ee3970ce8e..2e43447ec7 100644 --- a/src/osgEarth/ImageOverlay.cpp +++ b/src/osgEarth/ImageOverlay.cpp @@ -376,13 +376,13 @@ osg::Node* ImageOverlay::createNode() osgEarth::Bounds bounds; - double minX = osg::minimum(_lowerLeft.x(), osg::minimum(_lowerRight.x(), osg::minimum(_upperLeft.x(), _upperRight.x()))); - double minY = osg::minimum(_lowerLeft.y(), osg::minimum(_lowerRight.y(), osg::minimum(_upperLeft.y(), _upperRight.y()))); - double maxX = osg::maximum(_lowerLeft.x(), osg::maximum(_lowerRight.x(), osg::maximum(_upperLeft.x(), _upperRight.x()))); - double maxY = osg::maximum(_lowerLeft.y(), osg::maximum(_lowerRight.y(), osg::maximum(_upperLeft.y(), _upperRight.y()))); + double minX = std::min(_lowerLeft.x(), std::min(_lowerRight.x(), std::min(_upperLeft.x(), _upperRight.x()))); + double minY = std::min(_lowerLeft.y(), std::min(_lowerRight.y(), std::min(_upperLeft.y(), _upperRight.y()))); + double maxX = std::max(_lowerLeft.x(), std::max(_lowerRight.x(), std::max(_upperLeft.x(), _upperRight.x()))); + double maxY = std::max(_lowerLeft.y(), std::max(_lowerRight.y(), std::max(_upperLeft.y(), _upperRight.y()))); - int numCols = osg::maximum(2, (int)((maxX - minX) / targetDegrees) + 1); - int numRows = osg::maximum(2, (int)((maxY - minY) / targetDegrees) + 1); + unsigned numCols = std::max(2, (int)((maxX - minX) / targetDegrees) + 1); + unsigned numRows = std::max(2, (int)((maxY - minY) / targetDegrees) + 1); float dx = 1.0 / (float)(numCols - 1); float dy = 1.0 / (float)(numRows - 1); diff --git a/src/osgEarth/SDF.cpp b/src/osgEarth/SDF.cpp index 070f10c21d..f8b59980c2 100644 --- a/src/osgEarth/SDF.cpp +++ b/src/osgEarth/SDF.cpp @@ -393,9 +393,9 @@ SDFGenerator::compute_nnf_on_cpu(osg::Image* buf) const for (int L = n / 2; L >= 1; L /= 2) { - for (unsigned int iterT = 0; iterT < buf->t(); ++iterT) + for (int iterT = 0; iterT < buf->t(); ++iterT) { - for (unsigned int iterS = 0; iterS < buf->s(); ++iterS) + for (int iterS = 0; iterS < buf->s(); ++iterS) { readRGFloatPixel(imageData, imageWidth, imageHeight, pixel_points_to, iterS, iterT); @@ -456,7 +456,7 @@ static void edt1d(const float* f, float* d, int* v, float* z, unsigned int n) { v[0] = 0; z[0] = -INF; z[1] = INF; - for (int q = 1; q <= n - 1; ++q) { + for (int q = 1; q <= (int)(n - 1); ++q) { float s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]); while (s <= z[k]) { k--; @@ -469,7 +469,7 @@ static void edt1d(const float* f, float* d, int* v, float* z, unsigned int n) { } k = 0; - for (int q = 0; q <= n - 1; ++q) { + for (int q = 0; q <= (int)(n - 1); ++q) { while (z[k + 1] < q) k++; int r = v[k]; @@ -490,21 +490,21 @@ void edt2d(float* grid, unsigned int width, unsigned int height) float* z = new float[maxLength + 1u]; // process columns - for (int x = 0; x < width; ++x) { - for (int y = 0; y < height; ++y) { + for (unsigned x = 0; x < width; ++x) { + for (unsigned y = 0; y < height; ++y) { f[y] = grid[width * y + x]; } // Do the distance transform. edt1d(f, d, v, z, height); // Copy d back into the grid - for (int y = 0; y < height; ++y) { + for (unsigned y = 0; y < height; ++y) { grid[width * y + x] = d[y]; } } // process rows - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { + for (unsigned y = 0; y < height; ++y) { + for (unsigned x = 0; x < width; ++x) { f[x] = grid[width * y + x]; } @@ -512,7 +512,7 @@ void edt2d(float* grid, unsigned int width, unsigned int height) edt1d(f, d, v, z, width); // Copy d back into the grid - for (int x = 0; x < width; ++x) { + for (unsigned x = 0; x < width; ++x) { grid[width * y + x] = d[x]; } } @@ -559,9 +559,9 @@ osg::Image* SDFGenerator::createDistanceField(const osg::Image* image, float min ImageUtils::PixelWriter write(sdf.get()); write.assign(Color(1, 1, 1, 1)); - for (int y = 0; y < height; ++y) + for (unsigned y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) + for (unsigned x = 0; x < width; ++x) { // The distance computed is the square distance, so take the square root here to get the actual distance float d = sqrt(grid[width * y + x]); diff --git a/src/osgEarth/TerrainEngineNode b/src/osgEarth/TerrainEngineNode index 4556a5bb9a..dc8cc0ae14 100644 --- a/src/osgEarth/TerrainEngineNode +++ b/src/osgEarth/TerrainEngineNode @@ -286,14 +286,18 @@ namespace osgEarth void setComputeRangeCallback(ComputeRangeCallback* computeRangeCallback) override; + //! Return the top level node associated with the terrain. osg::Node* getNode() override { return this; } + //! API for accessing or changing terrain options. + //! You should call dirtyTerrainOptions() after changing the options. TerrainOptionsAPI getOptions() override { - return TerrainOptionsAPI(&_options); + return TerrainOptionsAPI(&_optionsConcrete); } + //! Subclass may override this to do something when the terrain options change virtual void dirtyTerrainOptions() { } public: @@ -333,7 +337,10 @@ namespace osgEarth friend class TerrainEngineNodeFactory; //! Assigns a map to render - virtual void setMap(const Map* map, const TerrainOptions& options); + void setMap(const Map* map, const TerrainOptions& options); + + //! Subclass runs this after a call to setMap. + virtual void onSetMap() { } // signals that a redraw is needed because something changed. virtual void requestRedraw(); @@ -363,7 +370,7 @@ namespace osgEarth osg::ref_ptr _terrainInterface; unsigned _dirtyCount; bool _updateScheduled; - TerrainOptions _options; + TerrainOptions _optionsConcrete; typedef std::vector > TerrainEffectVector; TerrainEffectVector effects_; diff --git a/src/osgEarth/TerrainEngineNode.cpp b/src/osgEarth/TerrainEngineNode.cpp index af2c1b71fd..2c6d638c50 100644 --- a/src/osgEarth/TerrainEngineNode.cpp +++ b/src/osgEarth/TerrainEngineNode.cpp @@ -84,15 +84,15 @@ TerrainEngineNode::getResources() const TerrainEngineNode::TerrainEngineNode() : -_dirtyCount ( 0 ), -_requireElevationTextures( false ), -_requireNormalTextures ( false ), -_requireLandCoverTextures( false ), -_requireParentTextures ( false ), -_requireElevationBorder ( false ), -_requireFullDataAtFirstLOD( false ), -_updateScheduled( false ), -_createTileModelCallbacksMutex(OE_MUTEX_NAME) + _dirtyCount(0), + _requireElevationTextures(false), + _requireNormalTextures(false), + _requireLandCoverTextures(false), + _requireParentTextures(false), + _requireElevationBorder(false), + _requireFullDataAtFirstLOD(false), + _updateScheduled(false), + _createTileModelCallbacksMutex(OE_MUTEX_NAME) { // register for event traversals so we can properly reset the dirtyCount ADJUST_EVENT_TRAV_COUNT(this, 1); @@ -142,7 +142,7 @@ TerrainEngineNode::setMap(const Map* map, const TerrainOptions& options) _map = map; // store a const copy of the terrain options - _options = options; + _optionsConcrete = options; // Create a terrain utility interface. This interface can be used // to query the in-memory terrain graph, subscribe to tile events, etc. @@ -174,6 +174,9 @@ TerrainEngineNode::setMap(const Map* map, const TerrainOptions& options) this->setEllipsoidModel(nullptr); } } + + // invoke the callback for a subclass to do its thing + onSetMap(); } osg::BoundingSphere diff --git a/src/osgEarth/TerrainOptions b/src/osgEarth/TerrainOptions index 4b08ed1ff5..7dc3c581b1 100644 --- a/src/osgEarth/TerrainOptions +++ b/src/osgEarth/TerrainOptions @@ -29,6 +29,13 @@ namespace osgEarth { + //! Method to use when determining when to switch terrain levels of detail. + enum class TerrainLODMethod + { + CAMERA_DISTANCE = osg::LOD::DISTANCE_FROM_EYE_POINT, + SCREEN_SPACE = osg::LOD::PIXEL_SIZE_ON_SCREEN + }; + // Options structure for a terrain engine (internal) class OSGEARTH_EXPORT TerrainOptions : public DriverConfigOptions { @@ -55,7 +62,7 @@ namespace osgEarth OE_OPTION(unsigned, maxTilesToUnloadPerFrame); OE_OPTION(unsigned, minResidentTiles); OE_OPTION(bool, castShadows); - OE_OPTION(osg::LOD::RangeMode, rangeMode); + OE_OPTION(TerrainLODMethod, lodMethod); OE_OPTION(float, tilePixelSize); OE_OPTION(float, heightFieldSkirtRatio); OE_OPTION(Color, color); @@ -188,9 +195,9 @@ namespace osgEarth const bool& getCastShadows() const; //! Mode to use when calculating LOD switching distances. - //! Choices are DISTANCE_FROM_EYE_POINT (default) or PIXEL_SIZE_ON_SCREEN - void setRangeMode(const osg::LOD::RangeMode& value); - const osg::LOD::RangeMode& getRangeMode() const; + //! Choices are TerrainLODMode::CAMERA_DISTANCE (default) or TerrainLODMode::SCREEN_SPACE + void setLODMethod(const TerrainLODMethod& value); + const TerrainLODMethod& getLODMethod() const; //! Size of the tile, in pixels, when using rangeMode = PIXEL_SIZE_ON_SCREEN void setTilePixelSize(const float& value); diff --git a/src/osgEarth/TerrainOptions.cpp b/src/osgEarth/TerrainOptions.cpp index 6944ee5b61..2b180c352f 100644 --- a/src/osgEarth/TerrainOptions.cpp +++ b/src/osgEarth/TerrainOptions.cpp @@ -45,8 +45,8 @@ TerrainOptions::getConfig() const conf.set( "compress_normal_maps", _compressNormalMaps); conf.set( "min_normal_map_lod", _minNormalMapLOD ); conf.set( "tessellation", _gpuTessellation ); - conf.set("tessellation_level", tessellationLevel()); - conf.set("tessellation_range", tessellationRange()); + conf.set( "tessellation_level", tessellationLevel()); + conf.set( "tessellation_range", tessellationRange()); conf.set( "debug", _debug ); conf.set( "bin_number", _renderBinNumber ); conf.set( "min_expiry_time", _minExpiryTime); @@ -55,8 +55,10 @@ TerrainOptions::getConfig() const conf.set( "max_tiles_to_unload_per_frame", _maxTilesToUnloadPerFrame); conf.set( "cast_shadows", _castShadows); conf.set( "tile_pixel_size", _tilePixelSize); - conf.set( "range_mode", "PIXEL_SIZE_ON_SCREEN", _rangeMode, osg::LOD::PIXEL_SIZE_ON_SCREEN); - conf.set( "range_mode", "DISTANCE_FROM_EYE_POINT", _rangeMode, osg::LOD::DISTANCE_FROM_EYE_POINT); + conf.set( "lod_method", "screen_space", _lodMethod, TerrainLODMethod::SCREEN_SPACE); + conf.set( "lod_method", "camera_distance", _lodMethod, TerrainLODMethod::CAMERA_DISTANCE); + conf.set( "range_mode", "PIXEL_SIZE_ON_SCREEN", _lodMethod, TerrainLODMethod::SCREEN_SPACE); // backwards compatible + conf.set( "range_mode", "DISTANCE_FROM_EYE_POINT", _lodMethod, TerrainLODMethod::CAMERA_DISTANCE); // backwards compatible conf.set( "skirt_ratio", heightFieldSkirtRatio() ); conf.set( "color", color() ); conf.set( "progressive", progressive() ); @@ -98,7 +100,7 @@ TerrainOptions::fromConfig(const Config& conf) debug().setDefault(false); renderBinNumber().setDefault(0); castShadows().setDefault(false); - rangeMode().setDefault(osg::LOD::DISTANCE_FROM_EYE_POINT); + lodMethod().setDefault(TerrainLODMethod::CAMERA_DISTANCE); tilePixelSize().setDefault(512); minExpiryFrames().setDefault(0); minExpiryTime().setDefault(0.0); @@ -143,10 +145,10 @@ TerrainOptions::fromConfig(const Config& conf) conf.get( "max_tiles_to_unload_per_frame", _maxTilesToUnloadPerFrame); conf.get( "cast_shadows", _castShadows); conf.get( "tile_pixel_size", _tilePixelSize); - conf.get( "range_mode", "PIXEL_SIZE_ON_SCREEN", rangeMode(), osg::LOD::PIXEL_SIZE_ON_SCREEN); - conf.get( "range_mode", "pixel_size", rangeMode(), osg::LOD::PIXEL_SIZE_ON_SCREEN); - conf.get( "range_mode", "DISTANCE_FROM_EYE_POINT", rangeMode(), osg::LOD::DISTANCE_FROM_EYE_POINT); - conf.get( "range_mode", "distance", rangeMode(), osg::LOD::DISTANCE_FROM_EYE_POINT); + conf.get( "lod_method", "screen_space", _lodMethod, TerrainLODMethod::SCREEN_SPACE); + conf.get( "lod_method", "camera_distance", _lodMethod, TerrainLODMethod::CAMERA_DISTANCE); + conf.get( "range_mode", "PIXEL_SIZE_ON_SCREEN", _lodMethod, TerrainLODMethod::SCREEN_SPACE); // backwards compatible + conf.get( "range_mode", "DISTANCE_FROM_EYE_POINT", _lodMethod, TerrainLODMethod::CAMERA_DISTANCE); // backwards compatible conf.get( "skirt_ratio", heightFieldSkirtRatio() ); conf.get( "color", color() ); conf.get( "progressive", progressive() ); @@ -222,7 +224,7 @@ OE_OPTION_IMPL(TerrainOptionsAPI, float, TessellationRange, tessellationRange); OE_OPTION_IMPL(TerrainOptionsAPI, bool, Debug, debug); OE_OPTION_IMPL(TerrainOptionsAPI, int, RenderBinNumber, renderBinNumber); OE_OPTION_IMPL(TerrainOptionsAPI, bool, CastShadows, castShadows); -OE_OPTION_IMPL(TerrainOptionsAPI, osg::LOD::RangeMode, RangeMode, rangeMode); +OE_OPTION_IMPL(TerrainOptionsAPI, TerrainLODMethod, LODMethod, lodMethod) OE_OPTION_IMPL(TerrainOptionsAPI, float, TilePixelSize, tilePixelSize); OE_OPTION_IMPL(TerrainOptionsAPI, unsigned, MinExpiryFrames, minExpiryFrames); OE_OPTION_IMPL(TerrainOptionsAPI, double, MinExpiryTime, minExpiryTime); diff --git a/src/osgEarthDrivers/engine_rex/EngineContext b/src/osgEarthDrivers/engine_rex/EngineContext index 815e1ffde6..f828236423 100644 --- a/src/osgEarthDrivers/engine_rex/EngineContext +++ b/src/osgEarthDrivers/engine_rex/EngineContext @@ -50,15 +50,15 @@ namespace osgEarth { namespace REX { public: EngineContext( - const Map* map, - TerrainEngineNode* engine, - GeometryPool* geometryPool, - Merger* merger, - TileNodeRegistry::Ptr tiles, - const RenderBindings& renderBindings, - const SelectionInfo& selectionInfo, - const FrameClock* clock); - + const Map* map, + TerrainEngineNode* engine, + GeometryPool* geometryPool, + Merger* merger, + TileNodeRegistry::Ptr tiles, + const RenderBindings& renderBindings, + const SelectionInfo& selectionInfo, + const FrameClock* clock); + Merger* getMerger() const { return _merger; } const RenderBindings& getRenderBindings() const { return _renderBindings; } diff --git a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode index dbec4fc277..f359982132 100644 --- a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode +++ b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode @@ -112,7 +112,7 @@ namespace osgEarth { namespace REX protected: // TerrainEngineNode protected - virtual void setMap(const Map* map, const TerrainOptions& options) override; + virtual void onSetMap() override; virtual void updateTextureCombining() override { updateState(); } @@ -148,14 +148,7 @@ namespace osgEarth { namespace REX //! Recompute all cached layer extents void cacheAllLayerExtentsInMapSRS(); - //! computes the heightfield sample size required to match the vertices at the highest - //! level of detail in rex if a tile key was requested at the given level of detail. - unsigned int computeSampleSize(unsigned int levelOfDetail); - private: - const TerrainOptions* _terrainOptions; - const TerrainOptions& options() const { return *_terrainOptions; } - UID _uid; bool _batchUpdateInProgress; bool _refreshRequired; diff --git a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp index 06a1a7a98d..f44382c7df 100644 --- a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp +++ b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp @@ -246,35 +246,28 @@ RexTerrainEngineNode::getNumResidentTiles() const } void -RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) +RexTerrainEngineNode::onSetMap() { - if (!map) return; - - _map = map; - - // Invoke the base class first: - TerrainEngineNode::setMap(map, inOptions); - - // merge in the custom options: - _terrainOptions = &inOptions; + OE_SOFT_ASSERT_AND_RETURN(_map.valid(), void()); _morphingSupported = true; - if (options().rangeMode() == osg::LOD::PIXEL_SIZE_ON_SCREEN) + auto options = getOptions(); + if (options.getLODMethod() ==TerrainLODMethod::SCREEN_SPACE) { - OE_INFO << LC << "Range mode = pixel size; pixel tile size = " << options().tilePixelSize().get() << std::endl; + OE_INFO << LC << "LOD method = pixel size; pixel tile size = " << options.getTilePixelSize() << std::endl; // force morphing off for PSOS mode _morphingSupported = false; } // morphing imagery LODs requires we bind parent textures to their own unit. - if (options().morphImagery() == true && _morphingSupported) + if (options.getMorphImagery() && _morphingSupported) { _requireParentTextures = true; } // Terrain morphing doesn't work in projected maps: - if (map->getSRS()->isProjected()) + if (_map->getSRS()->isProjected()) { _morphTerrainSupported = false; } @@ -286,10 +279,10 @@ RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) if (getStateSet()) getStateSet()->removeDefine("OE_DEBUG_NORMALS"); // check for normal map generation (required for lighting). - this->_requireNormalTextures = (options().useNormalMaps() == true); + this->_requireNormalTextures = (options.getUseNormalMaps() == true); // don't know how to set this up so just do it - this->_requireLandCoverTextures = (options().useLandCover() == true); + this->_requireLandCoverTextures = (options.getUseLandCover() == true); // ensure we get full coverage at the first LOD. this->_requireFullDataAtFirstLOD = true; @@ -300,7 +293,7 @@ RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) // themselves if necessary. _tiles = std::make_shared(); _tiles->setFrameClock(&_clock); - _tiles->setNotifyNeighbors(options().normalizeEdges() == true); + _tiles->setNotifyNeighbors(options.getNormalizeEdges() == true); // A shared geometry pool. _geometryPool = new GeometryPool(); @@ -308,11 +301,11 @@ RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) // Geometry compiler/merger _merger = new Merger(); - _merger->setMergesPerFrame(options().mergesPerFrame().get()); + _merger->setMergesPerFrame(options.getMergesPerFrame()); this->addChild(_merger.get()); // Loader concurrency (size of the thread pool) - unsigned concurrency = options().concurrency().get(); + unsigned concurrency = options.getConcurrency(); const char* concurrency_str = ::getenv("OSGEARTH_TERRAIN_CONCURRENCY"); if (concurrency_str) concurrency = Strings::as(concurrency_str, concurrency); @@ -327,13 +320,13 @@ RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) setupRenderBindings(); // install a layer callback for processing further map actions: - map->addMapCallback(new RexTerrainEngineNodeMapCallbackProxy(this)); + _map->addMapCallback(new RexTerrainEngineNodeMapCallbackProxy(this)); // Prime with existing layers: _batchUpdateInProgress = true; LayerVector layers; - map->getLayers(layers); + _map->getLayers(layers); for (LayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i) addLayer(i->get()); @@ -341,7 +334,7 @@ RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) // Establish a new engine context _engineContext = new EngineContext( - map, + _map.get(), this, // engine _geometryPool.get(), _merger.get(), @@ -351,13 +344,13 @@ RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) &_clock); // Calculate the LOD morphing parameters: - unsigned maxLOD = options().maxLOD().getOrUse(DEFAULT_MAX_LOD); + unsigned maxLOD = options.getMaxLOD(); _selectionInfo.initialize( 0u, // always zero, not the terrain options firstLOD maxLOD, - map->getProfile(), - options().minTileRangeFactor().get(), + _map->getProfile(), + options.getMinTileRangeFactor(), true); // restrict polar subdivision for geographic maps TerrainResources* res = getResources(); @@ -443,18 +436,6 @@ RexTerrainEngineNode::setMap(const Map* map, const TerrainOptions& inOptions) } } ); - - options().tessellationLevelChanged([&](const float& value) - { - getSurfaceStateSet()->getOrCreateUniform( - "oe_terrain_tess", osg::Uniform::FLOAT)->set(value); - }); - - options().tessellationRangeChanged([&](const float& value) - { - getSurfaceStateSet()->getOrCreateUniform( - "oe_terrain_tess_range", osg::Uniform::FLOAT)->set(value); - }); } @@ -565,7 +546,7 @@ RexTerrainEngineNode::refresh(bool forceDirty) // Build the first level of the terrain. // Collect the tile keys comprising the root tiles of the terrain. std::vector keys; - getMap()->getProfile()->getAllKeysAtLOD(options().firstLOD().get(), keys); + getMap()->getProfile()->getAllKeysAtLOD(getOptions().getFirstLOD(), keys); // create a root node for each root tile key. OE_INFO << LC << "Creating " << keys.size() << " root keys." << std::endl; @@ -739,19 +720,25 @@ RexTerrainEngineNode::dirtyTerrainOptions() { TerrainEngineNode::dirtyTerrainOptions(); + auto options = getOptions(); + auto& arena = getEngineContext()->_textures; if (arena) { - arena->setMaxTextureSize(options().maxTextureSize().get()); + arena->setMaxTextureSize(options.getMaxTextureSize()); } - _tiles->setNotifyNeighbors(options().normalizeEdges() == true); - _merger->setMergesPerFrame(options().mergesPerFrame().get()); + _tiles->setNotifyNeighbors(options.getNormalizeEdges() == true); - if (options().concurrency().isSet()) - { - JobArena::setConcurrency(ARENA_LOAD_TILE, options().concurrency().get()); - } + _merger->setMergesPerFrame(options.getMergesPerFrame()); + + JobArena::setConcurrency(ARENA_LOAD_TILE, options.getConcurrency()); + + getSurfaceStateSet()->getOrCreateUniform( + "oe_terrain_tess", osg::Uniform::FLOAT)->set(options.getTessellationLevel()); + + getSurfaceStateSet()->getOrCreateUniform( + "oe_terrain_tess_range", osg::Uniform::FLOAT)->set(options.getTessellationRange()); } void @@ -1056,86 +1043,6 @@ RexTerrainEngineNode::traverse(osg::NodeVisitor& nv) } } -unsigned int -RexTerrainEngineNode::computeSampleSize(unsigned int levelOfDetail) -{ - unsigned maxLevel = osg::minimum(options().maxLOD().get(), 19u); // beyond LOD 19 or 20, morphing starts to lose precision. - unsigned int meshSize = options().tileSize().get(); - - unsigned int sampleSize = meshSize; - int level = maxLevel; // make sure it's signed for the loop below to work - - while (level >= 0 && levelOfDetail != level) - { - sampleSize = sampleSize * 2 - 1; - level--; - } - - return sampleSize; -} - -osg::Vec3d getWorld(const GeoHeightField& geoHF, unsigned int c, unsigned int r) -{ - double x = geoHF.getExtent().xMin() + (double)c * geoHF.getXInterval(); - double y = geoHF.getExtent().yMin() + (double)r * geoHF.getYInterval(); - double h = geoHF.getHeightField()->getHeight(c, r); - - osg::Vec3d world; - GeoPoint point(geoHF.getExtent().getSRS(), x, y, h); - point.toWorld(world); - return world; -} - -osg::Node* renderHeightField(const GeoHeightField& geoHF) -{ - osg::MatrixTransform* mt = new osg::MatrixTransform; - - GeoPoint centroid = geoHF.getExtent().getCentroid(); - - osg::Matrix world2local, local2world; - centroid.createWorldToLocal(world2local); - local2world.invert(world2local); - - mt->setMatrix(local2world); - - osg::Geometry* geometry = new osg::Geometry; - geometry->setName("REX height field"); - geometry->setUseVertexBufferObjects(true); - - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); - mt->addChild(geode); - - osg::Vec3Array* verts = new osg::Vec3Array; - geometry->setVertexArray(verts); - - for (unsigned int c = 0; c < geoHF.getHeightField()->getNumColumns() - 1; c++) - { - for (unsigned int r = 0; r < geoHF.getHeightField()->getNumRows() - 1; r++) - { - // Add two triangles - verts->push_back(getWorld(geoHF, c, r) * world2local); - verts->push_back(getWorld(geoHF, c + 1, r) * world2local); - verts->push_back(getWorld(geoHF, c + 1, r + 1) * world2local); - - verts->push_back(getWorld(geoHF, c, r) * world2local); - verts->push_back(getWorld(geoHF, c + 1, r + 1) * world2local); - verts->push_back(getWorld(geoHF, c, r + 1) * world2local); - } - } - geode->setCullingActive(false); - mt->setCullingActive(false); - - geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, verts->size())); - - osg::Vec4ubArray* colors = new osg::Vec4ubArray(); - colors->push_back(osg::Vec4ub(255, 0, 0, 255)); - geometry->setColorArray(colors, osg::Array::BIND_OVERALL); - mt->getOrCreateStateSet()->setRenderBinDetails(99, "RenderBin"); - - return mt; -} - void RexTerrainEngineNode::onMapModelChanged(const MapModelChange& change) { @@ -1412,6 +1319,8 @@ RexTerrainEngineNode::updateState() // Load up the appropriate shader package: REXShaders& shaders = REXShadersFactory::get(GLUtils::useNVGL()); + auto options = getOptions(); + // State that affects any terrain layer (surface, patch, other) // AND compute shaders { @@ -1431,7 +1340,7 @@ RexTerrainEngineNode::updateState() // vertex-dimension of each standard terrain tile. _terrainSS->setDefine("OE_TILE_SIZE", - std::to_string(options().tileSize().get())); + std::to_string(options.getTileSize())); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) @@ -1470,7 +1379,7 @@ RexTerrainEngineNode::updateState() // untextured terrain skin color _surfaceSS->addUniform(new osg::Uniform( - "oe_terrain_color", options().color().get())); + "oe_terrain_color", options.getColor())); // vertical offset of the terrain verts (cloud layer e.g.) _surfaceSS->addUniform(new osg::Uniform( @@ -1486,13 +1395,13 @@ RexTerrainEngineNode::updateState() shaders.load(surfaceVP, shaders.normal_map()); // GPU tessellation: - if (options().gpuTessellation() == true) + if (options.getGPUTessellation()) { shaders.load(surfaceVP, shaders.tessellation()); // Default tess level - _surfaceSS->addUniform(new osg::Uniform("oe_terrain_tess", options().tessellationLevel().get())); - _surfaceSS->addUniform(new osg::Uniform("oe_terrain_tess_range", options().tessellationRange().get())); + _surfaceSS->addUniform(new osg::Uniform("oe_terrain_tess", options.getTessellationLevel())); + _surfaceSS->addUniform(new osg::Uniform("oe_terrain_tess_range", options.getTessellationRange())); #ifdef HAVE_PATCH_PARAMETER // backwards compatibility @@ -1513,13 +1422,13 @@ RexTerrainEngineNode::updateState() } // Imagery blending - if (options().enableBlending() == true) + if (options.getEnableBlending()) { _surfaceSS->setDefine("OE_TERRAIN_BLEND_IMAGERY"); } // Compressed normal maps - if (options().compressNormalMaps() == true) + if (options.getCompressNormalMaps()) { _surfaceSS->setDefine("OE_COMPRESSED_NORMAL_MAP"); } @@ -1527,18 +1436,18 @@ RexTerrainEngineNode::updateState() // Morphing (imagery and terrain) if (_morphingSupported) { - if ((options().morphTerrain() == true && _morphTerrainSupported == true) || - options().morphImagery() == true) + if ((options.getMorphTerrain() && _morphTerrainSupported) || + (options.getMorphImagery())) { // GL4 morphing is built into another shader (vert.GL4.glsl) if (!GLUtils::useNVGL()) shaders.load(surfaceVP, shaders.morphing()); - if ((options().morphTerrain() == true && _morphTerrainSupported == true)) + if ((options.getMorphTerrain() && _morphTerrainSupported)) { _surfaceSS->setDefine("OE_TERRAIN_MORPH_GEOMETRY"); } - if (options().morphImagery() == true) + if (options.getMorphImagery()) { _surfaceSS->setDefine("OE_TERRAIN_MORPH_IMAGERY"); } @@ -1546,7 +1455,7 @@ RexTerrainEngineNode::updateState() } // Shadowing - if (options().castShadows() == true) + if (options.getCastShadows()) { _surfaceSS->setDefine("OE_TERRAIN_CAST_SHADOWS"); } diff --git a/src/osgEarthDrivers/engine_rex/TileNode.cpp b/src/osgEarthDrivers/engine_rex/TileNode.cpp index 083c362725..2d177a2220 100644 --- a/src/osgEarthDrivers/engine_rex/TileNode.cpp +++ b/src/osgEarthDrivers/engine_rex/TileNode.cpp @@ -367,7 +367,7 @@ TileNode::shouldSubDivide(TerrainCuller* culler, const SelectionInfo& selectionI { // In PSOS mode, subdivide when the on-screen size of a tile exceeds the maximum // allowable on-screen tile size in pixels. - if (_context->options().getRangeMode() == osg::LOD::PIXEL_SIZE_ON_SCREEN) + if (_context->options().getLODMethod() == TerrainLODMethod::SCREEN_SPACE) { float tileSizeInPixels = -1.0;