#include "TreeBin.hxx"
#define SG_TREE_QUAD_TREE_DEPTH 3
+#define SG_TREE_FADE_OUT_LEVELS 10
using namespace osg;
LOD* operator() () const
{
LOD* result = new LOD;
- EffectGeode* geode = createTreeGeode(_width, _height, _varieties);
- geode->setEffect(_effect.get());
- result->addChild(geode, 0, _range);
+
+ // Create a series of LOD nodes so trees cover decreases slightly
+ // gradually with distance from _range to 2*_range
+ for (float i = 0.0; i < SG_TREE_FADE_OUT_LEVELS; i++)
+ {
+ EffectGeode* geode = createTreeGeode(_width, _height, _varieties);
+ geode->setEffect(_effect.get());
+ result->addChild(geode, 0, _range * (1.0 + i / (SG_TREE_FADE_OUT_LEVELS - 1.0)));
+ }
return result;
}
float _range;
{
void operator() (LOD* lod, const TreeBin::Tree& tree) const
{
- Geode* geode = static_cast<Geode*>(lod->getChild(0));
+ Geode* geode = static_cast<Geode*>(lod->getChild(rand() % SG_TREE_FADE_OUT_LEVELS));
addTreeToLeafGeode(geode, tree.position);
}
};
// forest into the local Z-up coordinate system we can reuse the
// primitive tree geometry for all the forests of the same type.
-osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
+osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform)
{
Matrix transInv = Matrix::inverse(transform);
static Matrix ident;
// Set up some shared structures.
ref_ptr<Group> group;
+ MatrixTransform* mt = new MatrixTransform(transform);
- Effect* effect = 0;
- EffectMap::iterator iter = treeEffectMap.find(forest.texture);
- if (iter == treeEffectMap.end()) {
- SGPropertyNode_ptr effectProp = new SGPropertyNode;
- makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
- SGPropertyNode* params = makeChild(effectProp, "parameters");
- // emphasize n = 0
- params->getChild("texture", 0, true)->getChild("image", 0, true)
- ->setStringValue(forest.texture);
- effect = makeEffect(effectProp, true);
- treeEffectMap.insert(EffectMap::value_type(forest.texture, effect));
- } else {
- effect = iter->second.get();
- }
- // Now, create a quadtree for the forest.
- {
+ SGTreeBinList::iterator i;
+
+ for (i = forestList.begin(); i != forestList.end(); ++i) {
+ TreeBin* forest = *i;
+
+ Effect* effect = 0;
+ EffectMap::iterator iter = treeEffectMap.find(forest->texture);
+ if (iter == treeEffectMap.end()) {
+ SGPropertyNode_ptr effectProp = new SGPropertyNode;
+ makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
+ SGPropertyNode* params = makeChild(effectProp, "parameters");
+ // emphasize n = 0
+ params->getChild("texture", 0, true)->getChild("image", 0, true)
+ ->setStringValue(forest->texture);
+ effect = makeEffect(effectProp, true);
+ treeEffectMap.insert(EffectMap::value_type(forest->texture, effect));
+ } else {
+ effect = iter->second.get();
+ }
+
+ // Now, create a quadtree for the forest.
ShaderGeometryQuadtree
quadtree(GetTreeCoord(), AddTreesLeafObject(),
SG_TREE_QUAD_TREE_DEPTH,
- MakeTreesLeaf(forest.range, forest.texture_varieties,
- forest.width, forest.height, effect));
+ MakeTreesLeaf(forest->range, forest->texture_varieties,
+ forest->width, forest->height, effect));
// Transform tree positions from the "geocentric" positions we
// get from the scenery polys into the local Z-up coordinate
// system.
std::vector<TreeBin::Tree> rotatedTrees;
- rotatedTrees.reserve(forest._trees.size());
- std::transform(forest._trees.begin(), forest._trees.end(),
+ rotatedTrees.reserve(forest->_trees.size());
+ std::transform(forest->_trees.begin(), forest->_trees.end(),
std::back_inserter(rotatedTrees),
TreeTransformer(transInv));
quadtree.buildQuadTree(rotatedTrees.begin(), rotatedTrees.end());
group = quadtree.getRoot();
+
+ for (size_t i = 0; i < group->getNumChildren(); ++i)
+ mt->addChild(group->getChild(i));
}
- MatrixTransform* mt = new MatrixTransform(transform);
- for (size_t i = 0; i < group->getNumChildren(); ++i)
- mt->addChild(group->getChild(i));
+
return mt;
}
#include <osg/StateSet>
#include <osg/Switch>
+#include <boost/foreach.hpp>
+
#include <simgear/debug/logstream.hxx>
#include <simgear/io/sg_binobj.hxx>
#include <simgear/math/sg_geodesy.hxx>
SGMaterialTriangleMap materialTriangleMap;
SGLightBin tileLights;
SGLightBin randomTileLights;
- TreeBin randomForest;
+ SGTreeBinList randomForest;
SGDirectionalLightBin runwayLights;
SGDirectionalLightBin taxiLights;
SGDirectionalLightListBin vasiLights;
float wood_coverage = mat->get_wood_coverage();
if (wood_coverage <= 0)
continue;
-
- // Attributes that don't vary by tree
- randomForest.texture = mat->get_tree_texture();
- randomForest.range = mat->get_tree_range();
- randomForest.width = mat->get_tree_width();
- randomForest.height = mat->get_tree_height();
- randomForest.texture_varieties = mat->get_tree_varieties();
+
+ // Attributes that don't vary by tree but do vary by material
+ bool found = false;
+ TreeBin* bin = NULL;
+
+ BOOST_FOREACH(bin, randomForest)
+ {
+ if ((bin->texture == mat->get_tree_texture() ) &&
+ (bin->texture_varieties == mat->get_tree_varieties()) &&
+ (bin->range == mat->get_tree_range() ) &&
+ (bin->width == mat->get_tree_width() ) &&
+ (bin->height == mat->get_tree_height() ) ) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ bin = new TreeBin();
+ bin->texture = mat->get_tree_texture();
+ SG_LOG(SG_INPUT, SG_DEBUG, "Tree texture " << bin->texture);
+ bin->range = mat->get_tree_range();
+ bin->width = mat->get_tree_width();
+ bin->height = mat->get_tree_height();
+ bin->texture_varieties = mat->get_tree_varieties();
+ randomForest.push_back(bin);
+ }
std::vector<SGVec3f> randomPoints;
i->second.addRandomTreePoints(wood_coverage,
mat->get_wood_size(),
randomPoints);
- std::vector<SGVec3f>::iterator j;
- for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
- randomForest.insert(*j);
+ std::vector<SGVec3f>::iterator k;
+ for (k = randomPoints.begin(); k != randomPoints.end(); ++k) {
+ bin->insert(*k);
}
}
}
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
osg::ref_ptr<osg::Group> randomObjects;
- osg::ref_ptr<osg::Group> randomForest;
+ osg::ref_ptr<osg::Group> forestNode;
osg::Group* terrainGroup = new osg::Group;
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
if (use_random_vegetation && matlib) {
// Now add some random forest.
tileGeometryBin.computeRandomForest(matlib);
-
- if (tileGeometryBin.randomForest.getNumTrees() > 0) {
- randomForest = createForest(tileGeometryBin.randomForest,
- osg::Matrix::identity());
- randomForest->setName("random trees");
+
+ if (tileGeometryBin.randomForest.size() > 0) {
+ forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity());
+ forestNode->setName("Random trees");
}
}
}
transform->addChild(lightLOD);
}
- if (randomObjects.valid() || randomForest.valid()) {
+ if (randomObjects.valid() || forestNode.valid()) {
// Add a LoD node, so we don't try to display anything when the tile center
// is more than 20km away.
osg::LOD* objectLOD = new osg::LOD;
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
- if (randomForest.valid()) objectLOD->addChild(randomForest.get(), 0, 20000);
+ if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
objectLOD->setNodeMask(nodeMask);