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");
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.
*/
// 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;
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;
}
}
}
+
+ // 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)
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
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) {