]> git.mxchange.org Git - simgear.git/commitdiff
Updates to random forest:
authorStuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Fri, 29 Jul 2011 14:22:24 +0000 (15:22 +0100)
committerStuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Fri, 29 Jul 2011 14:22:24 +0000 (15:22 +0100)
- Bug fix - use multiple textures per tile
- Graduate LoD so tree cover fades in/out.

simgear/scene/tgdb/TreeBin.cxx
simgear/scene/tgdb/TreeBin.hxx
simgear/scene/tgdb/obj.cxx

index 66c26addba0ea60ca68522cc6fd80dcccb095f1b..56c5d41588d3616dfc288a2d8b8dcd079a15c3d0 100644 (file)
@@ -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;
 }
 
index bb542c230edbd80860cc4f9cbca13bd2f84fba0e..a9c421987f1012eb5bc7078e81b05985a9565ffe 100644 (file)
@@ -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
index 4481b8308e706357c657cf5107905dd5dfd8a987..36011d723e489a60cc894c9d46dd0abbf0f364c5 100644 (file)
@@ -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);