From: torsten Date: Sun, 9 Aug 2009 10:49:20 +0000 (+0000) Subject: Stuart Buchanan: I've been working on a small patch to allow trees to be grouped... X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=1f1e28baf8d287f930ba955f2aba6f8323157448;p=simgear.git Stuart Buchanan: I've been working on a small patch to allow trees to be grouped together into woods. This allows what seems to me to be a more realistic grouping of trees for farmland in particular. --- diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index dc79d094..2fc7e9c8 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -131,11 +131,14 @@ SGMaterial::read_properties(const osgDB::ReaderWriter::Options* options, wrapv = props->getBoolValue("wrapv", true); mipmap = props->getBoolValue("mipmap", true); light_coverage = props->getDoubleValue("light-coverage", 0.0); - tree_coverage = props->getDoubleValue("tree-coverage", 0.0); + wood_coverage = props->getDoubleValue("wood-coverage", 0.0); + wood_size = props->getDoubleValue("wood-size", 0.0); + tree_density = props->getDoubleValue("tree-density", 1.0); tree_height = props->getDoubleValue("tree-height-m", 0.0); 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); + const SGPropertyNode* treeTexNode = props->getChild("tree-texture"); if (treeTexNode) { string treeTexPath = props->getStringValue("tree-texture"); diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index c510575e..ac2e5f1b 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -131,23 +131,37 @@ public: inline double get_light_coverage () const { return light_coverage; } /** - * Get the forest coverage. + * Get the wood coverage. * - * A smaller number means more generated forest canopy. + * A smaller number means more generated woods within the forest. * - * @return The area (m^2) covered by each canopy. + * @return The area (m^2) covered by each wood. */ - inline double get_tree_coverage () const { return tree_coverage; } + inline double get_wood_coverage () const { return wood_coverage; } /** - * Get the forest height. + * Get the density of the wood + * + * @return The area (m^2) covered by each tree in the wood. + */ + inline double get_tree_density () const { return tree_density; } + + /** + * Get the size of each wood + * + * @return the average area (m^2) of each wood + */ + inline double get_wood_size () const { return wood_size; } + + /** + * Get the tree height. * * @return The average height of the trees. */ inline double get_tree_height () const { return tree_height; } /** - * Get the forest width. + * Get the tree width. * * @return The average width of the trees. */ @@ -289,9 +303,15 @@ private: // coverage of night lighting. double light_coverage; - // coverage of trees - double tree_coverage; - + // coverage of woods + double wood_coverage; + + // The size of each wood + double wood_size; + + // Tree density within the wood + double tree_density; + // Range at which trees become visible double tree_range; diff --git a/simgear/scene/tgdb/SGTexturedTriangleBin.hxx b/simgear/scene/tgdb/SGTexturedTriangleBin.hxx index bbeb6244..96e49776 100644 --- a/simgear/scene/tgdb/SGTexturedTriangleBin.hxx +++ b/simgear/scene/tgdb/SGTexturedTriangleBin.hxx @@ -128,9 +128,12 @@ public: SGVec3f offsetVector = offset*normalize(normal); // generate a light point for each unit of area + while ( coverage < unit ) { + float a = mt_rand(&seed); float b = mt_rand(&seed); + if ( a + b > 1 ) { a = 1 - a; b = 1 - b; @@ -142,6 +145,102 @@ public: } } } + + // Computes and adds random surface points to the points list for tree + // coverage. + void addRandomTreePoints(float wood_coverage, + float tree_density, + float wood_size, + std::vector& points) + { + unsigned num = getNumTriangles(); + for (unsigned i = 0; i < num; ++i) { + triangle_ref triangleRef = getTriangleRef(i); + SGVec3f v0 = getVertex(triangleRef[0]).vertex; + SGVec3f v1 = getVertex(triangleRef[1]).vertex; + SGVec3f v2 = getVertex(triangleRef[2]).vertex; + SGVec3f normal = cross(v1 - v0, v2 - v0); + + // 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; + + int woodcount = (int) (unit / wood_coverage); + + for (unsigned j = 0; j < woodcount; j++) { + + if (wood_size < area) { + // We need to place a wood within the triangle and populate it + + // Determine the center of the wood + float x = mt_rand(&seed); + float y = mt_rand(&seed); + + // Determine the size of this wood in m^2, and the number + // of trees in the wood + float ws = wood_size + wood_size * (mt_rand(&seed) - 0.5f); + unsigned total_trees = ws / tree_density; + float wood_length = sqrt(ws); + + // From our wood size, work out the fraction on the two axis. + // This will be used as a factor when placing trees in the wood. + float x_tree_factor = wood_length / length(v1 -v0); + float y_tree_factor = wood_length / length(v2 -v0); + + for (unsigned k = 0; k <= total_trees; k++) { + + float a = x + x_tree_factor * (mt_rand(&seed) - 0.5f); + float b = y + y_tree_factor * (mt_rand(&seed) - 0.5f); + + + // In some cases, the triangle side lengths are so small that the + // tree_factors become so large as to make placing the tree within + // the triangle almost impossible. In this case, we place them + // randomly across the triangle. + if (a < 0.0f || a > 1.0f) a = mt_rand(&seed); + if (b < 0.0f || b > 1.0f) b = mt_rand(&seed); + + if ( a + b > 1.0f ) { + a = 1.0f - a; + b = 1.0f - b; + } + + float c = 1.0f - a - b; + + SGVec3f randomPoint = a*v0 + b*v1 + c*v2; + + points.push_back(randomPoint); + } + } else { + // This triangle is too small to contain a complete wood, so just + // distribute trees across it. + unsigned total_trees = area / tree_density; + + for (unsigned k = 0; k <= total_trees; k++) { + + float a = mt_rand(&seed); + float b = mt_rand(&seed); + + if ( a + b > 1.0f ) { + a = 1.0f - a; + b = 1.0f - b; + } + + float c = 1.0f - a - b; + + SGVec3f randomPoint = a*v0 + b*v1 + c*v2; + points.push_back(randomPoint); + } + } + } + } + } void addRandomPoints(float coverage, std::vector& points) diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 3869c521..cdfd64f6 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -455,8 +455,8 @@ struct SGTileGeometryBin { if (!mat) continue; - float coverage = mat->get_tree_coverage(); - if (coverage <= 0) + float wood_coverage = mat->get_wood_coverage(); + if (wood_coverage <= 0) continue; // Attributes that don't vary by tree @@ -467,7 +467,11 @@ struct SGTileGeometryBin { randomForest.texture_varieties = mat->get_tree_varieties(); std::vector randomPoints; - i->second.addRandomSurfacePoints(coverage, 0, randomPoints); + i->second.addRandomTreePoints(wood_coverage, + mat->get_tree_density(), + mat->get_wood_size(), + randomPoints); + std::vector::iterator j; for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {