Now based on /sim/rendering/static-lod/rough.
/** for backwards compatibility */
#define SG_SCENERY_FILE_FORMAT "0.4"
+/** Default range in m at which all objects are displayed. Overridden by /sim/rendering/static-lod/rough **/
+#define SG_OBJECT_RANGE 9000.0
+
+/** Radius of scenery tiles in m **/
+#define SG_TILE_RADIUS 14000.0
#endif // _SG_CONSTANTS_H
const SGPropertyNode *props,
SGPropertyNode *prop_root)
{
+ float default_object_range = prop_root->getFloatValue("/sim/rendering/static-lod/rough", SG_OBJECT_RANGE);
std::vector<bool> dds;
std::vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
for (unsigned int i = 0; i < textures.size(); i++)
building_large_min_depth = props->getFloatValue("building-large-min-depth-m", 50.0);
building_large_max_depth = props->getFloatValue("building-large-max-depth-m", 75.0);
- building_range = props->getDoubleValue("building-range-m", 10000.0);
+ building_range = props->getDoubleValue("building-range-m", default_object_range);
cos_object_max_density_slope_angle = cos(props->getFloatValue("object-max-density-angle-deg", 20.0) * osg::PI/180.0);
cos_object_zero_density_slope_angle = cos(props->getFloatValue("object-zero-density-angle-deg", 30.0) * osg::PI/180.0);
tree_effect = props->getStringValue("tree-effect", "Effects/tree");
tree_height = props->getDoubleValue("tree-height-m", 0.0);
tree_width = props->getDoubleValue("tree-width-m", 0.0);
- tree_range = props->getDoubleValue("tree-range-m", 0.0);
+ tree_range = props->getDoubleValue("tree-range-m", default_object_range);
tree_varieties = props->getIntValue("tree-varieties", 1);
cos_tree_max_density_slope_angle = cos(props->getFloatValue("tree-max-density-angle-deg", 30.0) * osg::PI/180.0);
cos_tree_zero_density_slope_angle = cos(props->getFloatValue("tree-zero-density-angle-deg", 45.0) * osg::PI/180.0);
std::vector<SGPropertyNode_ptr> object_group_nodes =
((SGPropertyNode *)props)->getChildren("object-group");
for (unsigned int i = 0; i < object_group_nodes.size(); i++)
- object_groups.push_back(new SGMatModelGroup(object_group_nodes[i]));
+ object_groups.push_back(new SGMatModelGroup(object_group_nodes[i], default_object_range));
// read glyph table for taxi-/runway-signs
std::vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph");
// Implementation of SGMatModelGroup.
////////////////////////////////////////////////////////////////////////
-SGMatModelGroup::SGMatModelGroup (SGPropertyNode * node)
- : _range_m(node->getDoubleValue("range-m", 2000))
+SGMatModelGroup::SGMatModelGroup (SGPropertyNode * node, float default_object_range)
+ : _range_m(node->getDoubleValue("range-m", default_object_range))
{
// Load the object subnodes
std::vector<SGPropertyNode_ptr> object_nodes =
friend class SGMaterial;
- SGMatModelGroup (SGPropertyNode * node);
+ SGMatModelGroup (SGPropertyNode * node, float default_object_range);
private:
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
+#include <simgear/math/sg_random.h>
#include <simgear/math/SGGeometry.hxx>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/logstream.hxx>
osg::ref_ptr<SGReaderWriterOptions> _options;
};
struct _ObjectStatic {
- _ObjectStatic() : _agl(false), _proxy(false), _lon(0), _lat(0), _elev(0), _hdg(0), _pitch(0), _roll(0) { }
+ _ObjectStatic() : _agl(false), _proxy(false), _lon(0), _lat(0), _elev(0), _hdg(0), _pitch(0), _roll(0), _range(SG_OBJECT_RANGE) { }
std::string _errorLocation;
std::string _token;
std::string _name;
bool _proxy;
double _lon, _lat, _elev;
double _hdg, _pitch, _roll;
+ double _range;
osg::ref_ptr<SGReaderWriterOptions> _options;
};
struct _Sign {
matrixTransform->setName("rotateStaticObject");
matrixTransform->setDataVariance(osg::Object::STATIC);
matrixTransform->addChild(node.get());
- leaf->addChild(matrixTransform, 0, 20000); //TODO: Make configurable?
+
+ leaf->addChild(matrixTransform, 0, o._range);
}
};
struct GetModelLODCoord {
return group.release();
}
+ mt _seed;
std::list<_ObjectStatic> _objectStaticList;
std::list<_Sign> _signList;
};
_ModelBin() :
+ _object_range(SG_OBJECT_RANGE),
_foundBase(false)
{ }
std::string filePath = osgDB::getFilePath(absoluteFileName);
+ // Bucket provides a consistent seed
+ // so we have consistent set of pseudo-random numbers for each STG file
+ mt seed;
+ int bucket = atoi(SGPath(absoluteFileName).file_base().c_str());
+ mt_init(&seed, bucket);
+
// do only load airport btg files.
bool onlyAirports = options->getPluginStringData("SimGear::FG_ONLY_AIRPORTS") == "ON";
// do only load terrain btg files
SGPath path = filePath;
path.append(name);
-
+
+ // Determine an appropriate range for the object, which has some randomness
+ double range = _object_range;
+ double lrand = mt_rand(&seed);
+ if (lrand < 0.1) range = range * 2.0;
+ else if (lrand < 0.4) range = range * 1.5;
+
if (token == "OBJECT_BASE") {
// Load only once (first found)
SG_LOG( SG_TERRAIN, SG_BULK, " " << token << " " << name );
obj._agl = (token == "OBJECT_STATIC_AGL");
obj._proxy = true;
in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll;
+ obj._range = range;
obj._options = opt;
_objectStaticList.push_back(obj);
}
obj._agl = (token == "OBJECT_SHARED_AGL");
obj._proxy = false;
in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll;
+ obj._range = range;
obj._options = opt;
_objectStaticList.push_back(obj);
}
osg::ref_ptr<SGReaderWriterOptions> options;
options = SGReaderWriterOptions::copyOrCreate(opt);
+ // Determine object ranges
+ _object_range = atof(options->getPluginStringData("SimGear::ROUGH_LOD_RANGE").c_str());
+
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
terrainGroup->setDataVariance(osg::Object::STATIC);
terrainGroup->setName("terrain");
pagedLOD->setDatabaseOptions(callbackOptions.get());
pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy name - use the stored data in the read file callback");
- pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 30000);
+
+ // Objects may end up displayed up to 2x the object range.
+ pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range + SG_TILE_RADIUS);
return pagedLOD;
}
}
+ double _object_range;
bool _foundBase;
std::list<_Object> _objectList;
std::list<_ObjectStatic> _objectStaticList;
LOD* result = new LOD;
if (_fade_out) {
- // Create a series of LOD nodes so buidling cover decreases
+ // Create a series of LOD nodes so building cover decreases
// gradually with distance from _range to 2*_range
for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
{
#define SG_SIMPLIFIER_RATIO (0.001)
#define SG_SIMPLIFIER_MAX_LENGTH (1000.0)
#define SG_SIMPLIFIER_MAX_ERROR (2000.0)
-#define SG_OBJECT_RANGE (9000.0)
-#define SG_TILE_RADIUS (14000.0)
#define SG_TILE_MIN_EXPIRY (180.0)
-
using namespace simgear;
// QuadTreeBuilder is used by Random Objects Generator
bool use_random_buildings = false;
float vegetation_density = 1.0f;
float building_density = 1.0f;
+ float object_range = SG_OBJECT_RANGE;
bool useVBOs = false;
osg::ref_ptr<osg::Group> randomObjects;
building_density
= propertyNode->getFloatValue("/sim/rendering/building-density",
building_density);
+ object_range
+ = propertyNode->getFloatValue("/sim/rendering/static-lod/rough",
+ object_range);
}
useVBOs = (_options->getPluginStringData("SimGear::USE_VBOS") == "ON");
if (randomObjects.valid() || forestNode.valid() || buildingNode.valid()) {
objectLOD = new osg::LOD;
- if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
- if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
- if (buildingNode.valid()) objectLOD->addChild(buildingNode.get(), 0, 20000);
+ // random objects, trees and buildings can be displayed up to 2xrange out.
+ if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 2.0 * object_range + SG_TILE_RADIUS);
+ if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 2.0 * object_range + SG_TILE_RADIUS);
+ if (buildingNode.valid()) objectLOD->addChild(buildingNode.get(), 0, 2.0 * object_range + SG_TILE_RADIUS);
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
objectLOD->setNodeMask(nodeMask);
} else if (simplifyDistant) {
// Simplified terrain is only used in the distance, the
// call-back below will re-generate the closer version
- pagedLOD->addChild(node, object_range + SG_TILE_RADIUS, FLT_MAX);
+ pagedLOD->addChild(node, 2*object_range + SG_TILE_RADIUS, FLT_MAX);
}
osg::ref_ptr<SGReaderWriterOptions> opt;
// Ensure that the random objects aren't expired too quickly
pagedLOD->setMinimumExpiryTime(pagedLOD->getNumChildren(), tile_min_expiry);
pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy filename for random objects callback");
- pagedLOD->setRange(pagedLOD->getNumChildren(), 0, object_range + SG_TILE_RADIUS);
+
+ // LOD Range is 2x the object range plus the tile radius because we display some objects up to 2x the
+ // range to reduce popping.
+ pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2 *object_range + SG_TILE_RADIUS);
transform->addChild(pagedLOD);
}