Updates to random forest:
- Bug fix - use multiple textures per tile - Graduate LoD so tree cover fades in/out.
This commit is contained in:
parent
b47d1ad5fd
commit
38ac7b41ad
@ -54,6 +54,7 @@
|
||||
#include "TreeBin.hxx"
|
||||
|
||||
#define SG_TREE_QUAD_TREE_DEPTH 3
|
||||
#define SG_TREE_FADE_OUT_LEVELS 10
|
||||
|
||||
using namespace osg;
|
||||
|
||||
@ -230,9 +231,15 @@ struct MakeTreesLeaf
|
||||
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;
|
||||
@ -246,7 +253,7 @@ struct AddTreesLeafObject
|
||||
{
|
||||
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);
|
||||
}
|
||||
};
|
||||
@ -278,48 +285,55 @@ struct TreeTransformer
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
float height;
|
||||
float width;
|
||||
std::string texture;
|
||||
|
||||
|
||||
void insert(const Tree& t)
|
||||
{ _trees.push_back(t); }
|
||||
void insert(const SGVec3f& p, int t, float s)
|
||||
@ -62,6 +62,9 @@ public:
|
||||
TreeList _trees;
|
||||
};
|
||||
|
||||
osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform);
|
||||
|
||||
typedef std::list<TreeBin*> SGTreeBinList;
|
||||
|
||||
osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform);
|
||||
}
|
||||
#endif
|
||||
|
@ -40,6 +40,8 @@
|
||||
#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>
|
||||
@ -74,7 +76,7 @@ struct SGTileGeometryBin {
|
||||
SGMaterialTriangleMap materialTriangleMap;
|
||||
SGLightBin tileLights;
|
||||
SGLightBin randomTileLights;
|
||||
TreeBin randomForest;
|
||||
SGTreeBinList randomForest;
|
||||
SGDirectionalLightBin runwayLights;
|
||||
SGDirectionalLightBin taxiLights;
|
||||
SGDirectionalLightListBin vasiLights;
|
||||
@ -459,13 +461,33 @@ struct SGTileGeometryBin {
|
||||
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,
|
||||
@ -473,9 +495,9 @@ struct SGTileGeometryBin {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -589,7 +611,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
|
||||
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);
|
||||
@ -639,11 +661,10 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -770,14 +791,14 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user