]> git.mxchange.org Git - simgear.git/commitdiff
Reduce tree and object cover on steep slopes, configurable through materials.xml
authorStuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Fri, 5 Oct 2012 20:59:13 +0000 (21:59 +0100)
committerStuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Fri, 5 Oct 2012 20:59:13 +0000 (21:59 +0100)
simgear/scene/material/mat.cxx
simgear/scene/material/mat.hxx
simgear/scene/tgdb/SGTexturedTriangleBin.hxx
simgear/scene/tgdb/obj.cxx

index 84b25659e8e42909f6a8b69857084fcdf5aa83a5..63ee9f8c67ad144f689133b6f8a4590b8ab48b1f 100644 (file)
@@ -320,6 +320,9 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
     building_large_max_width = props->getFloatValue("building-large-max-width-m", 75.0);
     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);
+    
+    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);
         
     // Random vegetation properties
     wood_coverage = props->getDoubleValue("wood-coverage", 0.0);
@@ -327,6 +330,8 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
     tree_width = props->getDoubleValue("tree-width-m", 0.0);
     tree_range = props->getDoubleValue("tree-range-m", 0.0);
     tree_varieties = props->getIntValue("tree-varieties", 1);
+    cos_tree_max_density_slope_angle  = cos(props->getFloatValue("tree-max-density-angle-deg", 45.0) * osg::PI/180.0);
+    cos_tree_zero_density_slope_angle = cos(props->getFloatValue("tree-zero-density-angle-deg", 60.0) * osg::PI/180.0);
 
     const SGPropertyNode* treeTexNode = props->getChild("tree-texture");
     
index 1f17579052ed04dfdb64293814ea8ed7dd275c41..1959cfffe97b56b3b2bef294ff08d4aa946af7a2 100644 (file)
@@ -210,6 +210,9 @@ public:
   inline double get_building_large_max_width () const { return building_large_max_width; }
   inline double get_building_large_min_depth () const { return building_large_min_depth; }
   inline double get_building_large_max_depth () const { return building_large_max_depth; }
+  
+  inline double get_cos_object_max_density_slope_angle () const { return cos_object_max_density_slope_angle; }
+  inline double get_cos_object_zero_density_slope_angle () const { return cos_object_zero_density_slope_angle; }
 
   /**
    * Get the wood coverage.
@@ -255,6 +258,24 @@ public:
    */
   inline std::string get_tree_texture () const { return  tree_texture; }
   
+  /**
+   * Get the cosine of the maximum tree density slope angle. We
+   * use the cosine as it can be compared directly to the z component
+   * of a triangle normal.
+   * 
+   * @return the cosine of the maximum tree density slope angle.
+   */
+  inline double get_cos_tree_max_density_slope_angle () const { return cos_tree_max_density_slope_angle; }
+  
+  /**
+   * Get the cosine of the maximum tree density slope angle. We
+   * use the cosine as it can be compared directly to the z component
+   * of a triangle normal.
+   * 
+   * @return the cosine of the maximum tree density slope angle.
+   */
+  inline double get_cos_tree_zero_density_slope_angle () const { return cos_tree_zero_density_slope_angle; }
+  
   /**
    * Get the list of names for this material
    */
@@ -301,7 +322,7 @@ public:
     return SGVec2f((0 < tex_width) ? 1000.0f/tex_width : 1.0f,
                    (0 < tex_height) ? 1000.0f/tex_height : 1.0f);
   }
-
+  
 protected:
 
 \f
@@ -394,6 +415,12 @@ private:
   double building_large_min_depth;
   double building_large_max_depth;
   
+  // Cosine of the angle of maximum and zero density, 
+  // used to stop buildings and random objects from being 
+  // created on too steep a slope.
+  double cos_object_max_density_slope_angle;
+  double cos_object_zero_density_slope_angle;
+  
   // coverage of woods
   double wood_coverage;
 
@@ -408,6 +435,11 @@ private:
 
   // Number of varieties of tree texture
   int tree_varieties;
+  
+  // cosine of the tile angle of maximum and zero density,
+  // used to stop trees from being created on too steep a slope.
+  double cos_tree_max_density_slope_angle;
+  double cos_tree_zero_density_slope_angle;
 
   // material properties
   SGVec4f ambient, diffuse, specular, emission;
index f87fc180e87ce758e1b463aeae469048960ad497..edb9cb20e7b8fd251ed7558119994dfba43abc0c 100644 (file)
@@ -173,6 +173,8 @@ public:
   void addRandomTreePoints(float wood_coverage, 
                            osg::Texture2D* object_mask,
                            float vegetation_density,
+                           float cos_max_density_angle,
+                           float cos_zero_density_angle,
                            std::vector<SGVec3f>& points)
   {
     unsigned num = getNumTriangles();
@@ -186,21 +188,33 @@ public:
       SGVec2f t2 = getVertex(triangleRef[2]).texCoord;
       SGVec3f normal = cross(v1 - v0, v2 - v0);
       
+      // Ensure the slope isn't too steep by checking the
+      // cos of the angle between the slope normal and the
+      // vertical (conveniently the z-component of the normalized
+      // normal) and values passed in.                   
+      float alpha = normalize(normal).z();
+      float slope_density = 1.0;
+      
+      if (alpha < cos_zero_density_angle) 
+        continue; // Too steep for any vegetation      
+      
+      if (alpha < cos_max_density_angle) {
+        slope_density = 
+          (alpha - cos_zero_density_angle) / (cos_max_density_angle - cos_zero_density_angle);
+      }
+      
       // Compute the area
       float area = 0.5f*length(normal);
       if (area <= SGLimitsf::min())
         continue;
-
-      // For partial units of area, use a zombie door method to
-      // create the proper random chance of a point being created
-      // for this triangle
-      float unit = area + mt_rand(&seed)*wood_coverage;
-      
-      // Vegetation density is linear, while we're creating woodland
-      // by area.
-      int woodcount = (int) (vegetation_density * 
-                             vegetation_density * 
-                             unit / wood_coverage);
+        
+      // Determine the number of trees, taking into account vegetation
+      // density (which is linear) and the slope density factor.
+      // Use a zombie door method to create the proper random chance 
+      // of a tree being created for partial values.
+      int woodcount = (int) (vegetation_density * vegetation_density * 
+                             slope_density *
+                             area / wood_coverage + mt_rand(&seed));
       
       for (int j = 0; j < woodcount; j++) {
         float a = mt_rand(&seed);
index 418ba2c3c1bc53f92f986aeab21b9f909a8c4b69..e09ee3ff3896b3909e974ff2565feca9e5292af1 100644 (file)
@@ -476,10 +476,11 @@ struct SGTileGeometryBin {
       if (!mat)
         continue;
 
-      osg::Texture2D* object_mask = mat->get_object_mask(triangleBin);
-
-      int group_count = mat->get_object_group_count();
-      float building_coverage = mat->get_building_coverage();      
+      osg::Texture2D* object_mask  = mat->get_object_mask(triangleBin);
+      int   group_count            = mat->get_object_group_count();
+      float building_coverage      = mat->get_building_coverage();      
+      float cos_zero_density_angle = mat->get_cos_object_zero_density_slope_angle();
+      float cos_max_density_angle  = mat->get_cos_object_max_density_slope_angle();
       
       bool found = false;
       SGBuildingBin* bin = NULL;
@@ -516,6 +517,19 @@ struct SGTileGeometryBin {
         SGVec2f t1 = triangleBin.getVertex(triangleRef[2]).texCoord - torigin;
         SGVec3f normal = cross(v0, v1);
         
+        // Ensure the slope isn't too steep by checking the
+        // cos of the angle between the slope normal and the
+        // vertical (conveniently the z-component of the normalized
+        // normal) and values passed in.                   
+        float cos = normalize(normal).z();
+        float slope_density = 1.0;
+        if (cos < cos_zero_density_angle) continue; // Too steep for any objects
+        if (cos < cos_max_density_angle) {
+          slope_density = 
+            (cos - cos_zero_density_angle) / 
+            (cos_max_density_angle - cos_zero_density_angle);
+        }
+                
         // Containers to hold the random buildings and objects generated
         // for this triangle for collision detection purposes.
         std::vector< std::pair< SGVec3f, float> > triangleObjectsList;
@@ -541,8 +555,12 @@ struct SGTileGeometryBin {
             for (int k = 0; k < nObjects; k++) {
               SGMatModel * object = object_group->get_object(k);
               
+              // Determine the number of objecst to place, taking into account
+              // the slope density factor.
+              double n = slope_density * area / object->get_coverage_m2();
+              
               // Use the zombie door method to determine fractional object placement.
-              double n = area / object->get_coverage_m2() + mt_rand(&seed);
+              n = n + mt_rand(&seed);
 
               // place an object each unit of area
               while ( n > 1.0 ) {
@@ -619,17 +637,20 @@ struct SGTileGeometryBin {
         }        
         
         // Random objects now generated.  Now generate the random buildings (if any);
-        if (use_random_buildings && (building_coverage > 0)) {
+        if (use_random_buildings && (building_coverage > 0) && (building_density > 0)) {
+          
+          // Calculate the number of buildings, taking into account building density (which is linear)
+          // and the slope density factor.  
+          double num = building_density * building_density * slope_density * area / building_coverage;
+          
           // For partial units of area, use a zombie door method to
           // create the proper random chance of an object being created
           // for this triangle.
-          double num = area / building_coverage + mt_rand(&seed);
+          num = num + mt_rand(&seed);
+
           if (num < 1.0f) {
             continue;          
           }
-                  
-          // Apply density, which is linear, while we're dealing in areas
-          num = num * building_density * building_density;
           
           // Cosine of the angle between the two vectors.
           float cosine = (dot(v0, v1) / (length(v0) * length(v1)));
@@ -784,7 +805,7 @@ struct SGTileGeometryBin {
         continue;
 
       float wood_coverage = mat->get_wood_coverage();
-      if (wood_coverage <= 0)
+      if ((wood_coverage <= 0) || (vegetation_density <= 0))
         continue;
               
       // Attributes that don't vary by tree but do vary by material
@@ -818,6 +839,8 @@ struct SGTileGeometryBin {
       i->second.addRandomTreePoints(wood_coverage,
                                     mat->get_object_mask(i->second),
                                     vegetation_density,
+                                    mat->get_cos_tree_max_density_slope_angle(),
+                                    mat->get_cos_tree_zero_density_slope_angle(),
                                     randomPoints);
       
       std::vector<SGVec3f>::iterator k;