Random trees from Stuart Buchanan
Stuart's new file SGTreeBin.hxx has been split into 4 files: TreeBin.[ch]xx and ShaderGeometry.[ch]xx.
This commit is contained in:
@@ -141,6 +141,10 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
wrapv = props->getBoolValue("wrapv", true);
|
||||
mipmap = props->getBoolValue("mipmap", true);
|
||||
light_coverage = props->getDoubleValue("light-coverage", 0.0);
|
||||
tree_coverage = props->getDoubleValue("tree-coverage", 0.0);
|
||||
tree_height = props->getDoubleValue("tree-height-m", 0.0);
|
||||
tree_width = props->getDoubleValue("tree-width-m", 0.0);
|
||||
tree_range = props->getDoubleValue("tree-range-m", 0.0);
|
||||
|
||||
// surface values for use with ground reactions
|
||||
solid = props->getBoolValue("solid", true);
|
||||
@@ -177,6 +181,14 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
for (unsigned int i = 0; i < object_group_nodes.size(); 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
|
||||
vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph");
|
||||
for (unsigned int i = 0; i < glyph_nodes.size(); i++) {
|
||||
|
||||
@@ -142,10 +142,47 @@ public:
|
||||
*
|
||||
* A smaller number means more generated night lighting.
|
||||
*
|
||||
* @return The area (m^2?) covered by each light.
|
||||
* @return The area (m^2) covered by each light.
|
||||
*/
|
||||
inline double get_light_coverage () const { return light_coverage; }
|
||||
|
||||
/**
|
||||
* Get the forest coverage.
|
||||
*
|
||||
* A smaller number means more generated forest canopy.
|
||||
*
|
||||
* @return The area (m^2) covered by each canopy.
|
||||
*/
|
||||
inline double get_tree_coverage () const { return tree_coverage; }
|
||||
|
||||
/**
|
||||
* Get the forest height.
|
||||
*
|
||||
* @return The average height of the trees.
|
||||
*/
|
||||
inline double get_tree_height () const { return tree_height; }
|
||||
|
||||
/**
|
||||
* Get the forest width.
|
||||
*
|
||||
* @return The average width of the trees.
|
||||
*/
|
||||
inline double get_tree_width () const { return tree_width; }
|
||||
|
||||
/**
|
||||
* Get the forest LoD range.
|
||||
*
|
||||
* @return The LoD range for the trees.
|
||||
*/
|
||||
inline double get_tree_range () const { return tree_range; }
|
||||
|
||||
/**
|
||||
* Get the list of textures to use for trees in the forest
|
||||
*
|
||||
* @return the vector of forest textures to use.
|
||||
*/
|
||||
inline vector<string> get_tree_textures () const { return tree_textures; }
|
||||
|
||||
/**
|
||||
* Return if the surface material is solid, if it is not solid, a fluid
|
||||
* can be assumed, that is usually water.
|
||||
@@ -259,6 +296,18 @@ private:
|
||||
|
||||
// coverage of night lighting.
|
||||
double light_coverage;
|
||||
|
||||
// coverage of trees
|
||||
double tree_coverage;
|
||||
|
||||
// Range at which trees become visible
|
||||
double tree_range;
|
||||
|
||||
// Height of the tree
|
||||
double tree_height;
|
||||
|
||||
// Width of the tree
|
||||
double tree_width;
|
||||
|
||||
// True if the material is solid, false if it is a fluid
|
||||
bool solid;
|
||||
@@ -286,7 +335,9 @@ private:
|
||||
|
||||
// taxiway-/runway-sign texture elements
|
||||
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
|
||||
|
||||
|
||||
// The list of forest textures, used when creating trees
|
||||
vector<string> tree_textures;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Internal constructors and methods.
|
||||
|
||||
@@ -142,33 +142,6 @@ SGMatModel::load_models ( SGModelLib *modellib,
|
||||
// the billboarding should be handled
|
||||
// there).
|
||||
|
||||
// Create multiple LoD nodes so instead of all objects
|
||||
// of the same type appearing at once, some appear further
|
||||
// away.
|
||||
//
|
||||
// Very basic hardcoded distribution:
|
||||
// 4 at normal range
|
||||
// 2 at 1.5 times normal range
|
||||
// 1 at 2 time normal range.
|
||||
//
|
||||
// We achieve this by creating the three different LoD
|
||||
// nodes and adding them to the _models list multiple times.
|
||||
|
||||
osg::LOD * lod1 = new osg::LOD;
|
||||
lod1->setName("Model LOD");
|
||||
lod1->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
|
||||
lod1->setRange(0, 0, _range_m);
|
||||
|
||||
osg::LOD * lod15 = new osg::LOD;
|
||||
lod15->setName("Model LOD - 1.5");
|
||||
lod15->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
|
||||
lod15->setRange(0, 0, 1.5 * _range_m);
|
||||
|
||||
osg::LOD * lod2 = new osg::LOD;
|
||||
lod2->setName("Model LOD - 2.0");
|
||||
lod2->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
|
||||
lod2->setRange(0, 0, 2.0 * _range_m);
|
||||
|
||||
if (_heading_type == HEADING_BILLBOARD) {
|
||||
// if the model is a billboard, it is likely :
|
||||
// 1. a branch with only leaves,
|
||||
@@ -180,27 +153,10 @@ SGMatModel::load_models ( SGModelLib *modellib,
|
||||
stateSet->setAttributeAndModes(alphaFunc,
|
||||
osg::StateAttribute::OVERRIDE);
|
||||
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
|
||||
lod1->addChild(entity);
|
||||
lod15->addChild(entity);
|
||||
lod2->addChild(entity);
|
||||
} else {
|
||||
lod1->addChild(entity);
|
||||
lod15->addChild(entity);
|
||||
lod2->addChild(entity);
|
||||
}
|
||||
|
||||
// Vary the distribution of LoDs by adding multiple times.
|
||||
_models.push_back(lod1);
|
||||
_models.push_back(lod1);
|
||||
_models.push_back(lod1);
|
||||
_models.push_back(lod1);
|
||||
|
||||
_models.push_back(lod15);
|
||||
_models.push_back(lod15);
|
||||
|
||||
_models.push_back(lod2);
|
||||
|
||||
}
|
||||
|
||||
_models.push_back(entity);
|
||||
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
|
||||
}
|
||||
@@ -240,6 +196,24 @@ SGMatModel::get_coverage_m2 () const
|
||||
return _coverage_m2;
|
||||
}
|
||||
|
||||
double SGMatModel::get_range_m() const
|
||||
{
|
||||
return _range_m;
|
||||
}
|
||||
|
||||
double SGMatModel::get_randomized_range_m(mt* seed) const
|
||||
{
|
||||
double lrand = mt_rand(seed);
|
||||
|
||||
// Note that the LoD is not completely randomized.
|
||||
// 10% at 2 * range_m
|
||||
// 30% at 1.5 * range_m
|
||||
// 60% at 1 * range_m
|
||||
if (lrand < 0.1) return 2 * _range_m;
|
||||
if (lrand < 0.4) return 1.5 * _range_m;
|
||||
else return _range_m;
|
||||
}
|
||||
|
||||
SGMatModel::HeadingType
|
||||
SGMatModel::get_heading_type () const
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
|
||||
SG_USING_STD(string);
|
||||
|
||||
@@ -112,6 +113,19 @@ public:
|
||||
*/
|
||||
double get_coverage_m2 () const;
|
||||
|
||||
/**
|
||||
* Get the visual range of the object in meters.
|
||||
*
|
||||
* @return The visual range.
|
||||
*/
|
||||
double get_range_m () const;
|
||||
|
||||
/**
|
||||
* Get a randomized visual range
|
||||
*
|
||||
* @return a randomized visual range
|
||||
*/
|
||||
double get_randomized_range_m(mt* seed) const;
|
||||
|
||||
/**
|
||||
* Get the heading type for the object.
|
||||
|
||||
@@ -18,7 +18,8 @@ include_HEADERS = \
|
||||
SGTexturedTriangleBin.hxx \
|
||||
SGTriangleBin.hxx \
|
||||
SGVertexArrayBin.hxx \
|
||||
GroundLightManager.hxx
|
||||
GroundLightManager.hxx \
|
||||
ShaderGeometry.hxx
|
||||
|
||||
libsgtgdb_a_SOURCES = \
|
||||
apt_signs.cxx \
|
||||
@@ -28,6 +29,8 @@ libsgtgdb_a_SOURCES = \
|
||||
SGOceanTile.cxx \
|
||||
SGReaderWriterBTG.cxx \
|
||||
SGVasiDrawable.cxx \
|
||||
GroundLightManager.cxx
|
||||
GroundLightManager.cxx \
|
||||
ShaderGeometry.cxx \
|
||||
TreeBin.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -27,48 +27,22 @@
|
||||
class SGMatModelBin {
|
||||
public:
|
||||
struct MatModel {
|
||||
MatModel(const SGVec3f& p, SGMatModel *m) :
|
||||
position(p), model(m)
|
||||
MatModel(const SGVec3f& p, SGMatModel *m, int l) :
|
||||
position(p), model(m), lod(l)
|
||||
{ }
|
||||
SGVec3f position;
|
||||
SGMatModel *model;
|
||||
int lod;
|
||||
};
|
||||
typedef std::vector<MatModel> MatModelList;
|
||||
|
||||
void insert(const MatModel& model)
|
||||
{
|
||||
float x = model.position.x();
|
||||
float y = model.position.y();
|
||||
float z = model.position.z();
|
||||
|
||||
if (_models.size() == 0)
|
||||
{
|
||||
min_x = x;
|
||||
max_x = x;
|
||||
|
||||
min_y = y;
|
||||
max_y = y;
|
||||
|
||||
min_z = z;
|
||||
max_z = z;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_x = SGMisc<float>::min(min_x, x);
|
||||
max_x = SGMisc<float>::max(max_x, x);
|
||||
|
||||
min_y = SGMisc<float>::min(min_y, y);
|
||||
max_y = SGMisc<float>::max(max_y, y);
|
||||
|
||||
min_z = SGMisc<float>::min(min_z, z);
|
||||
max_z = SGMisc<float>::max(max_z, z);
|
||||
}
|
||||
|
||||
_models.push_back(model);
|
||||
}
|
||||
|
||||
void insert(const SGVec3f& p, SGMatModel *m)
|
||||
{ insert(MatModel(p, m)); }
|
||||
void insert(const SGVec3f& p, SGMatModel *m, int l)
|
||||
{ insert(MatModel(p, m, l)); }
|
||||
|
||||
unsigned getNumModels() const
|
||||
{ return _models.size(); }
|
||||
@@ -77,12 +51,6 @@ public:
|
||||
|
||||
private:
|
||||
MatModelList _models;
|
||||
float min_x;
|
||||
float max_x;
|
||||
float min_y;
|
||||
float max_y;
|
||||
float min_z;
|
||||
float max_z;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
32
simgear/scene/tgdb/ShaderGeometry.cxx
Normal file
32
simgear/scene/tgdb/ShaderGeometry.cxx
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "ShaderGeometry.hxx"
|
||||
|
||||
using namespace osg;
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
void ShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
|
||||
{
|
||||
for(PositionSizeList::const_iterator itr = _trees.begin();
|
||||
itr != _trees.end();
|
||||
++itr) {
|
||||
glColor4fv(itr->ptr());
|
||||
_geometry->draw(renderInfo);
|
||||
}
|
||||
}
|
||||
|
||||
BoundingBox ShaderGeometry::computeBound() const
|
||||
{
|
||||
BoundingBox geom_box = _geometry->getBound();
|
||||
BoundingBox bb;
|
||||
for(PositionSizeList::const_iterator itr = _trees.begin();
|
||||
itr != _trees.end();
|
||||
++itr) {
|
||||
bb.expandBy(geom_box.corner(0)*(*itr)[3] +
|
||||
Vec3((*itr)[0], (*itr)[1], (*itr)[2]));
|
||||
bb.expandBy(geom_box.corner(7)*(*itr)[3] +
|
||||
Vec3((*itr)[0], (*itr)[1], (*itr)[2]));
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
}
|
||||
79
simgear/scene/tgdb/ShaderGeometry.hxx
Normal file
79
simgear/scene/tgdb/ShaderGeometry.hxx
Normal file
@@ -0,0 +1,79 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2008 Stuart Buchanan
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHADER_GEOMETRY_HXX
|
||||
#define SHADER_GEOMETRY_HXX 1
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/BoundingBox>
|
||||
#include <osg/CopyOp>
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/RenderInfo>
|
||||
#include <osg/Vec3>
|
||||
#include <osg/Vec4>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
class ShaderGeometry : public osg::Drawable
|
||||
{
|
||||
public:
|
||||
ShaderGeometry()
|
||||
{
|
||||
setUseDisplayList(false);
|
||||
}
|
||||
|
||||
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
||||
ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
|
||||
osg::Drawable(ShaderGeometry,copyop) {}
|
||||
|
||||
META_Object(osg,ShaderGeometry);
|
||||
|
||||
typedef std::vector<osg::Vec4> PositionSizeList;
|
||||
|
||||
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
|
||||
virtual osg::BoundingBox computeBound() const;
|
||||
|
||||
|
||||
void setGeometry(osg::Geometry* geometry)
|
||||
{
|
||||
_geometry = geometry;
|
||||
}
|
||||
|
||||
void addTree(const osg::Vec3& position, float scale)
|
||||
{
|
||||
_trees.push_back(osg::Vec4(position, scale));
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Geometry> _geometry;
|
||||
|
||||
PositionSizeList _trees;
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~ShaderGeometry() {}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
244
simgear/scene/tgdb/TreeBin.cxx
Normal file
244
simgear/scene/tgdb/TreeBin.cxx
Normal file
@@ -0,0 +1,244 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2008 Stuart Buchanan
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/Billboard>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Material>
|
||||
#include <osg/Math>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/Matrix>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/TexEnv>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/FileUtils>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include "ShaderGeometry.hxx"
|
||||
#include "TreeBin.hxx"
|
||||
|
||||
#define SG_TREE_QUAD_TREE_SIZE 32
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate)
|
||||
{
|
||||
|
||||
//const osg::Vec3& pos = osg::Vec3(0.0f,0.0f,0.0f),
|
||||
// set up the coords
|
||||
osg::Vec3Array& v = *(new osg::Vec3Array(8));
|
||||
osg::Vec2Array& t = *(new osg::Vec2Array(8));
|
||||
|
||||
/*
|
||||
float rotation = 0.0f;
|
||||
float sw = sinf(rotation)*w*0.5f;
|
||||
float cw = cosf(rotation)*w*0.5f;
|
||||
|
||||
v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
|
||||
v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
|
||||
v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
|
||||
v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
|
||||
|
||||
v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
|
||||
v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
|
||||
v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
|
||||
v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
|
||||
*/
|
||||
float cw = w*0.5f;
|
||||
|
||||
v[0].set(0.0f,-cw,0.0f);
|
||||
v[1].set(0.0f, cw,0.0f);
|
||||
v[2].set(0.0f, cw,h);
|
||||
v[3].set(0.0f,-cw,h);
|
||||
|
||||
v[4].set(-cw,0.0f,0.0f);
|
||||
v[5].set( cw,0.0f,0.0f);
|
||||
v[6].set( cw,0.0f,h);
|
||||
v[7].set(-cw,0.0f,h);
|
||||
|
||||
t[0].set(0.0f,0.0f);
|
||||
t[1].set(1.0f,0.0f);
|
||||
t[2].set(1.0f,1.0f);
|
||||
t[3].set(0.0f,1.0f);
|
||||
|
||||
t[4].set(0.0f,0.0f);
|
||||
t[5].set(1.0f,0.0f);
|
||||
t[6].set(1.0f,1.0f);
|
||||
t[7].set(0.0f,1.0f);
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++)
|
||||
{
|
||||
v[i] = v[i] * rotate;
|
||||
}
|
||||
|
||||
osg::Geometry *geom = new osg::Geometry;
|
||||
|
||||
geom->setVertexArray( &v );
|
||||
|
||||
geom->setTexCoordArray( 0, &t );
|
||||
|
||||
geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
|
||||
|
||||
return geom;
|
||||
}
|
||||
|
||||
osg::Group* createForest(const TreeBin& forest, const osg::Matrix& transform)
|
||||
{
|
||||
// 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
|
||||
// we should be able to handle multiple textures etc.
|
||||
TreeBin::Tree firstTree = forest.getTree(0);
|
||||
|
||||
osg::Geometry* shared_geometry = createOrthQuads(firstTree.width,
|
||||
firstTree.height,
|
||||
transform);
|
||||
osg::Group* group = new osg::Group;
|
||||
|
||||
osg::Texture2D *tex = new osg::Texture2D;
|
||||
tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
|
||||
tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
|
||||
tex->setImage(osgDB::readImageFile(firstTree.texture));
|
||||
|
||||
osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
|
||||
alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
|
||||
|
||||
osg::StateSet *dstate = new osg::StateSet;
|
||||
dstate->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
|
||||
dstate->setTextureAttribute(0, new osg::TexEnv );
|
||||
dstate->setAttributeAndModes( new osg::BlendFunc, osg::StateAttribute::ON );
|
||||
dstate->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );
|
||||
dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
|
||||
dstate->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
|
||||
|
||||
osg::StateSet* stateset = new osg::StateSet;
|
||||
stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
|
||||
stateset->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
|
||||
|
||||
osg::Program* program = new osg::Program;
|
||||
stateset->setAttribute(program);
|
||||
osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
|
||||
stateset->addUniform(baseTextureSampler);
|
||||
|
||||
/*
|
||||
* FIXME: Currently, calculating the diffuse term results in a bad
|
||||
* "flickering" and a tendency of the diffuse term be either
|
||||
* 0.0 of 1.0. Hence, it has been commented out in the shader below.
|
||||
* I (Stuart) suspect it may be because the light is so distant that
|
||||
* we're seeing floating point representation issues.
|
||||
*/
|
||||
char vertexShaderSource[] =
|
||||
// "varying vec3 N;\n"
|
||||
// "varying vec3 v;\n"
|
||||
"varying vec2 texcoord;\n"
|
||||
"varying float fogFactor;\n"
|
||||
"\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
// " v = vec3(gl_ModelViewMatrix * gl_Vertex);\n"
|
||||
// " N = normalize(gl_NormalMatrix * gl_Normal);\n"
|
||||
" texcoord = gl_MultiTexCoord0.st;\n"
|
||||
" vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n"
|
||||
" gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
|
||||
" const float LOG2 = 1.442695;\n"
|
||||
" gl_FogFragCoord = gl_Position.z;\n"
|
||||
" fogFactor = exp2( -gl_Fog.density * gl_Fog.density * gl_FogFragCoord * gl_FogFragCoord * LOG2 );\n"
|
||||
" fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
char fragmentShaderSource[] =
|
||||
"uniform sampler2D baseTexture; \n"
|
||||
// "varying vec3 N;\n"
|
||||
// "varying vec3 v;\n"
|
||||
"varying vec2 texcoord;\n"
|
||||
"varying float fogFactor;\n"
|
||||
"\n"
|
||||
"void main(void) \n"
|
||||
"{ \n"
|
||||
" vec4 base = texture2D( baseTexture, texcoord);\n"
|
||||
// " vec3 L = normalize(gl_LightSource[0].position.xyz);\n"
|
||||
// " vec4 vDiffuse = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);\n"
|
||||
// " vDiffuse = sqrt(clamp(vDiffuse, 0.0, 1.0));\n"
|
||||
// " vec4 vAmbient = gl_FrontLightProduct[0].ambient;\n"
|
||||
// " vec4 finalColor = base * (vAmbient + vDiffuse);\n"
|
||||
" vec4 finalColor = base * gl_FrontLightProduct[0].diffuse;\n"
|
||||
" gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n"
|
||||
"}\n";
|
||||
|
||||
osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
|
||||
program->addShader(vertex_shader);
|
||||
|
||||
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
|
||||
program->addShader(fragment_shader);
|
||||
|
||||
// Now, create a quadtree for the forest.
|
||||
osg::ref_ptr<osg::Group> _root;
|
||||
ShaderGeometry* leaves[SG_TREE_QUAD_TREE_SIZE][SG_TREE_QUAD_TREE_SIZE];
|
||||
|
||||
// Determine the extents of the tree, and a list of the required textures for later.
|
||||
osg::BoundingBox extents;
|
||||
for (unsigned int i = 0; i < forest.getNumTrees(); i++)
|
||||
{
|
||||
const osg::Vec3f center = forest.getTree(i).position.osg() * transform;
|
||||
extents.expandBy(center);
|
||||
}
|
||||
|
||||
const osg::Vec2 quadMin(extents.xMin(), extents.yMin());
|
||||
const osg::Vec2 quadMax(extents.xMax(), extents.yMax());
|
||||
|
||||
for (int i = 0; i < SG_TREE_QUAD_TREE_SIZE; ++i) {
|
||||
osg::LOD* interior = new osg::LOD;
|
||||
//osg::Group* interior = new osg::Group;
|
||||
group->addChild(interior);
|
||||
for (int j = 0; j < SG_TREE_QUAD_TREE_SIZE; ++j) {
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
leaves[i][j] = new ShaderGeometry();
|
||||
leaves[i][j]->setGeometry(shared_geometry);
|
||||
geode->setStateSet(stateset);
|
||||
geode->addDrawable(leaves[i][j]);
|
||||
interior->addChild(geode, 0, firstTree.range);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we've got our quadtree, add the trees based on location.
|
||||
|
||||
for (unsigned int i = 0; i < forest.getNumTrees(); i++)
|
||||
{
|
||||
TreeBin::Tree t = forest.getTree(i);
|
||||
osg::Vec3 center = t.position.osg() * transform;
|
||||
|
||||
int x = (int)(SG_TREE_QUAD_TREE_SIZE * (center.x() - quadMin.x()) / (quadMax.x() - quadMin.x()));
|
||||
x = osg::clampTo(x, 0, (SG_TREE_QUAD_TREE_SIZE - 1));
|
||||
int y = (int)(SG_TREE_QUAD_TREE_SIZE * (center.y() - quadMin.y()) / (quadMax.y() - quadMin.y()));
|
||||
y = osg::clampTo(y, 0, (SG_TREE_QUAD_TREE_SIZE -1));
|
||||
|
||||
leaves[y][x]->addTree(t.position.osg(), t.height);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
}
|
||||
66
simgear/scene/tgdb/TreeBin.hxx
Normal file
66
simgear/scene/tgdb/TreeBin.hxx
Normal file
@@ -0,0 +1,66 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2008 Stuart Buchanan
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TREE_BIN_HXX
|
||||
#define TREE_BIN_HXX
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Group>
|
||||
#include <osg/Matrix>
|
||||
|
||||
#include <simgear/math/SGVec3.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
class TreeBin {
|
||||
public:
|
||||
struct Tree {
|
||||
Tree(const SGVec3f& p, string t, float h, float w, double r) :
|
||||
position(p), texture(t), height(h), width(w), range(r)
|
||||
{ }
|
||||
SGVec3f position;
|
||||
string texture;
|
||||
float height;
|
||||
float width;
|
||||
double range;
|
||||
};
|
||||
typedef std::vector<Tree> TreeList;
|
||||
|
||||
void insert(const Tree& t)
|
||||
{ _trees.push_back(t); }
|
||||
void insert(const SGVec3f& p, string t, float h, float w, double r)
|
||||
{ insert(Tree(p, t, h, w, r)); }
|
||||
|
||||
unsigned getNumTrees() const
|
||||
{ return _trees.size(); }
|
||||
const Tree& getTree(unsigned i) const
|
||||
{ return _trees[i]; }
|
||||
|
||||
private:
|
||||
TreeList _trees;
|
||||
};
|
||||
|
||||
osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate);
|
||||
osg::Group* createForest(const TreeBin& forest, const osg::Matrix& transform);
|
||||
}
|
||||
#endif
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "SGTexturedTriangleBin.hxx"
|
||||
#include "SGLightBin.hxx"
|
||||
#include "SGModelBin.hxx"
|
||||
#include "TreeBin.hxx"
|
||||
#include "SGDirectionalLightBin.hxx"
|
||||
#include "GroundLightManager.hxx"
|
||||
|
||||
@@ -73,6 +74,7 @@ struct SGTileGeometryBin {
|
||||
SGMaterialTriangleMap materialTriangleMap;
|
||||
SGLightBin tileLights;
|
||||
SGLightBin randomTileLights;
|
||||
TreeBin randomForest;
|
||||
SGDirectionalLightBin runwayLights;
|
||||
SGDirectionalLightBin taxiLights;
|
||||
SGDirectionalLightListBin vasiLights;
|
||||
@@ -80,7 +82,7 @@ struct SGTileGeometryBin {
|
||||
SGLightListBin odalLights;
|
||||
SGDirectionalLightListBin reilLights;
|
||||
SGMatModelBin randomModels;
|
||||
|
||||
|
||||
static SGVec4f
|
||||
getMaterialLightColor(const SGMaterial* material)
|
||||
{
|
||||
@@ -448,10 +450,45 @@ struct SGTileGeometryBin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void computeRandomForest(SGMaterialLib* matlib)
|
||||
{
|
||||
SGMaterialTriangleMap::iterator i;
|
||||
|
||||
// generate a repeatable random seed
|
||||
mt seed;
|
||||
mt_init(&seed, unsigned(586));
|
||||
|
||||
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
|
||||
SGMaterial *mat = matlib->find(i->first);
|
||||
if (!mat)
|
||||
continue;
|
||||
|
||||
float coverage = mat->get_tree_coverage();
|
||||
if (coverage <= 0)
|
||||
continue;
|
||||
|
||||
vector<string> textures = mat->get_tree_textures();
|
||||
|
||||
std::vector<SGVec3f> randomPoints;
|
||||
i->second.addRandomSurfacePoints(coverage, 0, randomPoints);
|
||||
std::vector<SGVec3f>::iterator j;
|
||||
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
|
||||
int k = mt_rand(&seed) * textures.size();
|
||||
if (k == textures.size()) k--;
|
||||
randomForest.insert(*j, textures[k], mat->get_tree_height(), mat->get_tree_width(), mat->get_tree_range());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void computeRandomObjects(SGMaterialLib* matlib)
|
||||
{
|
||||
SGMaterialTriangleMap::iterator i;
|
||||
|
||||
// generate a repeatable random seed
|
||||
mt seed;
|
||||
mt_init(&seed, unsigned(123));
|
||||
|
||||
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
|
||||
SGMaterial *mat = matlib->find(i->first);
|
||||
if (!mat)
|
||||
@@ -478,7 +515,7 @@ struct SGTileGeometryBin {
|
||||
i->second.addRandomPoints(object->get_coverage_m2(), randomPoints);
|
||||
std::vector<SGVec3f>::iterator l;
|
||||
for (l = randomPoints.begin(); l != randomPoints.end(); ++l) {
|
||||
randomModels.insert(*l, object);
|
||||
randomModels.insert(*l, object, object->get_randomized_range_m(&seed));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -517,13 +554,22 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
|
||||
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
|
||||
osg::ref_ptr<osg::Group> randomObjects;
|
||||
osg::ref_ptr<osg::Group> randomForest;
|
||||
osg::Group* terrainGroup = new osg::Group;
|
||||
|
||||
|
||||
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
|
||||
if (node)
|
||||
terrainGroup->addChild(node);
|
||||
|
||||
if (use_random_objects) {
|
||||
|
||||
// Simple matrix for used for flipping models that have been oriented
|
||||
// with the center of the tile but upside down.
|
||||
static const osg::Matrix flip(1, 0, 0, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, -1, 0,
|
||||
0, 0, 0, 1);
|
||||
|
||||
tileGeometryBin.computeRandomObjects(matlib);
|
||||
|
||||
if (tileGeometryBin.randomModels.getNumModels() > 0) {
|
||||
@@ -536,12 +582,9 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
// based on the centre of the tile, as the small angular differences
|
||||
// between different points on the tile aren't worth worrying about
|
||||
// for random objects. We also need to flip the orientation 180 degrees
|
||||
static const osg::Matrix flip(1, 0, 0, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, -1, 0,
|
||||
0, 0, 0, 1);
|
||||
osg::Matrix mAtt = flip * osg::Matrix::rotate(hlOr.osg());
|
||||
std::vector<osg::ref_ptr<osg::Node> > models;
|
||||
|
||||
LodMap models;
|
||||
|
||||
for (unsigned int i = 0; i < tileGeometryBin.randomModels.getNumModels(); i++) {
|
||||
SGMatModelBin::MatModel obj = tileGeometryBin.randomModels.getMatModel(i);
|
||||
@@ -566,12 +609,21 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
}
|
||||
|
||||
position->addChild(node);
|
||||
models.push_back(position);
|
||||
// Add to the leaf of the quadtree based on object location.
|
||||
models.insert(std::pair<osg::ref_ptr<osg::Node>,int>(position, obj.lod));
|
||||
}
|
||||
|
||||
randomObjects = QuadTreeBuilder::makeQuadTree(models, world2Tile);
|
||||
randomObjects->setName("random objects");
|
||||
}
|
||||
|
||||
// Now add some random forest.
|
||||
tileGeometryBin.computeRandomForest(matlib);
|
||||
|
||||
if (tileGeometryBin.randomForest.getNumTrees() > 0) {
|
||||
osg::Matrix forAtt = flip * world2Tile;
|
||||
randomForest = createForest(tileGeometryBin.randomForest, forAtt);
|
||||
randomForest->setName("random trees");
|
||||
}
|
||||
}
|
||||
|
||||
if (calc_lights) {
|
||||
@@ -606,7 +658,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
lightGroup->addChild(groundLights2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!tileGeometryBin.vasiLights.empty()) {
|
||||
SGVec4f red(1, 0, 0, 1);
|
||||
SGMaterial* mat = matlib->find("RWY_RED_LIGHTS");
|
||||
@@ -689,12 +741,15 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
|
||||
transform->addChild(lightLOD);
|
||||
}
|
||||
|
||||
if (randomObjects.valid()) {
|
||||
if (randomObjects.valid() || randomForest.valid()) {
|
||||
|
||||
// Add a LoD node, so we don't try to display anything when the tile center
|
||||
// is more than 20km away.
|
||||
osg::LOD* objectLOD = new osg::LOD;
|
||||
objectLOD->addChild(randomObjects.get(), 0, 20000);
|
||||
|
||||
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
|
||||
if (randomForest.valid()) objectLOD->addChild(randomForest.get(), 0, 20000);
|
||||
|
||||
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT;
|
||||
objectLOD->setNodeMask(nodeMask);
|
||||
transform->addChild(objectLOD);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <osg/BoundingBox>
|
||||
#include <osg/Math>
|
||||
#include <simgear/scene/util/SGNodeMasks.hxx>
|
||||
|
||||
#include "QuadTreeBuilder.hxx"
|
||||
|
||||
@@ -27,35 +28,36 @@ namespace simgear
|
||||
QuadTreeBuilder::QuadTreeBuilder(const Vec2& min, const Vec2& max) :
|
||||
_root(new osg::Group), _min(min), _max(max)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < QUAD_TREE_LEAVES; ++i) {
|
||||
Group* interior = new osg::Group;
|
||||
_root->addChild(interior);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
Group* leaf = new osg::Group;
|
||||
interior->addChild(leaf);
|
||||
_leaves[i][j] = leaf;
|
||||
for (int j = 0; j < QUAD_TREE_LEAVES; ++j) {
|
||||
LOD* lod = new osg::LOD;
|
||||
interior->addChild(lod);
|
||||
_leaves[i][j] = lod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QuadTreeBuilder::addNode(Node* node, const Matrix& transform)
|
||||
void QuadTreeBuilder::addNode(Node* node, int lod, const Matrix& transform)
|
||||
{
|
||||
Vec3 center = node->getBound().center() * transform;
|
||||
|
||||
int x = (int)(4.0 * (center.x() - _min.x()) / (_max.x() - _min.x()));
|
||||
x = clampTo(x, 0, 3);
|
||||
int y = (int)(4.0 * (center.y() - _min.y()) / (_max.y() - _min.y()));
|
||||
y = clampTo(y, 0, 3);
|
||||
_leaves[y][x]->addChild(node);
|
||||
int x = (int)(QUAD_TREE_LEAVES * (center.x() - _min.x()) / (_max.x() - _min.x()));
|
||||
x = clampTo(x, 0, (QUAD_TREE_LEAVES - 1));
|
||||
int y = (int)(QUAD_TREE_LEAVES * (center.y() - _min.y()) / (_max.y() - _min.y()));
|
||||
y = clampTo(y, 0, (QUAD_TREE_LEAVES -1));
|
||||
|
||||
_leaves[y][x]->addChild(node, 0, lod);
|
||||
}
|
||||
|
||||
osg::Group* QuadTreeBuilder::makeQuadTree(vector<ref_ptr<Node> >& nodes,
|
||||
osg::Group* QuadTreeBuilder::makeQuadTree(LodMap& models,
|
||||
const Matrix& transform)
|
||||
{
|
||||
typedef vector<ref_ptr<Node> > NodeList;
|
||||
BoundingBox extents;
|
||||
for (NodeList::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) {
|
||||
const Vec3 center = (*iter)->getBound().center() * transform;
|
||||
for (LodMap::iterator iter = models.begin(); iter != models.end(); ++iter) {
|
||||
const Vec3 center = (*iter).first->getBound().center() * transform;
|
||||
extents.expandBy(center);
|
||||
}
|
||||
const Vec2 quadMin(extents.xMin(), extents.yMin());
|
||||
@@ -63,10 +65,10 @@ osg::Group* QuadTreeBuilder::makeQuadTree(vector<ref_ptr<Node> >& nodes,
|
||||
ref_ptr<Group> result;
|
||||
{
|
||||
QuadTreeBuilder quadTree(quadMin, quadMax);
|
||||
for (NodeList::iterator iter = nodes.begin();
|
||||
iter != nodes.end();
|
||||
for (LodMap::iterator iter = models.begin();
|
||||
iter != models.end();
|
||||
++iter) {
|
||||
quadTree.addNode(iter->get(), transform);
|
||||
quadTree.addNode(iter->first.get(), iter->second, transform);
|
||||
}
|
||||
result = quadTree.getRoot();
|
||||
}
|
||||
|
||||
@@ -22,23 +22,28 @@
|
||||
#include <osg/Group>
|
||||
#include <osg/Matrix>
|
||||
#include <osg/Vec2>
|
||||
#include <osg/LOD>
|
||||
|
||||
#define QUAD_TREE_LEAVES 4
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
typedef std::map<osg::ref_ptr<osg::Node>,int> LodMap;
|
||||
|
||||
// Create a quad tree based on x, y extents
|
||||
class QuadTreeBuilder {
|
||||
public:
|
||||
QuadTreeBuilder(const osg::Vec2& min, const osg::Vec2& max);
|
||||
~QuadTreeBuilder() {}
|
||||
osg::Group* getRoot() { return _root.get(); }
|
||||
// Add node to the quadtree using its x, y
|
||||
void addNode(osg::Node* node, const osg::Matrix& transform);
|
||||
// Make a quadtree of nodes from a vector of nodes
|
||||
static osg::Group* makeQuadTree(std::vector<osg::ref_ptr<osg::Node> >& nodes,
|
||||
// Add node to the quadtree using its x, y and LoD
|
||||
void addNode(osg::Node* node, int lod, const osg::Matrix& transform);
|
||||
// Make a quadtree of nodes from a map of nodes and LOD values
|
||||
static osg::Group* makeQuadTree(LodMap& nodes,
|
||||
const osg::Matrix& transform);
|
||||
protected:
|
||||
osg::ref_ptr<osg::Group> _root;
|
||||
osg::Group* _leaves[4][4];
|
||||
osg::LOD* _leaves[QUAD_TREE_LEAVES][QUAD_TREE_LEAVES];
|
||||
osg::Vec2 _min;
|
||||
osg::Vec2 _max;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user