Add generation of plantation vegetation to TileDetailsCallback.

Plantations are regularly spaced vegetation. This effect is switched
on by the is_plantation material property. Vegetation is laid out
at integer spacings in x and y, with the spacing determined by the
usual coverage properties.
This commit is contained in:
James.Hester
2019-11-16 11:16:09 +11:00
parent 56933067c0
commit 0f9fe8adef
3 changed files with 197 additions and 87 deletions
+85 -31
View File
@@ -291,6 +291,7 @@ public:
float vegetation_density, float vegetation_density,
float cos_max_density_angle, float cos_max_density_angle,
float cos_zero_density_angle, float cos_zero_density_angle,
bool is_plantation,
std::vector<SGVec3f>& points, std::vector<SGVec3f>& points,
std::vector<SGVec3f>& normals) std::vector<SGVec3f>& normals)
{ {
@@ -334,44 +335,97 @@ public:
if (area <= SGLimitsf::min()) if (area <= SGLimitsf::min())
continue; continue;
// Determine the number of trees, taking into account vegetation if (!is_plantation) {
// density (which is linear) and the slope density factor. // Determine the number of trees, taking into account vegetation
// Use a zombie door method to create the proper random chance // density (which is linear) and the slope density factor.
// of a tree being created for partial values. // Use a zombie door method to create the proper random chance
int woodcount = (int) (vegetation_density * vegetation_density * // of a tree being created for partial values.
slope_density * int woodcount = (int) (vegetation_density * vegetation_density *
area / wood_coverage + mt_rand(&seed)); slope_density *
area / wood_coverage + mt_rand(&seed));
for (int j = 0; j < woodcount; j++) {
// Use barycentric coordinates
float a = mt_rand(&seed);
float b = mt_rand(&seed);
for (int j = 0; j < woodcount; j++) { if ( a + b > 1.0f ) {
float a = mt_rand(&seed); a = 1.0f - a;
float b = mt_rand(&seed); b = 1.0f - b;
}
if ( a + b > 1.0f ) { float c = 1.0f - a - b;
a = 1.0f - a;
b = 1.0f - b;
}
float c = 1.0f - a - b; SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
if (object_mask != NULL) {
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
SGVec3f randomPoint = a*v0 + b*v1 + c*v2; // Check this random point against the object mask
// green (for trees) channel.
osg::Image* img = object_mask->getImage();
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
if (object_mask != NULL) { if (mt_rand(&seed) < img->getColor(x, y).g()) {
SGVec2f texCoord = a*t0 + b*t1 + c*t2; // The red channel contains the rotation for this object
points.push_back(randomPoint);
normals.push_back(normalize(normal));
}
} else {
points.push_back(randomPoint);
normals.push_back(normalize(normal));
// Check this random point against the object mask }
// green (for trees) channel. }
osg::Image* img = object_mask->getImage(); } else { // regularly-spaced vegetation
unsigned int x = (int) (img->s() * texCoord.x()) % img->s(); // separate vegetation in integral 1m units
unsigned int y = (int) (img->t() * texCoord.y()) % img->t(); int separation = (int) ceil(sqrt(wood_coverage));
float max_x = ceil(max(max(v1.x(),v2.x()),v0.x()));
if (mt_rand(&seed) < img->getColor(x, y).g()) { float min_x = floor(min(min(v1.x(),v2.x()),v0.x()));
// The red channel contains the rotation for this object float max_y = ceil(max(max(v1.y(),v2.y()),v0.y()));
points.push_back(randomPoint); float min_y = floor(min(min(v1.y(),v2.y()),v0.y()));
normals.push_back(normalize(normal));
/* equation of the plane ax+by+cz+d=0, need d */
float d = -1*(normal.x()*v0.x() + normal.y()*v0.y()+normal.z()*v0.z());
/* Now loop over a grid, skipping points not in the triangle */
int x_steps = (int) (max_x - min_x)/separation;
int y_steps = (int) (max_y - min_y)/separation;
SGVec2f v02d = SGVec2f(v0.x(),v0.y());
SGVec2f v12d = SGVec2f(v1.x(),v1.y());
SGVec2f v22d = SGVec2f(v2.x(),v2.y());
for (int jx = 0; jx < x_steps; jx++) {
float ptx = min_x + jx * separation;
for (int jy = 0; jy < y_steps; jy++) {
float pty = min_y + jy * separation;
SGVec2f newpt = SGVec2f(ptx,pty);
if (!point_in_triangle(newpt,v02d,v12d,v22d))
continue;
// z = (-ax-by-d)/c; c is not zero as
// that would be alpha of 1.0
float ptz = (-normal.x()*ptx - normal.y()*pty-d)/normal.z();
SGVec3f randomPoint = SGVec3f(ptx,pty,ptz);
if (object_mask != NULL) {
// Check this point against the object mask
// green (for trees) channel.
osg::Image* img = object_mask->getImage();
unsigned int x = (int) (img->s() * newpt.x()) % img->s();
unsigned int y = (int) (img->t() * newpt.y()) % img->t();
if (mt_rand(&seed) < img->getColor(x, y).g()) {
// The red channel contains the rotation for this object
points.push_back(randomPoint);
normals.push_back(normalize(normal));
}
} else {
points.push_back(randomPoint);
normals.push_back(normalize(normal));
}
} }
} else {
points.push_back(randomPoint);
normals.push_back(normalize(normal));
} }
} }
} }
+84 -29
View File
@@ -216,6 +216,7 @@ public:
float vegetation_density, float vegetation_density,
float cos_max_density_angle, float cos_max_density_angle,
float cos_zero_density_angle, float cos_zero_density_angle,
bool is_plantation,
std::vector<SGVec3f>& points, std::vector<SGVec3f>& points,
std::vector<SGVec3f>& normals) std::vector<SGVec3f>& normals)
{ {
@@ -249,45 +250,99 @@ public:
float area = 0.5f*length(normal); float area = 0.5f*length(normal);
if (area <= SGLimitsf::min()) if (area <= SGLimitsf::min())
continue; continue;
if (!is_plantation) {
// 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));
// Determine the number of trees, taking into account vegetation for (int j = 0; j < woodcount; j++) {
// density (which is linear) and the slope density factor. float a = mt_rand(&seed);
// Use a zombie door method to create the proper random chance float b = mt_rand(&seed);
// 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++) { if ( a + b > 1.0f ) {
float a = mt_rand(&seed); a = 1.0f - a;
float b = mt_rand(&seed); b = 1.0f - b;
}
if ( a + b > 1.0f ) { float c = 1.0f - a - b;
a = 1.0f - a;
b = 1.0f - b; SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
if (object_mask != NULL) {
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
// Check this random point against the object mask
// green (for trees) channel.
osg::Image* img = object_mask->getImage();
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
if (mt_rand(&seed) < img->getColor(x, y).g()) {
// The red channel contains the rotation for this object
points.push_back(randomPoint);
normals.push_back(normalize(normal));
}
} else {
points.push_back(randomPoint);
normals.push_back(normalize(normal));
}
} }
} else { // regularly-spaced vegetation
int separation = (int) ceil(sqrt(wood_coverage));
float max_x = ceil(max(max(v1.x(),v2.x()),v0.x()));
float min_x = floor(min(min(v1.x(),v2.x()),v0.x()));
float max_y = ceil(max(max(v1.y(),v2.y()),v0.y()));
float min_y = floor(min(min(v1.y(),v2.y()),v0.y()));
float c = 1.0f - a - b; // equation of the plane ax+by+cz+d=0, need d
SGVec3f randomPoint = a*v0 + b*v1 + c*v2; float d = -1*(normal.x()*v0.x() + normal.y()*v0.y()+normal.z()*v0.z());
if (object_mask != NULL) { // Now loop over a grid, skipping points not in the triangle
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
// Check this random point against the object mask int x_steps = (int) (max_x - min_x)/separation;
// green (for trees) channel. int y_steps = (int) (max_y - min_y)/separation;
osg::Image* img = object_mask->getImage(); SGVec2f v02d = SGVec2f(v0.x(),v0.y());
unsigned int x = (int) (img->s() * texCoord.x()) % img->s(); SGVec2f v12d = SGVec2f(v1.x(),v1.y());
unsigned int y = (int) (img->t() * texCoord.y()) % img->t(); SGVec2f v22d = SGVec2f(v2.x(),v2.y());
if (mt_rand(&seed) < img->getColor(x, y).g()) { for (int jx = 0; jx < x_steps; jx++) {
// The red channel contains the rotation for this object float ptx = min_x + jx * separation;
points.push_back(randomPoint);
normals.push_back(normalize(normal)); for (int jy = 0; jy < y_steps; jy++) {
float pty = min_y + jy * separation;
SGVec2f newpt = SGVec2f(ptx,pty);
if (!point_in_triangle(newpt,v02d,v12d,v22d))
continue;
// z = (-ax-by-d)/c; c is not zero as
// that would be alpha of 1.0
float ptz = (-normal.x()*ptx - normal.y()*pty-d)/normal.z();
SGVec3f randomPoint = SGVec3f(ptx,pty,ptz);
if (object_mask != NULL) {
// Check this point against the object mask
// green (for trees) channel.
osg::Image* img = object_mask->getImage();
unsigned int x = (int) (img->s() * newpt.x()) % img->s();
unsigned int y = (int) (img->t() * newpt.y()) % img->t();
if (mt_rand(&seed) < img->getColor(x, y).g()) {
// The red channel contains the rotation for this object
points.push_back(randomPoint);
normals.push_back(normalize(normal));
}
} else {
points.push_back(randomPoint);
normals.push_back(normalize(normal));
}
} }
} else {
points.push_back(randomPoint);
normals.push_back(normalize(normal));
} }
} }
} }
@@ -753,6 +753,7 @@ public:
vegetation_density, vegetation_density,
mat->get_cos_tree_max_density_slope_angle(), mat->get_cos_tree_max_density_slope_angle(),
mat->get_cos_tree_zero_density_slope_angle(), mat->get_cos_tree_zero_density_slope_angle(),
mat->get_is_plantation(),
randomPoints, randomPoints,
randomPointNormals); randomPointNormals);