Random object and vegetation masking based on bitmap file.

Also adds a property controlling vegetation density.
This commit is contained in:
Stuart Buchanan
2012-02-05 23:05:57 +00:00
parent 9d20de068c
commit 593c884f14
11 changed files with 368 additions and 108 deletions

View File

@@ -30,7 +30,7 @@
#include <string.h>
#include <map>
#include <vector>
#include<string>
#include <string>
#include <boost/foreach.hpp>
#include "mat.hxx"
@@ -74,7 +74,7 @@ SGMaterial::_internal_state::_internal_state(Effect *e, bool l,
{
}
SGMaterial::_internal_state::_internal_state(Effect *e, const string &t, bool l,
SGMaterial::_internal_state::_internal_state(Effect *e, const string &t, bool l,
const SGReaderWriterOptions* o)
: effect(e), effect_realized(l), options(o)
{
@@ -118,14 +118,22 @@ void
SGMaterial::read_properties(const SGReaderWriterOptions* options,
const SGPropertyNode *props)
{
// Gather the path(s) to the texture(s)
std::vector<bool> dds;
std::vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
for (unsigned int i = 0; i < textures.size(); i++)
{
string tname = textures[i]->getStringValue();
if (tname.empty()) {
tname = "unknown.rgb";
}
if (tname.rfind(".dds") == (tname.length() - 4)) {
dds.push_back(true);
} else {
dds.push_back(false);
}
SGPath tpath("Textures.high");
tpath.append(tname);
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
@@ -134,7 +142,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
tpath.append(tname);
fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
}
if (!fullTexPath.empty() ) {
_internal_state st( NULL, fullTexPath, false, options );
_status.push_back( st );
@@ -152,6 +160,15 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
if (tname.empty()) {
tname = "unknown.rgb";
}
if (j == 0) {
if (tname.rfind(".dds") == (tname.length() - 4)) {
dds.push_back(true);
} else {
dds.push_back(false);
}
}
SGPath tpath("Textures.high");
tpath.append(tname);
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
@@ -160,6 +177,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
tpath.append(tname);
fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
}
st.add_texture(fullTexPath, textures[j]->getIndex());
}
@@ -175,6 +193,43 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
_internal_state st( NULL, tpath.str(), true, options );
_status.push_back( st );
}
std::vector<SGPropertyNode_ptr> masks = props->getChildren("object-mask");
for (unsigned int i = 0; i < masks.size(); i++)
{
string omname = masks[i]->getStringValue();
if (! omname.empty()) {
SGPath ompath("Textures.high");
ompath.append(omname);
string fullMaskPath = SGModelLib::findDataFile(ompath.str(), options);
if (fullMaskPath.empty()) {
ompath = SGPath("Textures");
ompath.append(omname);
fullMaskPath = SGModelLib::findDataFile(ompath.str(), options);
}
osg::Image* image = osgDB::readImageFile(fullMaskPath, options);
if (image->valid())
{
osg::Texture2D* object_mask = new osg::Texture2D;
if (dds[i]) {
// Texture is a DDS. This is relevant for the object mask, as DDS
// textures have an origin at the bottom left rather than top
// left, therefore we flip the object mask vertically.
image->flipVertical();
}
object_mask->setImage(image);
object_mask->setDataVariance(osg::Object::STATIC);
object_mask->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
object_mask->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
_masks.push_back(object_mask);
}
}
}
xsize = props->getDoubleValue("xsize", 0.0);
ysize = props->getDoubleValue("ysize", 0.0);
@@ -195,7 +250,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
string treeTexPath = props->getStringValue("tree-texture");
tree_texture = SGModelLib::findDataFile(treeTexPath, options);
}
// surface values for use with ground reactions
solid = props->getBoolValue("solid", true);
friction_factor = props->getDoubleValue("friction-factor", 1.0);
@@ -253,7 +308,6 @@ void
SGMaterial::init ()
{
_status.clear();
_current_ptr = 0;
xsize = 0;
ysize = 0;
wrapu = true;
@@ -278,22 +332,47 @@ SGMaterial::init ()
effect = "Effects/terrain-default";
}
Effect* SGMaterial::get_effect(int n)
Effect* SGMaterial::get_effect(int i)
{
if(!_status[i].effect_realized) {
_status[i].effect->realizeTechniques(_status[i].options.get());
_status[i].effect_realized = true;
}
return _status[i].effect.get();
}
Effect* SGMaterial::get_effect(SGTexturedTriangleBin triangleBin)
{
if (_status.size() == 0) {
SG_LOG( SG_GENERAL, SG_WARN, "No effect available.");
return 0;
}
int i = n >= 0 ? n : _current_ptr;
if(!_status[i].effect_realized) {
_status[i].effect->realizeTechniques(_status[i].options.get());
_status[i].effect_realized = true;
int i = triangleBin.getTextureIndex() % _status.size();
return get_effect(i);
}
Effect* SGMaterial::get_effect()
{
return get_effect(0);
}
osg::Texture2D* SGMaterial::get_object_mask(SGTexturedTriangleBin triangleBin)
{
if (_status.size() == 0) {
SG_LOG( SG_GENERAL, SG_WARN, "No mask available.");
return 0;
}
// Note that the object mask is closely linked to the texture/effect
// so we index based on the texture index,
unsigned int i = triangleBin.getTextureIndex() % _status.size();
if (i < _masks.size()) {
return _masks[i];
} else {
return 0;
}
// XXX This business of returning a "random" alternate texture is
// really bogus. It means that the appearance of the terrain
// depends on the order in which it is paged in!
_current_ptr = (_current_ptr + 1) % _status.size();
return _status[i].effect.get();
}
void SGMaterial::buildEffectProperties(const SGReaderWriterOptions* options)

View File

@@ -37,8 +37,11 @@
#include <map>
#include <simgear/math/SGMath.hxx>
#include "Effect.hxx"
#include <simgear/scene/tgdb/SGTexturedTriangleBin.hxx>
#include <osg/ref_ptr>
#include <osg/Texture2D>
namespace osg
{
@@ -103,7 +106,14 @@ public:
/**
* Get the textured state.
*/
simgear::Effect *get_effect(int n = -1);
simgear::Effect* get_effect(SGTexturedTriangleBin triangleBin);
simgear::Effect* get_effect();
/**
* Get the textured state.
*/
osg::Texture2D* get_object_mask(SGTexturedTriangleBin triangleBin);
/**
* Get the number of textures assigned to this material.
@@ -189,7 +199,7 @@ public:
* @return the texture to use for trees.
*/
inline std::string get_tree_texture () const { return tree_texture; }
/**
* Return if the surface material is solid, if it is not solid, a fluid
* can be assumed, that is usually water.
@@ -293,9 +303,6 @@ private:
// texture status
std::vector<_internal_state> _status;
// Round-robin counter
mutable unsigned int _current_ptr;
// texture size
double xsize, ysize;
@@ -361,6 +368,10 @@ private:
// Tree texture, typically a strip of applicable tree textures
std::string tree_texture;
// Object mask, a simple RGB texture used as a mask when placing
// random vegetation, objects and buildings
std::vector<osg::Texture2D*> _masks;
////////////////////////////////////////////////////////////////////
// Internal constructors and methods.
@@ -369,6 +380,7 @@ private:
void read_properties(const simgear::SGReaderWriterOptions* options,
const SGPropertyNode *props);
void buildEffectProperties(const simgear::SGReaderWriterOptions* options);
simgear::Effect* get_effect(int i);
};

View File

@@ -55,6 +55,7 @@ using std::map;
SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
: _models_loaded(false),
_coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
_spacing_m(node->getDoubleValue("spacing-m", 20)),
_range_m(range_m)
{
// Sanity check
@@ -77,6 +78,8 @@ SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
_heading_type = HEADING_BILLBOARD;
} else if (hdg == "random") {
_heading_type = HEADING_RANDOM;
} else if (hdg == "mask") {
_heading_type = HEADING_MASK;
} else {
_heading_type = HEADING_FIXED;
SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
@@ -135,11 +138,11 @@ SGMatModel::load_models( SGPropertyNode *prop_root )
}
osg::Node*
SGMatModel::get_random_model( SGPropertyNode *prop_root, mt seed )
SGMatModel::get_random_model( SGPropertyNode *prop_root, mt* seed )
{
load_models( prop_root ); // comment this out if preloading models
int nModels = _models.size();
return _models[mt_rand(&seed) * nModels].get();
return _models[mt_rand(seed) * nModels].get();
}
double
@@ -153,6 +156,11 @@ double SGMatModel::get_range_m() const
return _range_m;
}
double SGMatModel::get_spacing_m() const
{
return _spacing_m;
}
double SGMatModel::get_randomized_range_m(mt* seed) const
{
double lrand = mt_rand(seed);

View File

@@ -66,7 +66,8 @@ public:
enum HeadingType {
HEADING_FIXED,
HEADING_BILLBOARD,
HEADING_RANDOM
HEADING_RANDOM,
HEADING_MASK
};
/**
@@ -82,7 +83,7 @@ public:
*
* @return A randomly select model from the variants.
*/
osg::Node *get_random_model( SGPropertyNode *prop_root, mt seed );
osg::Node *get_random_model( SGPropertyNode *prop_root, mt *seed );
/**
@@ -98,6 +99,15 @@ public:
* @return The visual range.
*/
double get_range_m () const;
/**
* Get the minimum spacing between this and any
* other objects in m
*
* @return The spacing in m.
*/
double get_spacing_m () const;
/**
* Get a randomized visual range
@@ -136,6 +146,7 @@ private:
mutable std::vector<osg::ref_ptr<osg::Node> > _models;
mutable bool _models_loaded;
double _coverage_m2;
double _spacing_m;
double _range_m;
HeadingType _heading_type;
};

View File

@@ -27,12 +27,13 @@
class SGMatModelBin {
public:
struct MatModel {
MatModel(const SGVec3f& p, SGMatModel *m, int l) :
position(p), model(m), lod(l)
MatModel(const SGVec3f& p, SGMatModel *m, int l, float rot) :
position(p), model(m), lod(l), rotation(rot)
{ }
SGVec3f position;
SGMatModel *model;
int lod;
float rotation;
};
typedef std::vector<MatModel> MatModelList;
@@ -41,8 +42,8 @@ public:
_models.push_back(model);
}
void insert(const SGVec3f& p, SGMatModel *m, int l)
{ insert(MatModel(p, m, l)); }
void insert(const SGVec3f& p, SGMatModel *m, int l, float rot)
{ insert(MatModel(p, m, l, rot)); }
unsigned getNumModels() const
{ return _models.size(); }

View File

@@ -62,6 +62,7 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
SGMaterialLib* matlib = 0;
bool useRandomObjects = false;
bool useRandomVegetation = false;
float vegetation_density = 1.0f;
const SGReaderWriterOptions* sgOptions;
sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options);
if (sgOptions) {
@@ -74,12 +75,16 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
useRandomVegetation
= propertyNode->getBoolValue("/sim/rendering/random-vegetation",
useRandomVegetation);
vegetation_density
= propertyNode->getFloatValue("/sim/rendering/vegetation-density",
vegetation_density);
}
}
osg::Node* result = SGLoadBTG(fileName, matlib,
useRandomObjects,
useRandomVegetation);
useRandomVegetation,
vegetation_density);
if (result)
return result;
else

View File

@@ -25,6 +25,8 @@
#include <osg/Array>
#include <osg/Geometry>
#include <osg/PrimitiveSet>
#include <osg/Texture2D>
#include <stdio.h>
#include <simgear/math/sg_random.h>
#include <simgear/math/SGMath.hxx>
@@ -106,6 +108,7 @@ public:
// The points are offsetted away from the triangles in
// offset * positive normal direction.
void addRandomSurfacePoints(float coverage, float offset,
osg::Texture2D* object_mask,
std::vector<SGVec3f>& points)
{
unsigned num = getNumTriangles();
@@ -114,6 +117,9 @@ public:
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
SGVec3f v2 = getVertex(triangleRef[2]).vertex;
SGVec2f t0 = getVertex(triangleRef[0]).texCoord;
SGVec2f t1 = getVertex(triangleRef[1]).texCoord;
SGVec2f t2 = getVertex(triangleRef[2]).texCoord;
SGVec3f normal = cross(v1 - v0, v2 - v0);
// Compute the area
@@ -140,8 +146,24 @@ public:
}
float c = 1 - a - b;
SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
points.push_back(randomPoint);
unit -= coverage;
if (object_mask != NULL) {
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
// Check this random point against the object mask
// red 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).r()) {
points.push_back(randomPoint);
}
} else {
// No object mask, so simply place the object
points.push_back(randomPoint);
}
unit -= coverage;
}
}
}
@@ -151,6 +173,8 @@ public:
void addRandomTreePoints(float wood_coverage,
float tree_density,
float wood_size,
osg::Texture2D* object_mask,
float vegetation_density,
std::vector<SGVec3f>& points)
{
unsigned num = getNumTriangles();
@@ -159,83 +183,135 @@ public:
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
SGVec3f v2 = getVertex(triangleRef[2]).vertex;
SGVec2f t0 = getVertex(triangleRef[0]).texCoord;
SGVec2f t1 = getVertex(triangleRef[1]).texCoord;
SGVec2f t2 = getVertex(triangleRef[2]).texCoord;
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);
if (object_mask != NULL) {
// 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);
for (int j = 0; j < woodcount; j++) {
float a = mt_rand(&seed);
float b = mt_rand(&seed);
for (int j = 0; j < woodcount; j++) {
if ( a + b > 1.0f ) {
a = 1.0f - a;
b = 1.0f - b;
}
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;
float c = 1.0f - a - b;
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
// Check this random point against the object mask
// green 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()) {
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;
}
} else {
// 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);
if (wood_size < 1.0) {
// A wood size of 0 is used for an even spread of woodland,
// where each wood contains a single tree. In this case we
// need to apply the vegetation_density to the wood count rather
// than the tree density.
woodcount = woodcount * vegetation_density;
}
for (int j = 0; j < woodcount; j++) {
for (unsigned k = 0; k <= total_trees; k++) {
if (wood_size < area) {
// We need to place a wood within the triangle and populate it
float a = mt_rand(&seed);
float b = mt_rand(&seed);
// Determine the center of the wood
float x = mt_rand(&seed);
float y = mt_rand(&seed);
if ( a + b > 1.0f ) {
a = 1.0f - a;
b = 1.0f - b;
// 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;
if (wood_size >= 1.0) {
total_trees = total_trees * vegetation_density;
}
float wood_length = sqrt(ws);
float c = 1.0f - a - b;
// 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);
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
points.push_back(randomPoint);
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;
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
points.push_back(randomPoint);
}
}
}
}
@@ -243,7 +319,8 @@ public:
}
void addRandomPoints(float coverage,
std::vector<SGVec3f>& points)
osg::Texture2D* object_mask,
std::vector<std::pair<SGVec3f, float> >& points)
{
unsigned num = getNumTriangles();
for (unsigned i = 0; i < num; ++i) {
@@ -251,6 +328,9 @@ public:
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
SGVec3f v2 = getVertex(triangleRef[2]).vertex;
SGVec2f t0 = getVertex(triangleRef[0]).texCoord;
SGVec2f t1 = getVertex(triangleRef[1]).texCoord;
SGVec2f t2 = getVertex(triangleRef[2]).texCoord;
SGVec3f normal = cross(v1 - v0, v2 - v0);
// Compute the area
@@ -273,7 +353,25 @@ public:
}
float c = 1 - a - b;
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
points.push_back(randomPoint);
if (object_mask != NULL) {
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
// Check this random point against the object mask
// blue (for buildings) channel. Also check
// that they are more than spacing metres away from
// any other point.
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).b()) {
// The red channel contains the rotation for this object
points.push_back(std::make_pair(randomPoint, img->getColor(x,y).r()));
}
} else {
points.push_back(std::make_pair(randomPoint, mt_rand(&seed)));
}
num -= 1.0;
}
}
@@ -338,6 +436,16 @@ public:
osg::Geometry* buildGeometry() const
{ return buildGeometry(getTriangles()); }
int getTextureIndex() {
if (empty() || getNumTriangles() == 0)
return 0;
triangle_ref triangleRef = getTriangleRef(0);
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
return floor(v0.x());
}
private:
// Random seed for the triangle.

View File

@@ -42,6 +42,8 @@
#include <boost/foreach.hpp>
#include <algorithm>
#include <simgear/debug/logstream.hxx>
#include <simgear/io/sg_binobj.hxx>
#include <simgear/math/sg_geodesy.hxx>
@@ -382,7 +384,7 @@ struct SGTileGeometryBin {
mat = matlib->find(i->first);
eg = new EffectGeode;
if (mat)
eg->setEffect(mat->get_effect());
eg->setEffect(mat->get_effect(i->second));
eg->addDrawable(geometry);
eg->runGenerators(geometry); // Generate extra data needed by effect
if (group)
@@ -417,7 +419,7 @@ struct SGTileGeometryBin {
}
std::vector<SGVec3f> randomPoints;
i->second.addRandomSurfacePoints(coverage, 3, randomPoints);
i->second.addRandomSurfacePoints(coverage, 3, mat->get_object_mask(i->second), randomPoints);
std::vector<SGVec3f>::iterator j;
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
float zombie = mt_rand(&seed);
@@ -445,7 +447,7 @@ struct SGTileGeometryBin {
}
}
void computeRandomForest(SGMaterialLib* matlib)
void computeRandomForest(SGMaterialLib* matlib, float vegetation_density)
{
SGMaterialTriangleMap::iterator i;
@@ -493,6 +495,8 @@ struct SGTileGeometryBin {
i->second.addRandomTreePoints(wood_coverage,
mat->get_tree_density(),
mat->get_wood_size(),
mat->get_object_mask(i->second),
vegetation_density,
randomPoints);
std::vector<SGVec3f>::iterator k;
@@ -531,12 +535,29 @@ struct SGTileGeometryBin {
for (int k = 0; k < nObjects; k++) {
SGMatModel * object = object_group->get_object(k);
std::vector<SGVec3f> randomPoints;
std::vector<std::pair<SGVec3f, float> > randomPoints;
i->second.addRandomPoints(object->get_coverage_m2(), randomPoints);
std::vector<SGVec3f>::iterator l;
i->second.addRandomPoints(object->get_coverage_m2(),
mat->get_object_mask(i->second),
randomPoints);
std::vector<std::pair<SGVec3f, float> >::iterator l;
for (l = randomPoints.begin(); l != randomPoints.end(); ++l) {
randomModels.insert(*l, object, (int)object->get_randomized_range_m(&seed));
// Only add the model if it is sufficiently far from the
// other models
bool close = false;
for (unsigned i = 0; i < randomModels.getNumModels(); i++) {
float spacing = std::max(randomModels.getMatModel(i).model->get_spacing_m(), object->get_spacing_m());
spacing = spacing * spacing;
if (distSqr(randomModels.getMatModel(i).position, l->first) < spacing) {
close = true;
}
}
if (!close) {
randomModels.insert(l->first, object, (int)object->get_randomized_range_m(&seed), l->second);
}
}
}
}
@@ -544,6 +565,7 @@ struct SGTileGeometryBin {
}
}
}
bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib)
{
@@ -579,7 +601,7 @@ typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
GetModelLODCoord> RandomObjectsQuadtree;
osg::Node*
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_objects, bool use_random_vegetation)
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_objects, bool use_random_vegetation, float vegetation_density)
{
SGBinObject tile;
if (!tile.read_bin(path))
@@ -632,12 +654,14 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_object
for (unsigned int i = 0;
i < tileGeometryBin.randomModels.getNumModels(); i++) {
SGMatModelBin::MatModel obj
= tileGeometryBin.randomModels.getMatModel(i);
osg::Node* node = sgGetRandomModel(obj.model, seed);
= tileGeometryBin.randomModels.getMatModel(i);
osg::Node* node = sgGetRandomModel(obj.model, &seed);
// Create a matrix to place the object in the correct
// location, and then apply the rotation matrix created
// above, with an additional random heading rotation if appropriate.
// above, with an additional random (or taken from
// the object mask) heading rotation if appropriate.
osg::Matrix transformMat;
transformMat = osg::Matrix::translate(toOsg(obj.position));
if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) {
@@ -646,6 +670,14 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_object
transformMat.preMult(osg::Matrix::rotate(hdg,
osg::Vec3d(0.0, 0.0, 1.0)));
}
if (obj.model->get_heading_type() == SGMatModel::HEADING_MASK) {
// Rotate the object around the z axis.
double hdg = obj.rotation * M_PI * 2;
transformMat.preMult(osg::Matrix::rotate(hdg,
osg::Vec3d(0.0, 0.0, 1.0)));
}
osg::MatrixTransform* position =
new osg::MatrixTransform(transformMat);
position->addChild(node);
@@ -660,7 +692,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_object
if (use_random_vegetation && matlib) {
// Now add some random forest.
tileGeometryBin.computeRandomForest(matlib);
tileGeometryBin.computeRandomForest(matlib, vegetation_density);
if (tileGeometryBin.randomForest.size() > 0) {
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity());

View File

@@ -56,6 +56,10 @@ inline bool SGGenTile( const std::string&, const SGBucket& b,
}
osg::Node*
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_objects, bool use_random_vegetation);
SGLoadBTG(const std::string& path,
SGMaterialLib *matlib,
bool use_random_objects,
bool use_random_vegetation,
float vegetation_density);
#endif // _SG_OBJ_HXX

View File

@@ -59,7 +59,7 @@ void sgUserDataInit( SGPropertyNode *p ) {
root_props = p;
}
osg::Node* sgGetRandomModel(SGMatModel *obj, mt seed) {
osg::Node* sgGetRandomModel(SGMatModel *obj, mt *seed) {
return obj->get_random_model( root_props, seed );
}

View File

@@ -43,7 +43,7 @@ void sgUserDataInit(SGPropertyNode *p);
/**
* Get a random model.
*/
osg::Node* sgGetRandomModel(SGMatModel *obj, mt seed);
osg::Node* sgGetRandomModel(SGMatModel *obj, mt *seed);
namespace simgear
{