Updates to random forest:
- Bug fix - use multiple textures per tile - Graduate LoD so tree cover fades in/out.
This commit is contained in:
@@ -54,6 +54,7 @@
|
|||||||
#include "TreeBin.hxx"
|
#include "TreeBin.hxx"
|
||||||
|
|
||||||
#define SG_TREE_QUAD_TREE_DEPTH 3
|
#define SG_TREE_QUAD_TREE_DEPTH 3
|
||||||
|
#define SG_TREE_FADE_OUT_LEVELS 10
|
||||||
|
|
||||||
using namespace osg;
|
using namespace osg;
|
||||||
|
|
||||||
@@ -230,9 +231,15 @@ struct MakeTreesLeaf
|
|||||||
LOD* operator() () const
|
LOD* operator() () const
|
||||||
{
|
{
|
||||||
LOD* result = new LOD;
|
LOD* result = new LOD;
|
||||||
EffectGeode* geode = createTreeGeode(_width, _height, _varieties);
|
|
||||||
geode->setEffect(_effect.get());
|
// Create a series of LOD nodes so trees cover decreases slightly
|
||||||
result->addChild(geode, 0, _range);
|
// 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;
|
return result;
|
||||||
}
|
}
|
||||||
float _range;
|
float _range;
|
||||||
@@ -246,7 +253,7 @@ struct AddTreesLeafObject
|
|||||||
{
|
{
|
||||||
void operator() (LOD* lod, const TreeBin::Tree& tree) const
|
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);
|
addTreeToLeafGeode(geode, tree.position);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -278,48 +285,55 @@ struct TreeTransformer
|
|||||||
// forest into the local Z-up coordinate system we can reuse the
|
// forest into the local Z-up coordinate system we can reuse the
|
||||||
// primitive tree geometry for all the forests of the same type.
|
// 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);
|
Matrix transInv = Matrix::inverse(transform);
|
||||||
static Matrix ident;
|
static Matrix ident;
|
||||||
// Set up some shared structures.
|
// Set up some shared structures.
|
||||||
ref_ptr<Group> group;
|
ref_ptr<Group> group;
|
||||||
|
MatrixTransform* mt = new MatrixTransform(transform);
|
||||||
|
|
||||||
Effect* effect = 0;
|
SGTreeBinList::iterator i;
|
||||||
EffectMap::iterator iter = treeEffectMap.find(forest.texture);
|
|
||||||
if (iter == treeEffectMap.end()) {
|
for (i = forestList.begin(); i != forestList.end(); ++i) {
|
||||||
SGPropertyNode_ptr effectProp = new SGPropertyNode;
|
TreeBin* forest = *i;
|
||||||
makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
|
|
||||||
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
Effect* effect = 0;
|
||||||
// emphasize n = 0
|
EffectMap::iterator iter = treeEffectMap.find(forest->texture);
|
||||||
params->getChild("texture", 0, true)->getChild("image", 0, true)
|
if (iter == treeEffectMap.end()) {
|
||||||
->setStringValue(forest.texture);
|
SGPropertyNode_ptr effectProp = new SGPropertyNode;
|
||||||
effect = makeEffect(effectProp, true);
|
makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
|
||||||
treeEffectMap.insert(EffectMap::value_type(forest.texture, effect));
|
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
||||||
} else {
|
// emphasize n = 0
|
||||||
effect = iter->second.get();
|
params->getChild("texture", 0, true)->getChild("image", 0, true)
|
||||||
}
|
->setStringValue(forest->texture);
|
||||||
// Now, create a quadtree for the forest.
|
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
|
ShaderGeometryQuadtree
|
||||||
quadtree(GetTreeCoord(), AddTreesLeafObject(),
|
quadtree(GetTreeCoord(), AddTreesLeafObject(),
|
||||||
SG_TREE_QUAD_TREE_DEPTH,
|
SG_TREE_QUAD_TREE_DEPTH,
|
||||||
MakeTreesLeaf(forest.range, forest.texture_varieties,
|
MakeTreesLeaf(forest->range, forest->texture_varieties,
|
||||||
forest.width, forest.height, effect));
|
forest->width, forest->height, effect));
|
||||||
// Transform tree positions from the "geocentric" positions we
|
// Transform tree positions from the "geocentric" positions we
|
||||||
// get from the scenery polys into the local Z-up coordinate
|
// get from the scenery polys into the local Z-up coordinate
|
||||||
// system.
|
// system.
|
||||||
std::vector<TreeBin::Tree> rotatedTrees;
|
std::vector<TreeBin::Tree> rotatedTrees;
|
||||||
rotatedTrees.reserve(forest._trees.size());
|
rotatedTrees.reserve(forest->_trees.size());
|
||||||
std::transform(forest._trees.begin(), forest._trees.end(),
|
std::transform(forest->_trees.begin(), forest->_trees.end(),
|
||||||
std::back_inserter(rotatedTrees),
|
std::back_inserter(rotatedTrees),
|
||||||
TreeTransformer(transInv));
|
TreeTransformer(transInv));
|
||||||
quadtree.buildQuadTree(rotatedTrees.begin(), rotatedTrees.end());
|
quadtree.buildQuadTree(rotatedTrees.begin(), rotatedTrees.end());
|
||||||
group = quadtree.getRoot();
|
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;
|
return mt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ public:
|
|||||||
TreeList _trees;
|
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
|
#endif
|
||||||
|
|||||||
+38
-17
@@ -40,6 +40,8 @@
|
|||||||
#include <osg/StateSet>
|
#include <osg/StateSet>
|
||||||
#include <osg/Switch>
|
#include <osg/Switch>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/io/sg_binobj.hxx>
|
#include <simgear/io/sg_binobj.hxx>
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
@@ -74,7 +76,7 @@ struct SGTileGeometryBin {
|
|||||||
SGMaterialTriangleMap materialTriangleMap;
|
SGMaterialTriangleMap materialTriangleMap;
|
||||||
SGLightBin tileLights;
|
SGLightBin tileLights;
|
||||||
SGLightBin randomTileLights;
|
SGLightBin randomTileLights;
|
||||||
TreeBin randomForest;
|
SGTreeBinList randomForest;
|
||||||
SGDirectionalLightBin runwayLights;
|
SGDirectionalLightBin runwayLights;
|
||||||
SGDirectionalLightBin taxiLights;
|
SGDirectionalLightBin taxiLights;
|
||||||
SGDirectionalLightListBin vasiLights;
|
SGDirectionalLightListBin vasiLights;
|
||||||
@@ -460,12 +462,32 @@ struct SGTileGeometryBin {
|
|||||||
if (wood_coverage <= 0)
|
if (wood_coverage <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Attributes that don't vary by tree
|
// Attributes that don't vary by tree but do vary by material
|
||||||
randomForest.texture = mat->get_tree_texture();
|
bool found = false;
|
||||||
randomForest.range = mat->get_tree_range();
|
TreeBin* bin = NULL;
|
||||||
randomForest.width = mat->get_tree_width();
|
|
||||||
randomForest.height = mat->get_tree_height();
|
BOOST_FOREACH(bin, randomForest)
|
||||||
randomForest.texture_varieties = mat->get_tree_varieties();
|
{
|
||||||
|
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;
|
std::vector<SGVec3f> randomPoints;
|
||||||
i->second.addRandomTreePoints(wood_coverage,
|
i->second.addRandomTreePoints(wood_coverage,
|
||||||
@@ -473,9 +495,9 @@ struct SGTileGeometryBin {
|
|||||||
mat->get_wood_size(),
|
mat->get_wood_size(),
|
||||||
randomPoints);
|
randomPoints);
|
||||||
|
|
||||||
std::vector<SGVec3f>::iterator j;
|
std::vector<SGVec3f>::iterator k;
|
||||||
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
|
for (k = randomPoints.begin(); k != randomPoints.end(); ++k) {
|
||||||
randomForest.insert(*j);
|
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> lightGroup = new SGOffsetTransform(0.94);
|
||||||
osg::ref_ptr<osg::Group> randomObjects;
|
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::Group* terrainGroup = new osg::Group;
|
||||||
|
|
||||||
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
|
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
|
||||||
@@ -640,10 +662,9 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
|||||||
// Now add some random forest.
|
// Now add some random forest.
|
||||||
tileGeometryBin.computeRandomForest(matlib);
|
tileGeometryBin.computeRandomForest(matlib);
|
||||||
|
|
||||||
if (tileGeometryBin.randomForest.getNumTrees() > 0) {
|
if (tileGeometryBin.randomForest.size() > 0) {
|
||||||
randomForest = createForest(tileGeometryBin.randomForest,
|
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity());
|
||||||
osg::Matrix::identity());
|
forestNode->setName("Random trees");
|
||||||
randomForest->setName("random trees");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,14 +791,14 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
|||||||
transform->addChild(lightLOD);
|
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
|
// Add a LoD node, so we don't try to display anything when the tile center
|
||||||
// is more than 20km away.
|
// is more than 20km away.
|
||||||
osg::LOD* objectLOD = new osg::LOD;
|
osg::LOD* objectLOD = new osg::LOD;
|
||||||
|
|
||||||
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
|
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;
|
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
|
||||||
objectLOD->setNodeMask(nodeMask);
|
objectLOD->setNodeMask(nodeMask);
|
||||||
|
|||||||
Reference in New Issue
Block a user