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

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_width = props->getDoubleValue("tree-width-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
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++)
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++) {

View File

@ -177,11 +177,18 @@ public:
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
@ -309,6 +316,9 @@ private:
// Width of the tree
double tree_width;
// Number of varieties of tree texture
int tree_varieties;
// True if the material is solid, false if it is a fluid
bool solid;
@ -336,8 +346,8 @@ private:
// taxiway-/runway-sign texture elements
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
// The list of forest textures, used when creating trees
vector<string> tree_textures;
// Tree texture, typically a strip of applicable tree textures
string tree_texture;
////////////////////////////////////////////////////////////////////
// Internal constructors and methods.

View File

@ -263,7 +263,4 @@ SGMatModelGroup::get_object (int index) const
return _objects[index];
}
// end of matmodel.cxx

View File

@ -54,15 +54,18 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
SGMaterialLib* matlib = 0;
bool calcLights = false;
bool useRandomObjects = false;
bool useRandomVegetation = false;
const SGReaderWriterBTGOptions* btgOptions
= dynamic_cast<const SGReaderWriterBTGOptions*>(options);
if (btgOptions) {
matlib = btgOptions->getMatlib();
calcLights = btgOptions->getCalcLights();
useRandomObjects = btgOptions->getUseRandomObjects();
useRandomVegetation = btgOptions->getUseRandomVegetation();
}
osg::Node* result = SGLoadBTG(fileName, matlib, calcLights,
useRandomObjects);
useRandomObjects,
useRandomVegetation);
if (result)
return result;
else

View File

@ -24,14 +24,17 @@ public:
SGReaderWriterBTGOptions() {}
SGReaderWriterBTGOptions(const std::string& str):
osgDB::ReaderWriter::Options(str),
_matlib(0), _calcLights(false), _useRandomObjects(false)
_matlib(0), _calcLights(false),
_useRandomObjects(false),
_useRandomVegetation(false)
{}
SGReaderWriterBTGOptions(const SGReaderWriterBTGOptions& options,
const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
osgDB::ReaderWriter::Options(options, copyop),
_matlib(options._matlib), _calcLights(options._calcLights),
_useRandomObjects(options._useRandomObjects)
_useRandomObjects(options._useRandomObjects),
_useRandomVegetation(options._useRandomVegetation)
{
}
SGMaterialLib* getMatlib() const { return _matlib; }
@ -39,15 +42,21 @@ public:
bool getCalcLights() const { return _calcLights; }
void setCalcLights(bool calcLights) { _calcLights = calcLights; }
bool getUseRandomObjects() const { return _useRandomObjects; }
bool getUseRandomVegetation() const { return _useRandomVegetation; }
void setUseRandomObjects(bool useRandomObjects)
{
_useRandomObjects = useRandomObjects;
}
void setUseRandomVegetation(bool useRandomVegetation)
{
_useRandomVegetation = useRandomVegetation;
}
protected:
virtual ~SGReaderWriterBTGOptions() {}
SGMaterialLib* _matlib;
bool _calcLights;
bool _useRandomObjects;
bool _useRandomVegetation;
};
#endif

View File

@ -22,6 +22,7 @@
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
#include <simgear/screen/extensions.hxx>
#include "ShaderGeometry.hxx"
@ -32,10 +33,13 @@ namespace simgear
{
void ShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
{
for(PositionSizeList::const_iterator itr = _trees.begin();
itr != _trees.end();
++itr) {
glColor4fv(itr->ptr());
osg::State& state = *renderInfo.getState();
const Extensions* extensions = getExtensions(state.getContextID(),true);
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);
}
}
@ -44,13 +48,13 @@ BoundingBox ShaderGeometry::computeBound() const
{
BoundingBox geom_box = _geometry->getBound();
BoundingBox bb;
for(PositionSizeList::const_iterator itr = _trees.begin();
for(TreeBin::TreeList::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]));
bb.expandBy(geom_box.corner(0)*itr->scale +
osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
bb.expandBy(geom_box.corner(7)*itr->scale +
osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
}
return bb;
}
@ -64,7 +68,7 @@ bool ShaderGeometry_readLocalData(Object& obj, Input& fr)
if ((fr[0].matchWord("geometry"))) {
++fr;
iteratorAdvanced = true;
Drawable* drawable = fr.readDrawable();
osg::Drawable* drawable = fr.readDrawable();
if (drawable) {
geom._geometry = drawable;
}
@ -78,11 +82,15 @@ bool ShaderGeometry_readLocalData(Object& obj, Input& fr)
iteratorAdvanced = true;
// skip {
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())
&& 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;
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 {
++fr;
}
@ -100,12 +108,12 @@ bool ShaderGeometry_writeLocalData(const Object& obj, Output& fw)
fw.indent() << "instances " << geom._trees.size() << std::endl;
fw.indent() << "{" << std::endl;
fw.moveIn();
for (ShaderGeometry::PositionSizeList::const_iterator iter
for (TreeBin::TreeList::const_iterator iter
= geom._trees.begin();
iter != geom._trees.end();
++iter) {
fw.indent() << iter->x() << " " << iter->y() << " " << iter->z() << " "
<< iter->w() << std::endl;
fw.indent() << iter->position.x() << " " << iter->position.y() << " " << iter->position.z() << " "
<< iter->texture_index << " " << iter->scale << std::endl;
}
fw.moveOut();
fw.indent() << "}" << std::endl;

View File

@ -32,6 +32,8 @@
#include <osg/Vec3>
#include <osg/Vec4>
#include "TreeBin.hxx"
namespace simgear
{
@ -43,6 +45,12 @@ class ShaderGeometry : public osg::Drawable
setUseDisplayList(false);
}
ShaderGeometry(int v) :
varieties(v)
{
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) {}
@ -60,14 +68,15 @@ class ShaderGeometry : public osg::Drawable
_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;
PositionSizeList _trees;
TreeBin::TreeList _trees;
int varieties;
protected:

View File

@ -64,7 +64,7 @@ using namespace osg;
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),
@ -87,14 +87,19 @@ osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate)
v[6].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[1].set(1.0f,0.0f);
t[2].set(1.0f,1.0f);
t[1].set( tx,0.0f);
t[2].set( tx,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[5].set( tx,0.0f);
t[6].set( tx,1.0f);
t[7].set(0.0f,1.0f);
// 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[] =
"varying vec2 texcoord;\n"
"varying float fogFactor;\n"
"attribute float textureIndex;\n"
"\n"
"void main(void)\n"
"{\n"
" texcoord = gl_MultiTexCoord0.st + vec2(textureIndex, 0.0);\n"
" vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n"
" gl_Position = gl_ModelViewProjectionMatrix * 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"
" 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_TexCoord[0] = gl_MultiTexCoord0;\n"
// " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" float fogCoord = abs(ecPosition.z);\n"
" fogFactor = exp( -gl_Fog.density * gl_Fog.density * fogCoord * fogCoord);\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[] =
"uniform sampler2D baseTexture; \n"
"varying vec2 texcoord;\n"
// "varying vec3 N;\n"
// "varying vec3 v;\n"
"varying float fogFactor;\n"
"\n"
"void main(void) \n"
"{ \n"
" vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n"
" vec4 base = texture2D( baseTexture, texcoord);\n"
" vec4 finalColor = base * gl_Color;\n"
" gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n"
@ -164,22 +173,23 @@ namespace
{
struct MakeTreesLeaf
{
MakeTreesLeaf(float range, Geometry* geometry) :
_range(range), _geometry(geometry)
MakeTreesLeaf(float range, Geometry* geometry, int varieties) :
_range(range), _geometry(geometry), _varieties(varieties)
{}
MakeTreesLeaf(const MakeTreesLeaf& rhs) :
_range(rhs._range), _geometry(rhs._geometry) {}
_range(rhs._range), _geometry(rhs._geometry), _varieties(rhs._varieties) {}
LOD* operator() () const
{
LOD* result = new LOD;
Geode* geode = new Geode;
ShaderGeometry* sg = new ShaderGeometry;
ShaderGeometry* sg = new ShaderGeometry(_varieties);
sg->setGeometry(_geometry);
geode->addDrawable(sg);
result->addChild(geode, 0, _range);
return result;
}
float _range;
int _varieties;
Geometry* _geometry;
};
@ -190,7 +200,7 @@ struct AddTreesLeafObject
Geode* geode = static_cast<Geode*>(lod->getChild(0));
ShaderGeometry* sg
= 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)
{
// 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,
osg::Geometry* shared_geometry = createOrthQuads(forest.width,
forest.height,
forest.texture_varieties,
transform);
ref_ptr<Group> group;
osg::StateSet* stateset = 0;
StateSetMap::iterator iter = treeTextureMap.find(firstTree.texture);
StateSetMap::iterator iter = treeTextureMap.find(forest.texture);
if (iter == treeTextureMap.end()) {
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));
tex->setImage(osgDB::readImageFile(forest.texture));
static ref_ptr<AlphaFunc> alphaFunc;
static ref_ptr<Program> program;
@ -244,6 +252,8 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
baseTextureSampler = new osg::Uniform("baseTexture", 0);
Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource);
program->addShader(vertex_shader);
program->addBindAttribLocation("textureIndex", 1);
Shader* fragment_shader = new Shader(Shader::FRAGMENT,
fragmentShaderSource);
program->addShader(fragment_shader);
@ -260,9 +270,8 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
stateset->addUniform(baseTextureSampler.get());
stateset->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON);
stateset->setAttribute(material.get());
// XXX This should really come from a material definition
// instead of being hard-coded.
treeTextureMap.insert(StateSetMap::value_type(firstTree.texture,
treeTextureMap.insert(StateSetMap::value_type(forest.texture,
stateset));
} else {
stateset = iter->second.get();
@ -272,8 +281,9 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
ShaderGeometryQuadtree quadtree(GetTreeCoord(Matrix::inverse(transform)),
AddTreesLeafObject(),
SG_TREE_QUAD_TREE_DEPTH,
MakeTreesLeaf(firstTree.range,
shared_geometry));
MakeTreesLeaf(forest.range,
shared_geometry,
forest.texture_varieties));
quadtree.buildQuadTree(forest._trees.begin(), forest._trees.end());
group = quadtree.getRoot();
}

View File

@ -23,33 +23,39 @@
#define TREE_BIN_HXX
#include <vector>
#include <string>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Matrix>
#include <simgear/math/SGVec3.hxx>
#include <simgear/math/SGMath.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)
Tree(const SGVec3f& p, int t, float s) :
position(p), texture_index(t), scale(s)
{ }
SGVec3f position;
string texture;
int texture_index;
float scale;
};
typedef std::vector<Tree> TreeList;
int texture_varieties;
double range;
float height;
float width;
double range;
};
typedef std::vector<Tree> TreeList;
std::string texture;
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)); }
void insert(const SGVec3f& p, int t, float s)
{ insert(Tree(p, t, s)); }
unsigned getNumTrees() const
{ return _trees.size(); }

View File

@ -468,15 +468,23 @@ struct SGTileGeometryBin {
if (coverage <= 0)
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;
i->second.addRandomSurfacePoints(coverage, 0, randomPoints);
std::vector<SGVec3f>::iterator j;
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
int k = (int)(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());
// Apply a random scaling factor and texture index.
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);
}
}
}
@ -559,7 +567,7 @@ typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
GetModelLODCoord> RandomObjectsQuadtree;
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;
if (!tile.read_bin(path))
@ -641,6 +649,8 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
randomObjects->setName("random objects");
}
if (use_random_vegetation)
{
// Now add some random forest.
tileGeometryBin.computeRandomForest(matlib);
@ -649,6 +659,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
randomForest->setName("random trees");
}
}
}
if (calc_lights) {
// FIXME: ugly, has a side effect

View File

@ -56,6 +56,6 @@ inline bool SGGenTile( const std::string&, const SGBucket& b,
}
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