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.
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<SGVec3f>& 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<SGVec3f>& points)
|
||||
|
||||
@@ -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<SGVec3f> randomPoints;
|
||||
i->second.addRandomSurfacePoints(coverage, 0, randomPoints);
|
||||
i->second.addRandomTreePoints(wood_coverage,
|
||||
mat->get_tree_density(),
|
||||
mat->get_wood_size(),
|
||||
randomPoints);
|
||||
|
||||
std::vector<SGVec3f>::iterator j;
|
||||
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user