diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx index 1498a4435..f48298cec 100644 --- a/src/AIModel/AIBase.cxx +++ b/src/AIModel/AIBase.cxx @@ -310,7 +310,7 @@ void FGAIBase::updateInterior() if(d2 <= _maxRangeInterior){ // if the AI is in-range we load the interior _interior = SGModelLib::loadPagedModel(_modeldata->getInteriorPath(), props, _modeldata); if(_interior.valid()){ - _interior->setRange(0, 0.0, _maxRangeInterior); + _interior->setRange(modelHighDetailIndex, 0.0, _maxRangeInterior); aip.add(_interior.get()); _modeldata->setInteriorLoaded(true); SG_LOG(SG_AI, SG_INFO, "AIBase: Loaded interior model " << _interior->getName()); @@ -322,25 +322,54 @@ void FGAIBase::updateInterior() /** update LOD properties of the model */ void FGAIBase::updateLOD() { - double maxRangeDetail = fgGetDouble("/sim/rendering/static-lod/ai-detailed", 3000.0); - double maxRangeBare = fgGetDouble("/sim/rendering/static-lod/ai-bare", 10000.0); + double maxRangeDetail = fgGetDouble("/sim/rendering/static-lod/aimp-detailed", 3000.0); + double maxRangeBare = fgGetDouble("/sim/rendering/static-lod/aimp-bare", 10000.0); - _maxRangeInterior = fgGetDouble("/sim/rendering/static-lod/ai-interior", 50.0); + _maxRangeInterior = fgGetDouble("/sim/rendering/static-lod/aimp-interior", 50.0); if (_model.valid()) { - if( maxRangeDetail == 0.0 ) + bool pixel_mode = !fgGetBool("/sim/rendering/static-lod/aimp-range-mode-distance", false); + if (pixel_mode) + _model->setRangeMode(osg::LOD::PIXEL_SIZE_ON_SCREEN); + else + _model->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT); + + if (maxRangeDetail < 0) // disable the bare model { - // Disable LOD. The First entry in the LOD node is the most detailed + // Disable LOD. The first entry in the LOD node is the most detailed // so use that. - _model->setRange(0, 0.0, FLT_MAX); if (_model->getNumFileNames() == 2) { - _model->setRange(1, FLT_MAX, FLT_MAX); + _model->setRange(modelHighDetailIndex, 0.0, FLT_MAX); // all ranges. + _model->setRange(modelLowDetailIndex, FLT_MAX, FLT_MAX); } + else + _model->setRange(modelHighDetailIndex , 0.0, FLT_MAX); // all ranges. + } + else if (maxRangeBare == maxRangeDetail) // only use the bare model + { + double start_range, end_range; + if (pixel_mode) { + // pixels, so the start of the range is when we want this to be drawn. this should + // be zero pixels to ensure that something is visible. + start_range = maxRangeDetail; + end_range = FLT_MAX; + } + else { + // meters; so start from 0 end and at the max range. + start_range = maxRangeDetail; + end_range = FLT_MAX; + } + if (_model->getNumFileNames() == 2) { + _model->setRange(modelHighDetailIndex , FLT_MAX, FLT_MAX); + _model->setRange(modelLowDetailIndex , start_range, end_range); + } + else + _model->setRange(modelHighDetailIndex , start_range, end_range); } else { - if( fgGetBool("/sim/rendering/static-lod/ai-range-mode-pixel", false ) ) + if(pixel_mode) { /* In pixel size mode, the range sense is reversed, so we want the * detailed model [0] to be displayed when the "range" is really @@ -356,21 +385,28 @@ void FGAIBase::updateLOD() maxRangeBare = maxRangeDetail; SG_LOG(SG_AI, SG_WARN, - "/sim/rendering/static-lod/ai-bare greater " << - "than /sim/rendering/static-lod/ai-detailed when using " << - "/sim/rendering/static-lod/ai-range-mode-pixel=true. Ignoring ai-bare." + "/sim/rendering/static-lod/aimp-bare greater " << + "than /sim/rendering/static-lod/aimp-detailed when using " << + "/sim/rendering/static-lod/aimp-range-mode-distance=false. Ignoring ai-bare." ); } - _model->setRangeMode( osg::LOD::PIXEL_SIZE_ON_SCREEN ); if (_model->getNumFileNames() == 2) { - _model->setRange(0, maxRangeDetail, 100000 ); - _model->setRange(1, maxRangeBare, maxRangeDetail); + /*if (_model->getRadius() < 0) + { + osg::BoundingSphere bs = _model->computeBound(); + if (bs.radius() > 0) { + _model->setRadius(bs.radius()); + _model->setCenterMode(osg::LOD::CenterMode::USER_DEFINED_CENTER); + } + }*/ + _model->setRange(modelHighDetailIndex , maxRangeDetail, 100000); // most detailed + _model->setRange(modelLowDetailIndex , maxRangeBare, maxRangeDetail); // least detailed } else { /* If we have only one LoD for this model, then we want to * display it from the smallest pixel value */ - _model->setRange(0, min(maxRangeBare, maxRangeDetail), 100000 ); + _model->setRange(modelHighDetailIndex , min(maxRangeBare, maxRangeDetail), 100000 ); } } else { /* In non-pixel range mode we're dealing with straight distance. @@ -384,20 +420,19 @@ void FGAIBase::updateLOD() maxRangeBare = maxRangeDetail; SG_LOG(SG_AI, SG_WARN, - "/sim/rendering/static-lod/ai-bare less than " << - "than /sim/rendering/static-lod/ai-detailed. Ignoring ai-bare." + "/sim/rendering/static-lod/aimp-bare less than " << + "than /sim/rendering/static-lod/aimp-detailed. Ignoring ai-bare." ); } - _model->setRangeMode( osg::LOD:: DISTANCE_FROM_EYE_POINT); if (_model->getNumFileNames() == 2) { - _model->setRange(0, 0, maxRangeDetail); - _model->setRange(1, maxRangeDetail, maxRangeBare); + _model->setRange(modelHighDetailIndex , 0, maxRangeDetail); // most detailed + _model->setRange(modelLowDetailIndex , maxRangeDetail, maxRangeDetail+maxRangeBare); // least detailed } else { /* If we have only one LoD for this model, then we want to * display it from whatever range. */ - _model->setRange(0, 0, max(maxRangeBare, maxRangeDetail)); + _model->setRange(modelHighDetailIndex , 0, max(maxRangeBare, maxRangeDetail)); } } } @@ -488,11 +523,13 @@ std::vector FGAIBase::resolveModelPath(ModelSearchOrder searchOrder } // At this point we're looking for a regular model to display at closer range. + // From experimentation it seems to work best if the LODs are in the range list in terms of detail + // from lowest to highest - so insert this at the end. auto p = simgear::SGModelLib::findDataFile(model_path); if (!p.empty()) { _installed = true; SG_LOG(SG_AI, SG_DEBUG, "Found DATA model " << p); - path_list.insert(path_list.begin(), p); + path_list.insert(path_list.end(), p); } } @@ -520,6 +557,7 @@ bool FGAIBase::init(ModelSearchOrder searchOrder) vector model_list = resolveModelPath(searchOrder); _model= SGModelLib::loadPagedModel(model_list, props, _modeldata); _model->setName("AI-model range animation node"); + _model->setRadius(getDefaultModelRadius()); updateLOD(); initModel(); diff --git a/src/AIModel/AIBase.hxx b/src/AIModel/AIBase.hxx index 3de51a261..919f0b942 100644 --- a/src/AIModel/AIBase.hxx +++ b/src/AIModel/AIBase.hxx @@ -55,6 +55,12 @@ public: FGAIBase(object_type ot, bool enableHot); virtual ~FGAIBase(); + // these depend on the order in which the models are loaded. OSG is a little vague about this, but + // from experimentation it seems to work best if the LODs are in the range list in terms of detail + // from lowest to highest + const int modelLowDetailIndex = 0; + const int modelHighDetailIndex = 1; + virtual void readFromScenario(SGPropertyNode* scFileNode); enum ModelSearchOrder { @@ -69,7 +75,8 @@ public: virtual void bind(); virtual void unbind(); virtual void reinit() {} - + // default model radius for LOD. + virtual double getDefaultModelRadius() { return 20.0; } void updateLOD(); void updateInterior(); void setManager(FGAIManager* mgr, SGPropertyNode* p); diff --git a/src/AIModel/AICarrier.hxx b/src/AIModel/AICarrier.hxx index 75dfdba16..69ba58154 100644 --- a/src/AIModel/AICarrier.hxx +++ b/src/AIModel/AICarrier.hxx @@ -48,6 +48,7 @@ public: void setSign(const string& ); void setDeckAltitude(const double altitude_feet); void setTACANChannelID(const string &); + virtual double getDefaultModelRadius() { return 350.0; } virtual void bind(); void UpdateWind ( double dt ); diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx index 87c8197e3..83b447b2c 100644 --- a/src/AIModel/AIManager.cxx +++ b/src/AIModel/AIManager.cxx @@ -105,9 +105,9 @@ private: FGAIManager::FGAIManager() : cb_ai_bare(SGPropertyChangeCallback(this,&FGAIManager::updateLOD, - fgGetNode("/sim/rendering/static-lod/ai-bare", true))), + fgGetNode("/sim/rendering/static-lod/aimp-bare", true))), cb_ai_detailed(SGPropertyChangeCallback(this,&FGAIManager::updateLOD, - fgGetNode("/sim/rendering/static-lod/ai-detailed", true))) + fgGetNode("/sim/rendering/static-lod/aimp-detailed", true))) { } diff --git a/src/AIModel/AIShip.hxx b/src/AIModel/AIShip.hxx index c0f62133a..4bb1862a8 100644 --- a/src/AIModel/AIShip.hxx +++ b/src/AIModel/AIShip.hxx @@ -41,6 +41,7 @@ public: virtual void bind(); virtual void update(double dt); virtual void reinit(); + virtual double getDefaultModelRadius() { return 200.0; } void setRudder(float r); void setRoll(double rl); diff --git a/src/Scenery/terrain_pgt.cxx b/src/Scenery/terrain_pgt.cxx index d3811d28b..a80fd8fe1 100644 --- a/src/Scenery/terrain_pgt.cxx +++ b/src/Scenery/terrain_pgt.cxx @@ -84,8 +84,8 @@ void FGPgtTerrain::init( osg::Group* terrain ) { options->setPluginStringData("SimGear::FG_ROOT", globals->get_fg_root().local8BitStr()); - options->setPluginStringData("SimGear::BARE_LOD_RANGE", fgGetString("/sim/rendering/static-lod/bare", boost::lexical_cast(SG_OBJECT_RANGE_BARE))); - options->setPluginStringData("SimGear::ROUGH_LOD_RANGE", fgGetString("/sim/rendering/static-lod/rough", boost::lexical_cast(SG_OBJECT_RANGE_ROUGH))); + options->setPluginStringData("SimGear::BARE_LOD_RANGE", fgGetString("/sim/rendering/static-lod/bare-delta", boost::lexical_cast(SG_OBJECT_RANGE_BARE))); + options->setPluginStringData("SimGear::ROUGH_LOD_RANGE", fgGetString("/sim/rendering/static-lod/rough-delta", boost::lexical_cast(SG_OBJECT_RANGE_ROUGH))); options->setPluginStringData("SimGear::ROUGH_LOD_DETAILED", fgGetString("/sim/rendering/static-lod/detailed", boost::lexical_cast(SG_OBJECT_RANGE_DETAILED))); options->setPluginStringData("SimGear::RENDER_BUILDING_MESH", fgGetBool("/sim/rendering/building-mesh", false) ? "true" : "false"); diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index cb23a0212..9eb762044 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -116,7 +116,9 @@ FGTileMgr::FGTileMgr(): _terra_sync(NULL), _listener(NULL), _visibilityMeters(fgGetNode("/environment/visibility-m", true)), - _maxTileRangeM(fgGetNode("/sim/rendering/static-lod/bare", true)), + _lodDetailed(fgGetNode("/sim/rendering/static-lod/detailed", true)), + _lodRoughDelta(fgGetNode("/sim/rendering/static-lod/rough-delta", true)), + _lodBareDelta(fgGetNode("/sim/rendering/static-lod/bare-delta", true)), _disableNasalHooks(fgGetNode("/sim/temp/disable-scenery-nasal", true)), _scenery_loaded(fgGetNode("/sim/sceneryloaded", true)), _scenery_override(fgGetNode("/sim/sceneryloaded-override", true)), @@ -295,8 +297,11 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis) // cout << "tile width = " << tile_width << " tile_height = " // << tile_height << endl; + // starting with 2018.3 we will use deltas rather than absolutes as it is more intuitive for the user + // and somewhat easier to visualise + double maxTileRange = _lodDetailed->getDoubleValue() + _lodRoughDelta->getDoubleValue() + _lodBareDelta->getDoubleValue(); - double tileRangeM = std::min(vis,_maxTileRangeM->getDoubleValue()); + double tileRangeM = std::min(vis, maxTileRange); int xrange = (int)(tileRangeM / tile_width) + 1; int yrange = (int)(tileRangeM / tile_height) + 1; if ( xrange < 1 ) { xrange = 1; } diff --git a/src/Scenery/tilemgr.hxx b/src/Scenery/tilemgr.hxx index 299930562..40a83517c 100644 --- a/src/Scenery/tilemgr.hxx +++ b/src/Scenery/tilemgr.hxx @@ -86,7 +86,7 @@ private: void schedule_tiles_at(const SGGeod& location, double rangeM); SGPropertyNode_ptr _visibilityMeters; - SGPropertyNode_ptr _maxTileRangeM, _disableNasalHooks; + SGPropertyNode_ptr _lodDetailed, _lodRoughDelta, _lodBareDelta, _disableNasalHooks; SGPropertyNode_ptr _scenery_loaded, _scenery_override; osg::ref_ptr _pager;