From ea4ed7cdd13ce6170048d4420620e3b244f2b898 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Fri, 5 Oct 2012 21:59:13 +0100 Subject: [PATCH] Reduce tree and object cover on steep slopes, configurable through materials.xml --- simgear/scene/material/mat.cxx | 5 +++ simgear/scene/material/mat.hxx | 34 ++++++++++++++- simgear/scene/tgdb/SGTexturedTriangleBin.hxx | 36 +++++++++++----- simgear/scene/tgdb/obj.cxx | 45 +++++++++++++++----- 4 files changed, 97 insertions(+), 23 deletions(-) diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 84b25659..63ee9f8c 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -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"); diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index 1f175790..1959cfff 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -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: @@ -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; diff --git a/simgear/scene/tgdb/SGTexturedTriangleBin.hxx b/simgear/scene/tgdb/SGTexturedTriangleBin.hxx index f87fc180..edb9cb20 100644 --- a/simgear/scene/tgdb/SGTexturedTriangleBin.hxx +++ b/simgear/scene/tgdb/SGTexturedTriangleBin.hxx @@ -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& 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); diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 418ba2c3..e09ee3ff 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -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::iterator k; -- 2.39.5