Second trees patch from Stuart Buchanan

Adds random variation of tree texture maps
This commit is contained in:
timoore
2008-02-07 23:00:23 +00:00
parent be61689458
commit 8cbe9f1bd0
11 changed files with 170 additions and 110 deletions
+5 -8
View File
@@ -145,6 +145,11 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
tree_height = props->getDoubleValue("tree-height-m", 0.0); tree_height = props->getDoubleValue("tree-height-m", 0.0);
tree_width = props->getDoubleValue("tree-width-m", 0.0); tree_width = props->getDoubleValue("tree-width-m", 0.0);
tree_range = props->getDoubleValue("tree-range-m", 0.0); tree_range = props->getDoubleValue("tree-range-m", 0.0);
tree_varieties = props->getIntValue("tree-varieties", 1);
SGPath tpath( fg_root );
tpath.append(props->getStringValue("tree-texture"));
tree_texture = tpath.str();
// surface values for use with ground reactions // surface values for use with ground reactions
solid = props->getBoolValue("solid", true); solid = props->getBoolValue("solid", true);
@@ -181,14 +186,6 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
for (unsigned int i = 0; i < object_group_nodes.size(); i++) for (unsigned int i = 0; i < object_group_nodes.size(); i++)
object_groups.push_back(new SGMatModelGroup(object_group_nodes[i])); object_groups.push_back(new SGMatModelGroup(object_group_nodes[i]));
vector<SGPropertyNode_ptr> tree_texture_nodes =
((SGPropertyNode *)props)->getChildren("tree-texture");
for (unsigned int i = 0; i < tree_texture_nodes.size(); i++) {
SGPath tpath( fg_root );
tpath.append(tree_texture_nodes[i]->getStringValue());
tree_textures.push_back(tpath.str());
}
// read glyph table for taxi-/runway-signs // read glyph table for taxi-/runway-signs
vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph"); vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph");
for (unsigned int i = 0; i < glyph_nodes.size(); i++) { for (unsigned int i = 0; i < glyph_nodes.size(); i++) {
+15 -5
View File
@@ -177,11 +177,18 @@ public:
inline double get_tree_range () const { return tree_range; } inline double get_tree_range () const { return tree_range; }
/** /**
* Get the list of textures to use for trees in the forest * Get the number of tree varieties available
* *
* @return the vector of forest textures to use. * @return the number of different trees defined in the texture strip
*/ */
inline vector<string> get_tree_textures () const { return tree_textures; } inline int get_tree_varieties () const { return tree_varieties; }
/**
* Get the texture strip to use for trees
*
* @return the texture to use for trees.
*/
inline string get_tree_texture () const { return tree_texture; }
/** /**
* Return if the surface material is solid, if it is not solid, a fluid * Return if the surface material is solid, if it is not solid, a fluid
@@ -309,6 +316,9 @@ private:
// Width of the tree // Width of the tree
double tree_width; double tree_width;
// Number of varieties of tree texture
int tree_varieties;
// True if the material is solid, false if it is a fluid // True if the material is solid, false if it is a fluid
bool solid; bool solid;
@@ -336,8 +346,8 @@ private:
// taxiway-/runway-sign texture elements // taxiway-/runway-sign texture elements
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs; map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
// The list of forest textures, used when creating trees // Tree texture, typically a strip of applicable tree textures
vector<string> tree_textures; string tree_texture;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Internal constructors and methods. // Internal constructors and methods.
-3
View File
@@ -263,7 +263,4 @@ SGMatModelGroup::get_object (int index) const
return _objects[index]; return _objects[index];
} }
// end of matmodel.cxx // end of matmodel.cxx
+4 -1
View File
@@ -54,15 +54,18 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
SGMaterialLib* matlib = 0; SGMaterialLib* matlib = 0;
bool calcLights = false; bool calcLights = false;
bool useRandomObjects = false; bool useRandomObjects = false;
bool useRandomVegetation = false;
const SGReaderWriterBTGOptions* btgOptions const SGReaderWriterBTGOptions* btgOptions
= dynamic_cast<const SGReaderWriterBTGOptions*>(options); = dynamic_cast<const SGReaderWriterBTGOptions*>(options);
if (btgOptions) { if (btgOptions) {
matlib = btgOptions->getMatlib(); matlib = btgOptions->getMatlib();
calcLights = btgOptions->getCalcLights(); calcLights = btgOptions->getCalcLights();
useRandomObjects = btgOptions->getUseRandomObjects(); useRandomObjects = btgOptions->getUseRandomObjects();
useRandomVegetation = btgOptions->getUseRandomVegetation();
} }
osg::Node* result = SGLoadBTG(fileName, matlib, calcLights, osg::Node* result = SGLoadBTG(fileName, matlib, calcLights,
useRandomObjects); useRandomObjects,
useRandomVegetation);
if (result) if (result)
return result; return result;
else else
@@ -24,14 +24,17 @@ public:
SGReaderWriterBTGOptions() {} SGReaderWriterBTGOptions() {}
SGReaderWriterBTGOptions(const std::string& str): SGReaderWriterBTGOptions(const std::string& str):
osgDB::ReaderWriter::Options(str), osgDB::ReaderWriter::Options(str),
_matlib(0), _calcLights(false), _useRandomObjects(false) _matlib(0), _calcLights(false),
_useRandomObjects(false),
_useRandomVegetation(false)
{} {}
SGReaderWriterBTGOptions(const SGReaderWriterBTGOptions& options, SGReaderWriterBTGOptions(const SGReaderWriterBTGOptions& options,
const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
osgDB::ReaderWriter::Options(options, copyop), osgDB::ReaderWriter::Options(options, copyop),
_matlib(options._matlib), _calcLights(options._calcLights), _matlib(options._matlib), _calcLights(options._calcLights),
_useRandomObjects(options._useRandomObjects) _useRandomObjects(options._useRandomObjects),
_useRandomVegetation(options._useRandomVegetation)
{ {
} }
SGMaterialLib* getMatlib() const { return _matlib; } SGMaterialLib* getMatlib() const { return _matlib; }
@@ -39,15 +42,21 @@ public:
bool getCalcLights() const { return _calcLights; } bool getCalcLights() const { return _calcLights; }
void setCalcLights(bool calcLights) { _calcLights = calcLights; } void setCalcLights(bool calcLights) { _calcLights = calcLights; }
bool getUseRandomObjects() const { return _useRandomObjects; } bool getUseRandomObjects() const { return _useRandomObjects; }
bool getUseRandomVegetation() const { return _useRandomVegetation; }
void setUseRandomObjects(bool useRandomObjects) void setUseRandomObjects(bool useRandomObjects)
{ {
_useRandomObjects = useRandomObjects; _useRandomObjects = useRandomObjects;
} }
void setUseRandomVegetation(bool useRandomVegetation)
{
_useRandomVegetation = useRandomVegetation;
}
protected: protected:
virtual ~SGReaderWriterBTGOptions() {} virtual ~SGReaderWriterBTGOptions() {}
SGMaterialLib* _matlib; SGMaterialLib* _matlib;
bool _calcLights; bool _calcLights;
bool _useRandomObjects; bool _useRandomObjects;
bool _useRandomVegetation;
}; };
#endif #endif
+24 -16
View File
@@ -22,6 +22,7 @@
#include <osgDB/Registry> #include <osgDB/Registry>
#include <osgDB/Input> #include <osgDB/Input>
#include <osgDB/ParameterOutput> #include <osgDB/ParameterOutput>
#include <simgear/screen/extensions.hxx>
#include "ShaderGeometry.hxx" #include "ShaderGeometry.hxx"
@@ -32,10 +33,13 @@ namespace simgear
{ {
void ShaderGeometry::drawImplementation(RenderInfo& renderInfo) const void ShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
{ {
for(PositionSizeList::const_iterator itr = _trees.begin(); osg::State& state = *renderInfo.getState();
itr != _trees.end(); const Extensions* extensions = getExtensions(state.getContextID(),true);
++itr) {
glColor4fv(itr->ptr()); for(TreeBin::TreeList::const_iterator t = _trees.begin(); t != _trees.end(); ++t)
{
extensions->glVertexAttrib1f(1, (float) t->texture_index/varieties);
glColor4f(t->position.x(), t->position.y(), t->position.z(), t->scale);
_geometry->draw(renderInfo); _geometry->draw(renderInfo);
} }
} }
@@ -44,13 +48,13 @@ BoundingBox ShaderGeometry::computeBound() const
{ {
BoundingBox geom_box = _geometry->getBound(); BoundingBox geom_box = _geometry->getBound();
BoundingBox bb; BoundingBox bb;
for(PositionSizeList::const_iterator itr = _trees.begin(); for(TreeBin::TreeList::const_iterator itr = _trees.begin();
itr != _trees.end(); itr != _trees.end();
++itr) { ++itr) {
bb.expandBy(geom_box.corner(0)*(*itr)[3] + bb.expandBy(geom_box.corner(0)*itr->scale +
Vec3((*itr)[0], (*itr)[1], (*itr)[2])); osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
bb.expandBy(geom_box.corner(7)*(*itr)[3] + bb.expandBy(geom_box.corner(7)*itr->scale +
Vec3((*itr)[0], (*itr)[1], (*itr)[2])); osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
} }
return bb; return bb;
} }
@@ -64,7 +68,7 @@ bool ShaderGeometry_readLocalData(Object& obj, Input& fr)
if ((fr[0].matchWord("geometry"))) { if ((fr[0].matchWord("geometry"))) {
++fr; ++fr;
iteratorAdvanced = true; iteratorAdvanced = true;
Drawable* drawable = fr.readDrawable(); osg::Drawable* drawable = fr.readDrawable();
if (drawable) { if (drawable) {
geom._geometry = drawable; geom._geometry = drawable;
} }
@@ -78,11 +82,15 @@ bool ShaderGeometry_readLocalData(Object& obj, Input& fr)
iteratorAdvanced = true; iteratorAdvanced = true;
// skip { // skip {
while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) { while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) {
Vec4 v; SGVec3f v;
int t;
float s;
if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y()) if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y())
&& fr[2].getFloat(v.z()) && fr[3].getFloat(v.w())) { && fr[2].getFloat(v.z()) && fr[3].getInt(t) && fr[4].getFloat(s)) {
fr += 4; fr += 4;
geom._trees.push_back(v); //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
//TreeBin::Tree tree = new TreeBin::Tree(v, t, s);
geom._trees.push_back(TreeBin::Tree(v, t, s));
} else { } else {
++fr; ++fr;
} }
@@ -100,12 +108,12 @@ bool ShaderGeometry_writeLocalData(const Object& obj, Output& fw)
fw.indent() << "instances " << geom._trees.size() << std::endl; fw.indent() << "instances " << geom._trees.size() << std::endl;
fw.indent() << "{" << std::endl; fw.indent() << "{" << std::endl;
fw.moveIn(); fw.moveIn();
for (ShaderGeometry::PositionSizeList::const_iterator iter for (TreeBin::TreeList::const_iterator iter
= geom._trees.begin(); = geom._trees.begin();
iter != geom._trees.end(); iter != geom._trees.end();
++iter) { ++iter) {
fw.indent() << iter->x() << " " << iter->y() << " " << iter->z() << " " fw.indent() << iter->position.x() << " " << iter->position.y() << " " << iter->position.z() << " "
<< iter->w() << std::endl; << iter->texture_index << " " << iter->scale << std::endl;
} }
fw.moveOut(); fw.moveOut();
fw.indent() << "}" << std::endl; fw.indent() << "}" << std::endl;
+12 -3
View File
@@ -32,6 +32,8 @@
#include <osg/Vec3> #include <osg/Vec3>
#include <osg/Vec4> #include <osg/Vec4>
#include "TreeBin.hxx"
namespace simgear namespace simgear
{ {
@@ -42,6 +44,12 @@ class ShaderGeometry : public osg::Drawable
{ {
setUseDisplayList(false); setUseDisplayList(false);
} }
ShaderGeometry(int v) :
varieties(v)
{
setUseDisplayList(false);
}
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/ /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
@@ -60,14 +68,15 @@ class ShaderGeometry : public osg::Drawable
_geometry = geometry; _geometry = geometry;
} }
void addTree(const osg::Vec3& position, float scale) void addTree(TreeBin::Tree tree)
{ {
_trees.push_back(osg::Vec4(position, scale)); _trees.push_back(tree);
} }
osg::ref_ptr<osg::Drawable> _geometry; osg::ref_ptr<osg::Drawable> _geometry;
PositionSizeList _trees; TreeBin::TreeList _trees;
int varieties;
protected: protected:
+36 -26
View File
@@ -64,7 +64,7 @@ using namespace osg;
namespace simgear namespace simgear
{ {
osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate) osg::Geometry* createOrthQuads(float w, float h, int varieties, const osg::Matrix& rotate)
{ {
//const osg::Vec3& pos = osg::Vec3(0.0f,0.0f,0.0f), //const osg::Vec3& pos = osg::Vec3(0.0f,0.0f,0.0f),
@@ -87,14 +87,19 @@ osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate)
v[6].set( cw,0.0f,h); v[6].set( cw,0.0f,h);
v[7].set(-cw,0.0f,h); v[7].set(-cw,0.0f,h);
// The texture coordinate range is not the
// entire coordinate space - as the texture
// has a number of different trees on it.
float tx = 1.0f/varieties;
t[0].set(0.0f,0.0f); t[0].set(0.0f,0.0f);
t[1].set(1.0f,0.0f); t[1].set( tx,0.0f);
t[2].set(1.0f,1.0f); t[2].set( tx,1.0f);
t[3].set(0.0f,1.0f); t[3].set(0.0f,1.0f);
t[4].set(0.0f,0.0f); t[4].set(0.0f,0.0f);
t[5].set(1.0f,0.0f); t[5].set( tx,0.0f);
t[6].set(1.0f,1.0f); t[6].set( tx,1.0f);
t[7].set(0.0f,1.0f); t[7].set(0.0f,1.0f);
// For now the normal is normal to the quad. If we want to get // For now the normal is normal to the quad. If we want to get
@@ -122,10 +127,13 @@ osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate)
} }
static char vertexShaderSource[] = static char vertexShaderSource[] =
"varying vec2 texcoord;\n"
"varying float fogFactor;\n" "varying float fogFactor;\n"
"attribute float textureIndex;\n"
"\n" "\n"
"void main(void)\n" "void main(void)\n"
"{\n" "{\n"
" texcoord = gl_MultiTexCoord0.st + vec2(textureIndex, 0.0);\n"
" vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n" " vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n"
" gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n" " gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
" vec3 ecPosition = vec3(gl_ModelViewMatrix * vec4(position, 1.0));\n" " vec3 ecPosition = vec3(gl_ModelViewMatrix * vec4(position, 1.0));\n"
@@ -135,7 +143,7 @@ osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate)
" vec4 ambientColor = gl_FrontLightModelProduct.sceneColor + gl_LightSource[0].ambient * gl_FrontMaterial.ambient;\n" " vec4 ambientColor = gl_FrontLightModelProduct.sceneColor + gl_LightSource[0].ambient * gl_FrontMaterial.ambient;\n"
" gl_FrontColor = ambientColor + gl_LightSource[0].diffuse * vec4(diffuse, 1.0);\n" " gl_FrontColor = ambientColor + gl_LightSource[0].diffuse * vec4(diffuse, 1.0);\n"
" gl_BackColor = ambientColor + gl_LightSource[0].diffuse * vec4(backDiffuse, 1.0)\n;" " gl_BackColor = ambientColor + gl_LightSource[0].diffuse * vec4(backDiffuse, 1.0)\n;"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n" // " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" float fogCoord = abs(ecPosition.z);\n" " float fogCoord = abs(ecPosition.z);\n"
" fogFactor = exp( -gl_Fog.density * gl_Fog.density * fogCoord * fogCoord);\n" " fogFactor = exp( -gl_Fog.density * gl_Fog.density * fogCoord * fogCoord);\n"
" fogFactor = clamp(fogFactor, 0.0, 1.0);\n" " fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
@@ -143,13 +151,14 @@ osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate)
static char fragmentShaderSource[] = static char fragmentShaderSource[] =
"uniform sampler2D baseTexture; \n" "uniform sampler2D baseTexture; \n"
// "varying vec3 N;\n" "varying vec2 texcoord;\n"
// "varying vec3 N;\n"
// "varying vec3 v;\n" // "varying vec3 v;\n"
"varying float fogFactor;\n" "varying float fogFactor;\n"
"\n" "\n"
"void main(void) \n" "void main(void) \n"
"{ \n" "{ \n"
" vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n" " vec4 base = texture2D( baseTexture, texcoord);\n"
" vec4 finalColor = base * gl_Color;\n" " vec4 finalColor = base * gl_Color;\n"
" gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n" " gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n"
@@ -164,22 +173,23 @@ namespace
{ {
struct MakeTreesLeaf struct MakeTreesLeaf
{ {
MakeTreesLeaf(float range, Geometry* geometry) : MakeTreesLeaf(float range, Geometry* geometry, int varieties) :
_range(range), _geometry(geometry) _range(range), _geometry(geometry), _varieties(varieties)
{} {}
MakeTreesLeaf(const MakeTreesLeaf& rhs) : MakeTreesLeaf(const MakeTreesLeaf& rhs) :
_range(rhs._range), _geometry(rhs._geometry) {} _range(rhs._range), _geometry(rhs._geometry), _varieties(rhs._varieties) {}
LOD* operator() () const LOD* operator() () const
{ {
LOD* result = new LOD; LOD* result = new LOD;
Geode* geode = new Geode; Geode* geode = new Geode;
ShaderGeometry* sg = new ShaderGeometry; ShaderGeometry* sg = new ShaderGeometry(_varieties);
sg->setGeometry(_geometry); sg->setGeometry(_geometry);
geode->addDrawable(sg); geode->addDrawable(sg);
result->addChild(geode, 0, _range); result->addChild(geode, 0, _range);
return result; return result;
} }
float _range; float _range;
int _varieties;
Geometry* _geometry; Geometry* _geometry;
}; };
@@ -190,7 +200,7 @@ struct AddTreesLeafObject
Geode* geode = static_cast<Geode*>(lod->getChild(0)); Geode* geode = static_cast<Geode*>(lod->getChild(0));
ShaderGeometry* sg ShaderGeometry* sg
= static_cast<ShaderGeometry*>(geode->getDrawable(0)); = static_cast<ShaderGeometry*>(geode->getDrawable(0));
sg->addTree(tree.position.osg(), tree.height); sg->addTree(tree);
} }
}; };
@@ -212,22 +222,20 @@ typedef QuadTreeBuilder<LOD*, TreeBin::Tree, MakeTreesLeaf, AddTreesLeafObject,
osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform) osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
{ {
// Set up some shared structures. // Set up some shared structures.
// FIXME: Currently we only take the texture, height and width of the first tree in the forest. In the future osg::Geometry* shared_geometry = createOrthQuads(forest.width,
// we should be able to handle multiple textures etc. forest.height,
TreeBin::Tree firstTree = forest.getTree(0); forest.texture_varieties,
osg::Geometry* shared_geometry = createOrthQuads(firstTree.width,
firstTree.height,
transform); transform);
ref_ptr<Group> group; ref_ptr<Group> group;
osg::StateSet* stateset = 0; osg::StateSet* stateset = 0;
StateSetMap::iterator iter = treeTextureMap.find(firstTree.texture); StateSetMap::iterator iter = treeTextureMap.find(forest.texture);
if (iter == treeTextureMap.end()) { if (iter == treeTextureMap.end()) {
osg::Texture2D *tex = new osg::Texture2D; osg::Texture2D *tex = new osg::Texture2D;
tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP ); tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP ); tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
tex->setImage(osgDB::readImageFile(firstTree.texture)); tex->setImage(osgDB::readImageFile(forest.texture));
static ref_ptr<AlphaFunc> alphaFunc; static ref_ptr<AlphaFunc> alphaFunc;
static ref_ptr<Program> program; static ref_ptr<Program> program;
@@ -244,6 +252,8 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
baseTextureSampler = new osg::Uniform("baseTexture", 0); baseTextureSampler = new osg::Uniform("baseTexture", 0);
Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource); Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource);
program->addShader(vertex_shader); program->addShader(vertex_shader);
program->addBindAttribLocation("textureIndex", 1);
Shader* fragment_shader = new Shader(Shader::FRAGMENT, Shader* fragment_shader = new Shader(Shader::FRAGMENT,
fragmentShaderSource); fragmentShaderSource);
program->addShader(fragment_shader); program->addShader(fragment_shader);
@@ -260,9 +270,8 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
stateset->addUniform(baseTextureSampler.get()); stateset->addUniform(baseTextureSampler.get());
stateset->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON); stateset->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON);
stateset->setAttribute(material.get()); stateset->setAttribute(material.get());
// XXX This should really come from a material definition
// instead of being hard-coded. treeTextureMap.insert(StateSetMap::value_type(forest.texture,
treeTextureMap.insert(StateSetMap::value_type(firstTree.texture,
stateset)); stateset));
} else { } else {
stateset = iter->second.get(); stateset = iter->second.get();
@@ -272,8 +281,9 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
ShaderGeometryQuadtree quadtree(GetTreeCoord(Matrix::inverse(transform)), ShaderGeometryQuadtree quadtree(GetTreeCoord(Matrix::inverse(transform)),
AddTreesLeafObject(), AddTreesLeafObject(),
SG_TREE_QUAD_TREE_DEPTH, SG_TREE_QUAD_TREE_DEPTH,
MakeTreesLeaf(firstTree.range, MakeTreesLeaf(forest.range,
shared_geometry)); shared_geometry,
forest.texture_varieties));
quadtree.buildQuadTree(forest._trees.begin(), forest._trees.end()); quadtree.buildQuadTree(forest._trees.begin(), forest._trees.end());
group = quadtree.getRoot(); group = quadtree.getRoot();
} }
+19 -13
View File
@@ -23,33 +23,39 @@
#define TREE_BIN_HXX #define TREE_BIN_HXX
#include <vector> #include <vector>
#include <string>
#include <osg/Geometry> #include <osg/Geometry>
#include <osg/Group> #include <osg/Group>
#include <osg/Matrix> #include <osg/Matrix>
#include <simgear/math/SGVec3.hxx> #include <simgear/math/SGMath.hxx>
namespace simgear namespace simgear
{ {
class TreeBin { class TreeBin {
public: public:
struct Tree { struct Tree {
Tree(const SGVec3f& p, string t, float h, float w, double r) : Tree(const SGVec3f& p, int t, float s) :
position(p), texture(t), height(h), width(w), range(r) position(p), texture_index(t), scale(s)
{ } { }
SGVec3f position; SGVec3f position;
string texture; int texture_index;
float height; float scale;
float width; };
double range;
};
typedef std::vector<Tree> TreeList; typedef std::vector<Tree> TreeList;
int texture_varieties;
double range;
float height;
float width;
std::string texture;
void insert(const Tree& t) void insert(const Tree& t)
{ _trees.push_back(t); } { _trees.push_back(t); }
void insert(const SGVec3f& p, string t, float h, float w, double r) void insert(const SGVec3f& p, int t, float s)
{ insert(Tree(p, t, h, w, r)); } { insert(Tree(p, t, s)); }
unsigned getNumTrees() const unsigned getNumTrees() const
{ return _trees.size(); } { return _trees.size(); }
+42 -31
View File
@@ -133,7 +133,7 @@ struct SGTileGeometryBin {
std::string materialName = obj.get_pt_materials()[grp]; std::string materialName = obj.get_pt_materials()[grp];
SGMaterial* material = matlib->find(materialName); SGMaterial* material = matlib->find(materialName);
SGVec4f color = getMaterialLightColor(material); SGVec4f color = getMaterialLightColor(material);
if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") { if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") {
// Just plain lights. Not something for the runway. // Just plain lights. Not something for the runway.
addPointGeometry(tileLights, obj.get_wgs84_nodes(), color, addPointGeometry(tileLights, obj.get_wgs84_nodes(), color,
@@ -454,11 +454,11 @@ struct SGTileGeometryBin {
void computeRandomForest(SGMaterialLib* matlib) void computeRandomForest(SGMaterialLib* matlib)
{ {
SGMaterialTriangleMap::iterator i; SGMaterialTriangleMap::iterator i;
// generate a repeatable random seed // generate a repeatable random seed
mt seed; mt seed;
mt_init(&seed, unsigned(586)); mt_init(&seed, unsigned(586));
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
SGMaterial *mat = matlib->find(i->first); SGMaterial *mat = matlib->find(i->first);
if (!mat) if (!mat)
@@ -467,24 +467,32 @@ struct SGTileGeometryBin {
float coverage = mat->get_tree_coverage(); float coverage = mat->get_tree_coverage();
if (coverage <= 0) if (coverage <= 0)
continue; continue;
vector<string> textures = mat->get_tree_textures(); // Attributes that don't vary by tree
randomForest.texture = mat->get_tree_texture();
randomForest.range = mat->get_tree_range();
randomForest.width = mat->get_tree_width();
randomForest.height = mat->get_tree_height();
randomForest.texture_varieties = mat->get_tree_varieties();
std::vector<SGVec3f> randomPoints; std::vector<SGVec3f> randomPoints;
i->second.addRandomSurfacePoints(coverage, 0, randomPoints); i->second.addRandomSurfacePoints(coverage, 0, 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) {
int k = (int)(mt_rand(&seed) * textures.size());
if (k == textures.size()) k--; // Apply a random scaling factor and texture index.
randomForest.insert(*j, textures[k], mat->get_tree_height(), mat->get_tree_width(), mat->get_tree_range()); float scale = (mt_rand(&seed) + mt_rand(&seed)) / 2.0f + 0.5f;
int v = (int) (mt_rand(&seed) * mat->get_tree_varieties());
if (v == mat->get_tree_varieties()) v--;
randomForest.insert(*j, v, scale);
} }
} }
} }
void computeRandomObjects(SGMaterialLib* matlib) void computeRandomObjects(SGMaterialLib* matlib)
{ {
SGMaterialTriangleMap::iterator i; SGMaterialTriangleMap::iterator i;
// generate a repeatable random seed // generate a repeatable random seed
mt seed; mt seed;
mt_init(&seed, unsigned(123)); mt_init(&seed, unsigned(123));
@@ -493,23 +501,23 @@ struct SGTileGeometryBin {
SGMaterial *mat = matlib->find(i->first); SGMaterial *mat = matlib->find(i->first);
if (!mat) if (!mat)
continue; continue;
int group_count = mat->get_object_group_count(); int group_count = mat->get_object_group_count();
if (group_count > 0) if (group_count > 0)
{ {
for (int j = 0; j < group_count; j++) for (int j = 0; j < group_count; j++)
{ {
SGMatModelGroup *object_group = mat->get_object_group(j); SGMatModelGroup *object_group = mat->get_object_group(j);
int nObjects = object_group->get_object_count(); int nObjects = object_group->get_object_count();
if (nObjects > 0) if (nObjects > 0)
{ {
// For each of the random models in the group, determine an appropriate // For each of the random models in the group, determine an appropriate
// number of random placements and insert them. // number of random placements and insert them.
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<SGVec3f> randomPoints;
i->second.addRandomPoints(object->get_coverage_m2(), randomPoints); i->second.addRandomPoints(object->get_coverage_m2(), randomPoints);
@@ -559,7 +567,7 @@ typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
GetModelLODCoord> RandomObjectsQuadtree; GetModelLODCoord> RandomObjectsQuadtree;
osg::Node* osg::Node*
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects) SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects, bool use_random_vegetation)
{ {
SGBinObject tile; SGBinObject tile;
if (!tile.read_bin(path)) if (!tile.read_bin(path))
@@ -579,13 +587,13 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
osg::ref_ptr<osg::Group> randomObjects; osg::ref_ptr<osg::Group> randomObjects;
osg::ref_ptr<osg::Group> randomForest; osg::ref_ptr<osg::Group> randomForest;
osg::Group* terrainGroup = new osg::Group; osg::Group* terrainGroup = new osg::Group;
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib); osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
if (node) if (node)
terrainGroup->addChild(node); terrainGroup->addChild(node);
if (use_random_objects) { if (use_random_objects) {
// Simple matrix for used for flipping models that have been oriented // Simple matrix for used for flipping models that have been oriented
// with the center of the tile but upside down. // with the center of the tile but upside down.
static const osg::Matrix flip(1, 0, 0, 0, static const osg::Matrix flip(1, 0, 0, 0,
@@ -618,7 +626,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
// heading rotation if appropriate. // heading rotation if appropriate.
osg::Matrix mPos = osg::Matrix::translate(obj.position.osg()); osg::Matrix mPos = osg::Matrix::translate(obj.position.osg());
osg::MatrixTransform* position; osg::MatrixTransform* position;
if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) { if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) {
// Rotate the object around the z axis. // Rotate the object around the z axis.
double hdg = mt_rand(&seed) * M_PI * 2; double hdg = mt_rand(&seed) * M_PI * 2;
@@ -631,7 +639,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
position = new osg::MatrixTransform(mAtt * mPos); position = new osg::MatrixTransform(mAtt * mPos);
} }
position->addChild(node); position->addChild(node);
models.push_back(ModelLOD(position, obj.lod)); models.push_back(ModelLOD(position, obj.lod));
} }
RandomObjectsQuadtree quadtree((GetModelLODCoord(world2Tile)), RandomObjectsQuadtree quadtree((GetModelLODCoord(world2Tile)),
@@ -640,13 +648,16 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
randomObjects = quadtree.getRoot(); randomObjects = quadtree.getRoot();
randomObjects->setName("random objects"); randomObjects->setName("random objects");
} }
// Now add some random forest. if (use_random_vegetation)
tileGeometryBin.computeRandomForest(matlib); {
// Now add some random forest.
if (tileGeometryBin.randomForest.getNumTrees() > 0) { tileGeometryBin.computeRandomForest(matlib);
randomForest = createForest(tileGeometryBin.randomForest, mAtt);
randomForest->setName("random trees"); if (tileGeometryBin.randomForest.getNumTrees() > 0) {
randomForest = createForest(tileGeometryBin.randomForest, mAtt);
randomForest->setName("random trees");
}
} }
} }
+1 -1
View File
@@ -56,6 +56,6 @@ inline bool SGGenTile( const std::string&, const SGBucket& b,
} }
osg::Node* osg::Node*
SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects); SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects, bool use_random_vegetation);
#endif // _SG_OBJ_HXX #endif // _SG_OBJ_HXX