Random object and vegetation masking based on bitmap file.
Also adds a property controlling vegetation density.
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include<string>
|
#include <string>
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include "mat.hxx"
|
#include "mat.hxx"
|
||||||
@@ -118,14 +118,22 @@ void
|
|||||||
SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||||
const SGPropertyNode *props)
|
const SGPropertyNode *props)
|
||||||
{
|
{
|
||||||
// Gather the path(s) to the texture(s)
|
std::vector<bool> dds;
|
||||||
std::vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
|
std::vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
|
||||||
for (unsigned int i = 0; i < textures.size(); i++)
|
for (unsigned int i = 0; i < textures.size(); i++)
|
||||||
{
|
{
|
||||||
string tname = textures[i]->getStringValue();
|
string tname = textures[i]->getStringValue();
|
||||||
|
|
||||||
if (tname.empty()) {
|
if (tname.empty()) {
|
||||||
tname = "unknown.rgb";
|
tname = "unknown.rgb";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tname.rfind(".dds") == (tname.length() - 4)) {
|
||||||
|
dds.push_back(true);
|
||||||
|
} else {
|
||||||
|
dds.push_back(false);
|
||||||
|
}
|
||||||
|
|
||||||
SGPath tpath("Textures.high");
|
SGPath tpath("Textures.high");
|
||||||
tpath.append(tname);
|
tpath.append(tname);
|
||||||
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
|
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
|
||||||
@@ -152,6 +160,15 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
|||||||
if (tname.empty()) {
|
if (tname.empty()) {
|
||||||
tname = "unknown.rgb";
|
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");
|
SGPath tpath("Textures.high");
|
||||||
tpath.append(tname);
|
tpath.append(tname);
|
||||||
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
|
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
|
||||||
@@ -160,6 +177,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
|||||||
tpath.append(tname);
|
tpath.append(tname);
|
||||||
fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
|
fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
st.add_texture(fullTexPath, textures[j]->getIndex());
|
st.add_texture(fullTexPath, textures[j]->getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +194,43 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
|||||||
_status.push_back( st );
|
_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);
|
xsize = props->getDoubleValue("xsize", 0.0);
|
||||||
ysize = props->getDoubleValue("ysize", 0.0);
|
ysize = props->getDoubleValue("ysize", 0.0);
|
||||||
wrapu = props->getBoolValue("wrapu", true);
|
wrapu = props->getBoolValue("wrapu", true);
|
||||||
@@ -253,7 +308,6 @@ void
|
|||||||
SGMaterial::init ()
|
SGMaterial::init ()
|
||||||
{
|
{
|
||||||
_status.clear();
|
_status.clear();
|
||||||
_current_ptr = 0;
|
|
||||||
xsize = 0;
|
xsize = 0;
|
||||||
ysize = 0;
|
ysize = 0;
|
||||||
wrapu = true;
|
wrapu = true;
|
||||||
@@ -278,22 +332,47 @@ SGMaterial::init ()
|
|||||||
effect = "Effects/terrain-default";
|
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) {
|
if (_status.size() == 0) {
|
||||||
SG_LOG( SG_GENERAL, SG_WARN, "No effect available.");
|
SG_LOG( SG_GENERAL, SG_WARN, "No effect available.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int i = n >= 0 ? n : _current_ptr;
|
|
||||||
if(!_status[i].effect_realized) {
|
int i = triangleBin.getTextureIndex() % _status.size();
|
||||||
_status[i].effect->realizeTechniques(_status[i].options.get());
|
return get_effect(i);
|
||||||
_status[i].effect_realized = true;
|
}
|
||||||
|
|
||||||
|
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)
|
void SGMaterial::buildEffectProperties(const SGReaderWriterOptions* options)
|
||||||
|
|||||||
@@ -37,8 +37,11 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <simgear/math/SGMath.hxx>
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include "Effect.hxx"
|
||||||
|
#include <simgear/scene/tgdb/SGTexturedTriangleBin.hxx>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
@@ -103,7 +106,14 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Get the textured state.
|
* 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.
|
* Get the number of textures assigned to this material.
|
||||||
@@ -293,9 +303,6 @@ private:
|
|||||||
// texture status
|
// texture status
|
||||||
std::vector<_internal_state> _status;
|
std::vector<_internal_state> _status;
|
||||||
|
|
||||||
// Round-robin counter
|
|
||||||
mutable unsigned int _current_ptr;
|
|
||||||
|
|
||||||
// texture size
|
// texture size
|
||||||
double xsize, ysize;
|
double xsize, ysize;
|
||||||
|
|
||||||
@@ -361,6 +368,10 @@ private:
|
|||||||
|
|
||||||
// Tree texture, typically a strip of applicable tree textures
|
// Tree texture, typically a strip of applicable tree textures
|
||||||
std::string tree_texture;
|
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.
|
// Internal constructors and methods.
|
||||||
@@ -369,6 +380,7 @@ private:
|
|||||||
void read_properties(const simgear::SGReaderWriterOptions* options,
|
void read_properties(const simgear::SGReaderWriterOptions* options,
|
||||||
const SGPropertyNode *props);
|
const SGPropertyNode *props);
|
||||||
void buildEffectProperties(const simgear::SGReaderWriterOptions* options);
|
void buildEffectProperties(const simgear::SGReaderWriterOptions* options);
|
||||||
|
simgear::Effect* get_effect(int i);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ using std::map;
|
|||||||
SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
|
SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
|
||||||
: _models_loaded(false),
|
: _models_loaded(false),
|
||||||
_coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
|
_coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
|
||||||
|
_spacing_m(node->getDoubleValue("spacing-m", 20)),
|
||||||
_range_m(range_m)
|
_range_m(range_m)
|
||||||
{
|
{
|
||||||
// Sanity check
|
// Sanity check
|
||||||
@@ -77,6 +78,8 @@ SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
|
|||||||
_heading_type = HEADING_BILLBOARD;
|
_heading_type = HEADING_BILLBOARD;
|
||||||
} else if (hdg == "random") {
|
} else if (hdg == "random") {
|
||||||
_heading_type = HEADING_RANDOM;
|
_heading_type = HEADING_RANDOM;
|
||||||
|
} else if (hdg == "mask") {
|
||||||
|
_heading_type = HEADING_MASK;
|
||||||
} else {
|
} else {
|
||||||
_heading_type = HEADING_FIXED;
|
_heading_type = HEADING_FIXED;
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
|
SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
|
||||||
@@ -135,11 +138,11 @@ SGMatModel::load_models( SGPropertyNode *prop_root )
|
|||||||
}
|
}
|
||||||
|
|
||||||
osg::Node*
|
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
|
load_models( prop_root ); // comment this out if preloading models
|
||||||
int nModels = _models.size();
|
int nModels = _models.size();
|
||||||
return _models[mt_rand(&seed) * nModels].get();
|
return _models[mt_rand(seed) * nModels].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
@@ -153,6 +156,11 @@ double SGMatModel::get_range_m() const
|
|||||||
return _range_m;
|
return _range_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SGMatModel::get_spacing_m() const
|
||||||
|
{
|
||||||
|
return _spacing_m;
|
||||||
|
}
|
||||||
|
|
||||||
double SGMatModel::get_randomized_range_m(mt* seed) const
|
double SGMatModel::get_randomized_range_m(mt* seed) const
|
||||||
{
|
{
|
||||||
double lrand = mt_rand(seed);
|
double lrand = mt_rand(seed);
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ public:
|
|||||||
enum HeadingType {
|
enum HeadingType {
|
||||||
HEADING_FIXED,
|
HEADING_FIXED,
|
||||||
HEADING_BILLBOARD,
|
HEADING_BILLBOARD,
|
||||||
HEADING_RANDOM
|
HEADING_RANDOM,
|
||||||
|
HEADING_MASK
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +83,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @return A randomly select model from the variants.
|
* @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 );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,6 +100,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
double get_range_m () const;
|
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
|
* Get a randomized visual range
|
||||||
*
|
*
|
||||||
@@ -136,6 +146,7 @@ private:
|
|||||||
mutable std::vector<osg::ref_ptr<osg::Node> > _models;
|
mutable std::vector<osg::ref_ptr<osg::Node> > _models;
|
||||||
mutable bool _models_loaded;
|
mutable bool _models_loaded;
|
||||||
double _coverage_m2;
|
double _coverage_m2;
|
||||||
|
double _spacing_m;
|
||||||
double _range_m;
|
double _range_m;
|
||||||
HeadingType _heading_type;
|
HeadingType _heading_type;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,12 +27,13 @@
|
|||||||
class SGMatModelBin {
|
class SGMatModelBin {
|
||||||
public:
|
public:
|
||||||
struct MatModel {
|
struct MatModel {
|
||||||
MatModel(const SGVec3f& p, SGMatModel *m, int l) :
|
MatModel(const SGVec3f& p, SGMatModel *m, int l, float rot) :
|
||||||
position(p), model(m), lod(l)
|
position(p), model(m), lod(l), rotation(rot)
|
||||||
{ }
|
{ }
|
||||||
SGVec3f position;
|
SGVec3f position;
|
||||||
SGMatModel *model;
|
SGMatModel *model;
|
||||||
int lod;
|
int lod;
|
||||||
|
float rotation;
|
||||||
};
|
};
|
||||||
typedef std::vector<MatModel> MatModelList;
|
typedef std::vector<MatModel> MatModelList;
|
||||||
|
|
||||||
@@ -41,8 +42,8 @@ public:
|
|||||||
_models.push_back(model);
|
_models.push_back(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(const SGVec3f& p, SGMatModel *m, int l)
|
void insert(const SGVec3f& p, SGMatModel *m, int l, float rot)
|
||||||
{ insert(MatModel(p, m, l)); }
|
{ insert(MatModel(p, m, l, rot)); }
|
||||||
|
|
||||||
unsigned getNumModels() const
|
unsigned getNumModels() const
|
||||||
{ return _models.size(); }
|
{ return _models.size(); }
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
|
|||||||
SGMaterialLib* matlib = 0;
|
SGMaterialLib* matlib = 0;
|
||||||
bool useRandomObjects = false;
|
bool useRandomObjects = false;
|
||||||
bool useRandomVegetation = false;
|
bool useRandomVegetation = false;
|
||||||
|
float vegetation_density = 1.0f;
|
||||||
const SGReaderWriterOptions* sgOptions;
|
const SGReaderWriterOptions* sgOptions;
|
||||||
sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options);
|
sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options);
|
||||||
if (sgOptions) {
|
if (sgOptions) {
|
||||||
@@ -74,12 +75,16 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
|
|||||||
useRandomVegetation
|
useRandomVegetation
|
||||||
= propertyNode->getBoolValue("/sim/rendering/random-vegetation",
|
= propertyNode->getBoolValue("/sim/rendering/random-vegetation",
|
||||||
useRandomVegetation);
|
useRandomVegetation);
|
||||||
|
vegetation_density
|
||||||
|
= propertyNode->getFloatValue("/sim/rendering/vegetation-density",
|
||||||
|
vegetation_density);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Node* result = SGLoadBTG(fileName, matlib,
|
osg::Node* result = SGLoadBTG(fileName, matlib,
|
||||||
useRandomObjects,
|
useRandomObjects,
|
||||||
useRandomVegetation);
|
useRandomVegetation,
|
||||||
|
vegetation_density);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#include <osg/Array>
|
#include <osg/Array>
|
||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
#include <osg/PrimitiveSet>
|
#include <osg/PrimitiveSet>
|
||||||
|
#include <osg/Texture2D>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <simgear/math/sg_random.h>
|
#include <simgear/math/sg_random.h>
|
||||||
#include <simgear/math/SGMath.hxx>
|
#include <simgear/math/SGMath.hxx>
|
||||||
@@ -106,6 +108,7 @@ public:
|
|||||||
// The points are offsetted away from the triangles in
|
// The points are offsetted away from the triangles in
|
||||||
// offset * positive normal direction.
|
// offset * positive normal direction.
|
||||||
void addRandomSurfacePoints(float coverage, float offset,
|
void addRandomSurfacePoints(float coverage, float offset,
|
||||||
|
osg::Texture2D* object_mask,
|
||||||
std::vector<SGVec3f>& points)
|
std::vector<SGVec3f>& points)
|
||||||
{
|
{
|
||||||
unsigned num = getNumTriangles();
|
unsigned num = getNumTriangles();
|
||||||
@@ -114,6 +117,9 @@ public:
|
|||||||
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
|
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
|
||||||
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
|
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
|
||||||
SGVec3f v2 = getVertex(triangleRef[2]).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);
|
SGVec3f normal = cross(v1 - v0, v2 - v0);
|
||||||
|
|
||||||
// Compute the area
|
// Compute the area
|
||||||
@@ -140,7 +146,23 @@ public:
|
|||||||
}
|
}
|
||||||
float c = 1 - a - b;
|
float c = 1 - a - b;
|
||||||
SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
|
SGVec3f randomPoint = offsetVector + 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
|
||||||
|
// 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;
|
unit -= coverage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,6 +173,8 @@ public:
|
|||||||
void addRandomTreePoints(float wood_coverage,
|
void addRandomTreePoints(float wood_coverage,
|
||||||
float tree_density,
|
float tree_density,
|
||||||
float wood_size,
|
float wood_size,
|
||||||
|
osg::Texture2D* object_mask,
|
||||||
|
float vegetation_density,
|
||||||
std::vector<SGVec3f>& points)
|
std::vector<SGVec3f>& points)
|
||||||
{
|
{
|
||||||
unsigned num = getNumTriangles();
|
unsigned num = getNumTriangles();
|
||||||
@@ -159,6 +183,9 @@ public:
|
|||||||
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
|
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
|
||||||
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
|
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
|
||||||
SGVec3f v2 = getVertex(triangleRef[2]).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);
|
SGVec3f normal = cross(v1 - v0, v2 - v0);
|
||||||
|
|
||||||
// Compute the area
|
// Compute the area
|
||||||
@@ -166,76 +193,125 @@ public:
|
|||||||
if (area <= SGLimitsf::min())
|
if (area <= SGLimitsf::min())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// For partial units of area, use a zombie door method to
|
if (object_mask != NULL) {
|
||||||
// create the proper random chance of a point being created
|
// For partial units of area, use a zombie door method to
|
||||||
// for this triangle
|
// create the proper random chance of a point being created
|
||||||
float unit = area + mt_rand(&seed)*wood_coverage;
|
// for this triangle
|
||||||
|
float unit = area + mt_rand(&seed)*wood_coverage;
|
||||||
|
|
||||||
int woodcount = (int) (unit / 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++) {
|
for (int j = 0; j < woodcount; j++) {
|
||||||
|
float a = mt_rand(&seed);
|
||||||
|
float b = mt_rand(&seed);
|
||||||
|
|
||||||
if (wood_size < area) {
|
if ( a + b > 1.0f ) {
|
||||||
// We need to place a wood within the triangle and populate it
|
a = 1.0f - a;
|
||||||
|
b = 1.0f - b;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine the center of the wood
|
float c = 1.0f - a - b;
|
||||||
float x = mt_rand(&seed);
|
|
||||||
float y = mt_rand(&seed);
|
|
||||||
|
|
||||||
// Determine the size of this wood in m^2, and the number
|
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
|
||||||
// of trees in the wood
|
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
|
||||||
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.
|
// Check this random point against the object mask
|
||||||
// This will be used as a factor when placing trees in the wood.
|
// green channel.
|
||||||
float x_tree_factor = wood_length / length(v1 -v0);
|
osg::Image* img = object_mask->getImage();
|
||||||
float y_tree_factor = wood_length / length(v2 -v0);
|
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
|
||||||
|
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
|
||||||
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;
|
|
||||||
|
|
||||||
|
if (mt_rand(&seed) < img->getColor(x, y).g()) {
|
||||||
points.push_back(randomPoint);
|
points.push_back(randomPoint);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// This triangle is too small to contain a complete wood, so just
|
} else {
|
||||||
// distribute trees across it.
|
// For partial units of area, use a zombie door method to
|
||||||
unsigned total_trees = area / tree_density;
|
// 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 k = 0; k <= total_trees; k++) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
float a = mt_rand(&seed);
|
for (int j = 0; j < woodcount; j++) {
|
||||||
float b = mt_rand(&seed);
|
|
||||||
|
|
||||||
if ( a + b > 1.0f ) {
|
if (wood_size < area) {
|
||||||
a = 1.0f - a;
|
// We need to place a wood within the triangle and populate it
|
||||||
b = 1.0f - b;
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
if (wood_size >= 1.0) {
|
||||||
|
total_trees = total_trees * vegetation_density;
|
||||||
}
|
}
|
||||||
|
|
||||||
float c = 1.0f - a - b;
|
float wood_length = sqrt(ws);
|
||||||
|
|
||||||
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
|
// From our wood size, work out the fraction on the two axis.
|
||||||
points.push_back(randomPoint);
|
// 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;
|
||||||
|
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
|
||||||
|
points.push_back(randomPoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +319,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addRandomPoints(float coverage,
|
void addRandomPoints(float coverage,
|
||||||
std::vector<SGVec3f>& points)
|
osg::Texture2D* object_mask,
|
||||||
|
std::vector<std::pair<SGVec3f, float> >& points)
|
||||||
{
|
{
|
||||||
unsigned num = getNumTriangles();
|
unsigned num = getNumTriangles();
|
||||||
for (unsigned i = 0; i < num; ++i) {
|
for (unsigned i = 0; i < num; ++i) {
|
||||||
@@ -251,6 +328,9 @@ public:
|
|||||||
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
|
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
|
||||||
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
|
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
|
||||||
SGVec3f v2 = getVertex(triangleRef[2]).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);
|
SGVec3f normal = cross(v1 - v0, v2 - v0);
|
||||||
|
|
||||||
// Compute the area
|
// Compute the area
|
||||||
@@ -273,7 +353,25 @@ public:
|
|||||||
}
|
}
|
||||||
float c = 1 - a - b;
|
float c = 1 - a - b;
|
||||||
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
|
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;
|
num -= 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,6 +437,16 @@ public:
|
|||||||
osg::Geometry* buildGeometry() const
|
osg::Geometry* buildGeometry() const
|
||||||
{ return buildGeometry(getTriangles()); }
|
{ 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:
|
private:
|
||||||
// Random seed for the triangle.
|
// Random seed for the triangle.
|
||||||
mt seed;
|
mt seed;
|
||||||
|
|||||||
+43
-11
@@ -42,6 +42,8 @@
|
|||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/io/sg_binobj.hxx>
|
#include <simgear/io/sg_binobj.hxx>
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
@@ -382,7 +384,7 @@ struct SGTileGeometryBin {
|
|||||||
mat = matlib->find(i->first);
|
mat = matlib->find(i->first);
|
||||||
eg = new EffectGeode;
|
eg = new EffectGeode;
|
||||||
if (mat)
|
if (mat)
|
||||||
eg->setEffect(mat->get_effect());
|
eg->setEffect(mat->get_effect(i->second));
|
||||||
eg->addDrawable(geometry);
|
eg->addDrawable(geometry);
|
||||||
eg->runGenerators(geometry); // Generate extra data needed by effect
|
eg->runGenerators(geometry); // Generate extra data needed by effect
|
||||||
if (group)
|
if (group)
|
||||||
@@ -417,7 +419,7 @@ struct SGTileGeometryBin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SGVec3f> randomPoints;
|
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;
|
std::vector<SGVec3f>::iterator j;
|
||||||
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
|
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
|
||||||
float zombie = mt_rand(&seed);
|
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;
|
SGMaterialTriangleMap::iterator i;
|
||||||
|
|
||||||
@@ -493,6 +495,8 @@ struct SGTileGeometryBin {
|
|||||||
i->second.addRandomTreePoints(wood_coverage,
|
i->second.addRandomTreePoints(wood_coverage,
|
||||||
mat->get_tree_density(),
|
mat->get_tree_density(),
|
||||||
mat->get_wood_size(),
|
mat->get_wood_size(),
|
||||||
|
mat->get_object_mask(i->second),
|
||||||
|
vegetation_density,
|
||||||
randomPoints);
|
randomPoints);
|
||||||
|
|
||||||
std::vector<SGVec3f>::iterator k;
|
std::vector<SGVec3f>::iterator k;
|
||||||
@@ -531,12 +535,29 @@ struct SGTileGeometryBin {
|
|||||||
for (int k = 0; k < nObjects; k++) {
|
for (int k = 0; k < nObjects; k++) {
|
||||||
SGMatModel * object = object_group->get_object(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);
|
i->second.addRandomPoints(object->get_coverage_m2(),
|
||||||
std::vector<SGVec3f>::iterator l;
|
mat->get_object_mask(i->second),
|
||||||
|
randomPoints);
|
||||||
|
std::vector<std::pair<SGVec3f, float> >::iterator l;
|
||||||
for (l = randomPoints.begin(); l != randomPoints.end(); ++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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -545,6 +566,7 @@ struct SGTileGeometryBin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib)
|
bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib)
|
||||||
{
|
{
|
||||||
if (!insertPtGeometry(obj, matlib))
|
if (!insertPtGeometry(obj, matlib))
|
||||||
@@ -579,7 +601,7 @@ typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
|
|||||||
GetModelLODCoord> RandomObjectsQuadtree;
|
GetModelLODCoord> RandomObjectsQuadtree;
|
||||||
|
|
||||||
osg::Node*
|
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;
|
SGBinObject tile;
|
||||||
if (!tile.read_bin(path))
|
if (!tile.read_bin(path))
|
||||||
@@ -633,11 +655,13 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_object
|
|||||||
i < tileGeometryBin.randomModels.getNumModels(); i++) {
|
i < tileGeometryBin.randomModels.getNumModels(); i++) {
|
||||||
SGMatModelBin::MatModel obj
|
SGMatModelBin::MatModel obj
|
||||||
= tileGeometryBin.randomModels.getMatModel(i);
|
= tileGeometryBin.randomModels.getMatModel(i);
|
||||||
osg::Node* node = sgGetRandomModel(obj.model, seed);
|
|
||||||
|
osg::Node* node = sgGetRandomModel(obj.model, &seed);
|
||||||
|
|
||||||
// Create a matrix to place the object in the correct
|
// Create a matrix to place the object in the correct
|
||||||
// location, and then apply the rotation matrix created
|
// 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;
|
osg::Matrix transformMat;
|
||||||
transformMat = osg::Matrix::translate(toOsg(obj.position));
|
transformMat = osg::Matrix::translate(toOsg(obj.position));
|
||||||
if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) {
|
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,
|
transformMat.preMult(osg::Matrix::rotate(hdg,
|
||||||
osg::Vec3d(0.0, 0.0, 1.0)));
|
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 =
|
osg::MatrixTransform* position =
|
||||||
new osg::MatrixTransform(transformMat);
|
new osg::MatrixTransform(transformMat);
|
||||||
position->addChild(node);
|
position->addChild(node);
|
||||||
@@ -660,7 +692,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_object
|
|||||||
|
|
||||||
if (use_random_vegetation && matlib) {
|
if (use_random_vegetation && matlib) {
|
||||||
// Now add some random forest.
|
// Now add some random forest.
|
||||||
tileGeometryBin.computeRandomForest(matlib);
|
tileGeometryBin.computeRandomForest(matlib, vegetation_density);
|
||||||
|
|
||||||
if (tileGeometryBin.randomForest.size() > 0) {
|
if (tileGeometryBin.randomForest.size() > 0) {
|
||||||
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity());
|
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity());
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ inline bool SGGenTile( const std::string&, const SGBucket& b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
osg::Node*
|
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
|
#endif // _SG_OBJ_HXX
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ void sgUserDataInit( SGPropertyNode *p ) {
|
|||||||
root_props = 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 );
|
return obj->get_random_model( root_props, seed );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ void sgUserDataInit(SGPropertyNode *p);
|
|||||||
/**
|
/**
|
||||||
* Get a random model.
|
* Get a random model.
|
||||||
*/
|
*/
|
||||||
osg::Node* sgGetRandomModel(SGMatModel *obj, mt seed);
|
osg::Node* sgGetRandomModel(SGMatModel *obj, mt *seed);
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user