root/OpenSceneGraph/trunk/examples/osgforest/osgforest.cpp @ 4350

Revision 4350, 33.8 kB (checked in by robert, 10 years ago)

Added experimental OpenGL shader path for positioning of trees (doens't work yet though..)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/AlphaFunc>
2#include <osg/Billboard>
3#include <osg/BlendFunc>
4#include <osg/Depth>
5#include <osg/Geode>
6#include <osg/Geometry>
7#include <osg/Material>
8#include <osg/Math>
9#include <osg/MatrixTransform>
10#include <osg/PolygonOffset>
11#include <osg/Projection>
12#include <osg/ShapeDrawable>
13#include <osg/StateSet>
14#include <osg/Switch>
15#include <osg/Texture2D>
16
17#include <osgDB/ReadFile>
18
19#include <osgUtil/IntersectVisitor>
20#include <osgUtil/SmoothingVisitor>
21
22#include <osgText/Text>
23
24#include <osgProducer/Viewer>
25
26// for the grid data..
27#include "../osghangglide/terrain_coords.h"
28
29// class to create the forest and manage the movement between various techniques.
30class ForestTechniqueManager : public osg::Referenced
31{
32public:
33
34    ForestTechniqueManager() {}
35
36    class Tree : public osg::Referenced
37    {
38    public:
39
40        Tree():
41            _color(255,255,255,255),
42            _width(1.0f),
43            _height(1.0f),
44            _type(0) {}
45
46        Tree(const osg::Vec3& position, const osg::UByte4& color, float width, float height, unsigned int type):
47            _position(position),
48            _color(color),
49            _width(width),
50            _height(height),
51            _type(type) {}
52
53        osg::Vec3       _position;
54        osg::UByte4     _color;
55        float           _width;
56        float           _height;
57        unsigned int    _type;
58    };
59   
60    typedef std::vector< osg::ref_ptr<Tree> > TreeList;
61   
62    class Cell : public osg::Referenced
63    {
64    public:
65        typedef std::vector< osg::ref_ptr<Cell> > CellList;
66
67        Cell():_parent(0) {}
68        Cell(osg::BoundingBox& bb):_parent(0), _bb(bb) {}
69       
70        void addCell(Cell* cell) { cell->_parent=this; _cells.push_back(cell); }
71
72        void addTree(Tree* tree) { _trees.push_back(tree); }
73       
74        void addTrees(const TreeList& trees) { _trees.insert(_trees.end(),trees.begin(),trees.end()); }
75       
76        void computeBound();
77       
78        bool contains(const osg::Vec3& position) const { return _bb.contains(position); }
79       
80        bool divide(unsigned int maxNumTreesPerCell=10);
81       
82        bool devide(bool xAxis, bool yAxis, bool zAxis);
83       
84        void bin();
85
86
87        Cell*               _parent;
88        osg::BoundingBox    _bb;
89        CellList            _cells;
90        TreeList            _trees;
91       
92    };
93
94    float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
95    int random(int min,int max) { return min + (int)((float)(max-min)*(float)rand()/(float)RAND_MAX); }
96
97    osg::Geode* createTerrain(const osg::Vec3& origin, const osg::Vec3& size);
98
99    void createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees);
100
101    osg::Geometry* createSprite( float w, float h, osg::UByte4 color );
102
103    osg::Geometry* createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::UByte4 color );
104    osg::Geometry* createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h );
105
106    osg::Node* createBillboardGraph(Cell* cell,osg::StateSet* stateset);
107
108    osg::Node* createXGraph(Cell* cell,osg::StateSet* stateset);
109
110    osg::Node* createTransformGraph(Cell* cell,osg::StateSet* stateset);
111
112    osg::Node* createShaderGraph(Cell* cell,osg::StateSet* stateset);
113   
114    osg::Node* createHUDWithText(const std::string& text);
115
116    osg::Node* createScene(unsigned int numTreesToCreates);
117   
118    void advanceToNextTechnique(int delta=1)
119    {
120        if (_techniqueSwitch.valid())
121        {
122            _currentTechnique += delta;
123            if (_currentTechnique<0)
124                _currentTechnique = _techniqueSwitch->getNumChildren()-1;
125            if (_currentTechnique>=(int)_techniqueSwitch->getNumChildren())
126                _currentTechnique = 0;
127            _techniqueSwitch->setSingleChildOn(_currentTechnique);
128        }
129    }
130   
131    osg::ref_ptr<osg::Switch>   _techniqueSwitch;
132    int                         _currentTechnique;
133   
134
135};
136
137// event handler to capture keyboard events and use them to advance the technique used for rendering
138class TechniqueEventHandler : public osgGA::GUIEventHandler
139{
140public:
141
142    TechniqueEventHandler(ForestTechniqueManager* ttm=0) { _ForestTechniqueManager = ttm; }
143   
144    META_Object(osgforestApp,TechniqueEventHandler);
145
146    virtual void accept(osgGA::GUIEventHandlerVisitor& v) { v.visit(*this); }
147
148    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*);
149   
150    virtual void getUsage(osg::ApplicationUsage& usage) const;
151
152protected:
153
154    ~TechniqueEventHandler() {}
155   
156    TechniqueEventHandler(const TechniqueEventHandler&,const osg::CopyOp&) {}
157   
158    osg::ref_ptr<ForestTechniqueManager> _ForestTechniqueManager;
159
160       
161};
162
163bool TechniqueEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*)
164{
165    switch(ea.getEventType())
166    {
167        case(osgGA::GUIEventAdapter::KEYDOWN):
168        {
169            if (ea.getKey()=='n' ||
170                ea.getKey()==osgGA::GUIEventAdapter::KEY_Right ||
171                ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Right)
172            {
173                _ForestTechniqueManager->advanceToNextTechnique(1);
174                return true;
175            }
176            else if (ea.getKey()=='p' ||
177                     ea.getKey()==osgGA::GUIEventAdapter::KEY_Left ||
178                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Left)
179            {
180                _ForestTechniqueManager->advanceToNextTechnique(-1);
181                return true;
182            }
183            return false;
184        }
185
186        default:
187            return false;
188    }
189}
190
191void TechniqueEventHandler::getUsage(osg::ApplicationUsage& usage) const
192{
193    usage.addKeyboardMouseBinding("n or Left Arrow","Advance to next technique");
194    usage.addKeyboardMouseBinding("p or Right Array","Move to previous technique");
195}
196
197
198void ForestTechniqueManager::Cell::computeBound()
199{
200    _bb.init();
201    for(CellList::iterator citr=_cells.begin();
202        citr!=_cells.end();
203        ++citr)
204    {
205        (*citr)->computeBound();
206        _bb.expandBy((*citr)->_bb);
207    }
208
209    for(TreeList::iterator titr=_trees.begin();
210        titr!=_trees.end();
211        ++titr)
212    {
213        _bb.expandBy((*titr)->_position);
214    }
215}
216
217bool ForestTechniqueManager::Cell::divide(unsigned int maxNumTreesPerCell)
218{
219
220    if (_trees.size()<=maxNumTreesPerCell) return false;
221
222    computeBound();
223
224    float radius = _bb.radius();
225    float divide_distance = radius*0.7f;
226    if (devide((_bb.xMax()-_bb.xMin())>divide_distance,(_bb.yMax()-_bb.yMin())>divide_distance,(_bb.zMax()-_bb.zMin())>divide_distance))
227    {
228        // recusively divide the new cells till maxNumTreesPerCell is met.
229        for(CellList::iterator citr=_cells.begin();
230            citr!=_cells.end();
231            ++citr)
232        {
233            (*citr)->divide(maxNumTreesPerCell);
234        }
235        return true;
236   }
237   else
238   {
239        return false;
240   }
241}
242
243bool ForestTechniqueManager::Cell::devide(bool xAxis, bool yAxis, bool zAxis)
244{
245    if (!(xAxis || yAxis || zAxis)) return false;
246
247    if (_cells.empty())
248        _cells.push_back(new Cell(_bb));
249
250    if (xAxis)
251    {
252        unsigned int numCellsToDivide=_cells.size();
253        for(unsigned int i=0;i<numCellsToDivide;++i)
254        {
255            Cell* orig_cell = _cells[i].get();
256            Cell* new_cell = new Cell(orig_cell->_bb);
257
258            float xCenter = (orig_cell->_bb.xMin()+orig_cell->_bb.xMax())*0.5f;
259            orig_cell->_bb.xMax() = xCenter;
260            new_cell->_bb.xMin() = xCenter;
261
262            _cells.push_back(new_cell);
263        }
264    }
265
266    if (yAxis)
267    {
268        unsigned int numCellsToDivide=_cells.size();
269        for(unsigned int i=0;i<numCellsToDivide;++i)
270        {
271            Cell* orig_cell = _cells[i].get();
272            Cell* new_cell = new Cell(orig_cell->_bb);
273
274            float yCenter = (orig_cell->_bb.yMin()+orig_cell->_bb.yMax())*0.5f;
275            orig_cell->_bb.yMax() = yCenter;
276            new_cell->_bb.yMin() = yCenter;
277
278            _cells.push_back(new_cell);
279        }
280    }
281
282    if (zAxis)
283    {
284        unsigned int numCellsToDivide=_cells.size();
285        for(unsigned int i=0;i<numCellsToDivide;++i)
286        {
287            Cell* orig_cell = _cells[i].get();
288            Cell* new_cell = new Cell(orig_cell->_bb);
289
290            float zCenter = (orig_cell->_bb.zMin()+orig_cell->_bb.zMax())*0.5f;
291            orig_cell->_bb.zMax() = zCenter;
292            new_cell->_bb.zMin() = zCenter;
293
294            _cells.push_back(new_cell);
295        }
296    }
297
298    bin();
299
300    return true;
301
302}
303
304void ForestTechniqueManager::Cell::bin()
305{   
306    // put trees in apprpriate cells.
307    TreeList treesNotAssigned;
308    for(TreeList::iterator titr=_trees.begin();
309        titr!=_trees.end();
310        ++titr)
311    {
312        Tree* tree = titr->get();
313        bool assigned = false;
314        for(CellList::iterator citr=_cells.begin();
315            citr!=_cells.end() && !assigned;
316            ++citr)
317        {
318            if ((*citr)->contains(tree->_position))
319            {
320                (*citr)->addTree(tree);
321                assigned = true;
322            }
323        }
324        if (!assigned) treesNotAssigned.push_back(tree);
325    }
326
327    // put the unassigned trees back into the original local tree list.
328    _trees.swap(treesNotAssigned);
329
330
331    // prune empty cells.
332    CellList cellsNotEmpty;
333    for(CellList::iterator citr=_cells.begin();
334        citr!=_cells.end();
335        ++citr)
336    {
337        if (!((*citr)->_trees.empty()))
338        {
339            cellsNotEmpty.push_back(*citr);
340        }
341    }
342    _cells.swap(cellsNotEmpty);
343
344
345}
346
347osg::Geode* ForestTechniqueManager::createTerrain(const osg::Vec3& origin, const osg::Vec3& size)
348{
349    osg::Geode* geode = new osg::Geode();
350
351    // ---------------------------------------
352    // Set up a StateSet to texture the objects
353    // ---------------------------------------
354    osg::StateSet* stateset = new osg::StateSet();
355
356    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
357    if (image)
358    {
359        osg::Texture2D* texture = new osg::Texture2D;
360        texture->setImage(image);
361        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
362    }
363   
364    geode->setStateSet( stateset );
365   
366    unsigned int numColumns = 38;
367    unsigned int numRows = 39;
368    unsigned int r;
369    unsigned int c;
370
371    // compute z range of z values of grid data so we can scale it.
372    float min_z = FLT_MAX;
373    float max_z = -FLT_MAX;
374    for(r=0;r<numRows;++r)
375    {
376        for(c=0;c<numColumns;++c)
377        {
378            min_z = osg::minimum(min_z,vertex[r+c*numRows][2]);
379            max_z = osg::maximum(max_z,vertex[r+c*numRows][2]);
380        }
381    }
382   
383    float scale_z = size.z()/(max_z-min_z);
384
385
386    bool createGrid = false;
387    if (createGrid)
388    {
389
390        osg::HeightField* grid = new osg::HeightField;
391        grid->allocate(numColumns,numRows);
392        grid->setOrigin(origin);
393        grid->setXInterval(size.x()/(float)(numColumns-1));
394        grid->setYInterval(size.y()/(float)(numRows-1));
395
396        for(r=0;r<numRows;++r)
397        {
398            for(c=0;c<numColumns;++c)
399            {
400                grid->setHeight(c,r,(vertex[r+c*numRows][2]-min_z)*scale_z);
401            }
402        }
403       
404        geode->addDrawable(new osg::ShapeDrawable(grid));
405    }
406    else
407    {
408        osg::Geometry* geometry = new osg::Geometry;
409       
410        osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
411        osg::Vec2Array& t = *(new osg::Vec2Array(numColumns*numRows));
412        osg::UByte4Array& color = *(new osg::UByte4Array(1));
413       
414        color[0].set(255,255,255,255);
415
416        float rowCoordDelta = size.y()/(float)(numRows-1);
417        float columnCoordDelta = size.x()/(float)(numColumns-1);
418       
419        float rowTexDelta = 1.0f/(float)(numRows-1);
420        float columnTexDelta = 1.0f/(float)(numColumns-1);
421
422        osg::Vec3 pos = origin;
423        osg::Vec2 tex(0.0f,0.0f);
424        int vi=0;
425        for(r=0;r<numRows;++r)
426        {
427            pos.x() = origin.x();
428            tex.x() = 0.0f;
429            for(c=0;c<numColumns;++c)
430            {
431                v[vi].set(pos.x(),pos.y(),pos.z()+(vertex[r+c*numRows][2]-min_z)*scale_z);
432                t[vi].set(tex.x(),tex.y());
433                pos.x()+=columnCoordDelta;
434                tex.x()+=columnTexDelta;
435                ++vi;
436            }
437            pos.y() += rowCoordDelta;
438            tex.y() += rowTexDelta;
439        }
440       
441        geometry->setVertexArray(&v);
442        geometry->setColorArray(&color);
443        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
444        geometry->setTexCoordArray(0,&t);
445       
446        for(r=0;r<numRows-1;++r)
447        {
448            osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
449            geometry->addPrimitiveSet(&drawElements);
450            int ei=0;
451            for(c=0;c<numColumns;++c)
452            {
453                drawElements[ei++] = (r+1)*numColumns+c;
454                drawElements[ei++] = (r)*numColumns+c;
455            }
456        }
457       
458        geode->addDrawable(geometry);
459       
460        osgUtil::SmoothingVisitor sv;
461        sv.smooth(*geometry);
462    }
463   
464    return geode;
465}
466
467void ForestTechniqueManager::createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees)
468{
469
470    float max_TreeHeight = sqrtf(size.length2()/(float)numTreesToCreate);
471    float max_TreeWidth = max_TreeHeight*0.5f;
472   
473    float min_TreeHeight = max_TreeHeight*0.3f;
474    float min_TreeWidth = min_TreeHeight*0.5f;
475
476    trees.reserve(trees.size()+numTreesToCreate);
477
478
479    for(unsigned int i=0;i<numTreesToCreate;++i)
480    {
481        Tree* tree = new Tree;
482        tree->_position.set(random(origin.x(),origin.x()+size.x()),random(origin.y(),origin.y()+size.y()),origin.z());
483        tree->_color.set(random(128,255),random(128,255),random(128,255),255);
484        tree->_width = random(min_TreeWidth,max_TreeWidth);
485        tree->_height = random(min_TreeHeight,max_TreeHeight);
486        tree->_type = 0;
487       
488        if (terrain)
489        {
490            osgUtil::IntersectVisitor iv;
491            osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
492
493            segDown->set(tree->_position,tree->_position+osg::Vec3(0.0f,0.0f,size.z()));
494            iv.addLineSegment(segDown.get());
495           
496            terrain->accept(iv);
497
498            if (iv.hits())
499            {
500                osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
501                if (!hitList.empty())
502                {
503                    osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
504                    osg::Vec3 np = hitList.front().getWorldIntersectNormal();
505                    tree->_position = ip;
506                }
507            }
508        }
509       
510        trees.push_back(tree);
511    }
512}
513
514osg::Geometry* ForestTechniqueManager::createSprite( float w, float h, osg::UByte4 color )
515{
516    // set up the coords
517    osg::Vec3Array& v = *(new osg::Vec3Array(4));
518    osg::Vec2Array& t = *(new osg::Vec2Array(4));
519    osg::UByte4Array& c = *(new osg::UByte4Array(1));
520
521    v[0].set(-w*0.5f,0.0f,0.0f);
522    v[1].set( w*0.5f,0.0f,0.0f);
523    v[2].set( w*0.5f,0.0f,h);
524    v[3].set(-w*0.5f,0.0f,h);
525
526    c[0] = color;
527
528    t[0].set(0.0f,0.0f);
529    t[1].set(1.0f,0.0f);
530    t[2].set(1.0f,1.0f);
531    t[3].set(0.0f,1.0f);
532
533    osg::Geometry *geom = new osg::Geometry;
534
535    geom->setVertexArray( &v );
536
537    geom->setTexCoordArray( 0, &t );
538
539    geom->setColorArray( &c );
540    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
541
542    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4) );
543
544    return geom;
545}
546
547osg::Geometry* ForestTechniqueManager::createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::UByte4 color )
548{
549    // set up the coords
550    osg::Vec3Array& v = *(new osg::Vec3Array(8));
551    osg::Vec2Array& t = *(new osg::Vec2Array(8));
552    osg::UByte4Array& c = *(new osg::UByte4Array(1));
553   
554    float rotation = random(0.0f,osg::PI/2.0f);
555    float sw = sinf(rotation)*w*0.5f;
556    float cw = cosf(rotation)*w*0.5f;
557
558    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
559    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
560    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
561    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
562
563    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
564    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
565    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
566    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
567
568    c[0] = color;
569
570    t[0].set(0.0f,0.0f);
571    t[1].set(1.0f,0.0f);
572    t[2].set(1.0f,1.0f);
573    t[3].set(0.0f,1.0f);
574
575    t[4].set(0.0f,0.0f);
576    t[5].set(1.0f,0.0f);
577    t[6].set(1.0f,1.0f);
578    t[7].set(0.0f,1.0f);
579
580    osg::Geometry *geom = new osg::Geometry;
581
582    geom->setVertexArray( &v );
583
584    geom->setTexCoordArray( 0, &t );
585
586    geom->setColorArray( &c );
587    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
588
589    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
590
591    return geom;
592}
593
594osg::Node* ForestTechniqueManager::createBillboardGraph(Cell* cell,osg::StateSet* stateset)
595{
596    bool needGroup = !(cell->_cells.empty());
597    bool needBillboard = !(cell->_trees.empty());
598   
599    osg::Billboard* billboard = 0;
600    osg::Group* group = 0;
601   
602    if (needBillboard)
603    {
604        billboard = new osg::Billboard;
605        billboard->setStateSet(stateset);
606        for(TreeList::iterator itr=cell->_trees.begin();
607            itr!=cell->_trees.end();
608            ++itr)
609        {
610            Tree& tree = **itr;
611            billboard->addDrawable(createSprite(tree._width,tree._height,tree._color),tree._position);   
612        }
613    }
614   
615    if (needGroup)
616    {
617        group = new osg::Group;
618        for(Cell::CellList::iterator itr=cell->_cells.begin();
619            itr!=cell->_cells.end();
620            ++itr)
621        {
622            group->addChild(createBillboardGraph(itr->get(),stateset));
623        }
624       
625        if (billboard) group->addChild(billboard);
626       
627    }
628    if (group) return group;
629    else return billboard;
630}
631
632osg::Node* ForestTechniqueManager::createXGraph(Cell* cell,osg::StateSet* stateset)
633{
634    bool needGroup = !(cell->_cells.empty());
635    bool needTrees = !(cell->_trees.empty());
636   
637    osg::Geode* geode = 0;
638    osg::Group* group = 0;
639   
640    if (needTrees)
641    {
642        geode = new osg::Geode;
643        geode->setStateSet(stateset);
644       
645        for(TreeList::iterator itr=cell->_trees.begin();
646            itr!=cell->_trees.end();
647            ++itr)
648        {
649            Tree& tree = **itr;
650            geode->addDrawable(createOrthogonalQuads(tree._position,tree._width,tree._height,tree._color));
651        }
652    }
653   
654    if (needGroup)
655    {
656        group = new osg::Group;
657        for(Cell::CellList::iterator itr=cell->_cells.begin();
658            itr!=cell->_cells.end();
659            ++itr)
660        {
661            group->addChild(createXGraph(itr->get(),stateset));
662        }
663       
664        if (geode) group->addChild(geode);
665       
666    }
667    if (group) return group;
668    else return geode;
669}
670
671osg::Node* ForestTechniqueManager::createTransformGraph(Cell* cell,osg::StateSet* stateset)
672{
673    bool needGroup = !(cell->_cells.empty());
674    bool needTrees = !(cell->_trees.empty());
675   
676    osg::Group* transform_group = 0;
677    osg::Group* group = 0;
678   
679    if (needTrees)
680    {
681        transform_group = new osg::Group;
682       
683        osg::Geometry* geometry = createOrthogonalQuads(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f,osg::UByte4(255,255,255,255));
684       
685        for(TreeList::iterator itr=cell->_trees.begin();
686            itr!=cell->_trees.end();
687            ++itr)
688        {
689            Tree& tree = **itr;
690            osg::MatrixTransform* transform = new osg::MatrixTransform;
691            transform->setMatrix(osg::Matrix::scale(tree._width,tree._width,tree._height)*osg::Matrix::translate(tree._position));
692   
693            osg::Geode* geode = new osg::Geode;
694            geode->setStateSet(stateset);
695            geode->addDrawable(geometry);
696            transform->addChild(geode);
697            transform_group->addChild(transform);
698        }
699    }
700   
701    if (needGroup)
702    {
703        group = new osg::Group;
704        for(Cell::CellList::iterator itr=cell->_cells.begin();
705            itr!=cell->_cells.end();
706            ++itr)
707        {
708            group->addChild(createTransformGraph(itr->get(),stateset));
709        }
710       
711        if (transform_group) group->addChild(transform_group);
712       
713    }
714    if (group) return group;
715    else return transform_group;
716}
717
718osg::Geometry* ForestTechniqueManager::createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h)
719{
720    // set up the coords
721    osg::Vec3Array& v = *(new osg::Vec3Array(8));
722    osg::Vec2Array& t = *(new osg::Vec2Array(8));
723   
724    float rotation = random(0.0f,osg::PI/2.0f);
725    float sw = sinf(rotation)*w*0.5f;
726    float cw = cosf(rotation)*w*0.5f;
727
728    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
729    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
730    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
731    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
732
733    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
734    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
735    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
736    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
737
738    t[0].set(0.0f,0.0f);
739    t[1].set(1.0f,0.0f);
740    t[2].set(1.0f,1.0f);
741    t[3].set(0.0f,1.0f);
742
743    t[4].set(0.0f,0.0f);
744    t[5].set(1.0f,0.0f);
745    t[6].set(1.0f,1.0f);
746    t[7].set(0.0f,1.0f);
747
748    osg::Geometry *geom = new osg::Geometry;
749
750    geom->setVertexArray( &v );
751
752    geom->setTexCoordArray( 0, &t );
753
754    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
755
756    return geom;
757}
758
759class ShaderGeometry : public osg::Drawable
760{
761    public:
762        ShaderGeometry() { setUseDisplayList(false); }
763
764        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
765        ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
766            osg::Drawable(ShaderGeometry,copyop) {}
767
768        META_Object(osg,ShaderGeometry)
769
770        typedef std::vector<osg::Vec4> PositionSizeList;
771       
772        virtual void drawImplementation(osg::State& state) const
773        {
774            for(PositionSizeList::const_iterator itr = _trees.begin();
775                itr != _trees.end();
776                ++itr)
777            {
778#if 0
779                glColor4fv(itr->ptr());
780                _geometry->drawImplementation(state);
781#else
782                glPushMatrix();
783                glTranslatef((*itr)[0], (*itr)[1], (*itr)[2]);
784                glScalef( (*itr)[3],(*itr)[3],(*itr)[3] );
785                _geometry->drawImplementation(state);
786                glPopMatrix();
787#endif
788            }
789        }
790
791        virtual osg::BoundingBox computeBound() const
792        {
793            osg::BoundingBox geom_box = _geometry->getBound();
794            osg::BoundingBox bb;
795            for(PositionSizeList::const_iterator itr = _trees.begin();
796                itr != _trees.end();
797                ++itr)
798            {
799                bb.expandBy(geom_box.corner(0)*(*itr)[3] +
800                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
801                bb.expandBy(geom_box.corner(7)*(*itr)[3] +
802                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
803            }
804            return bb;
805        }
806       
807        void setGeometry(osg::Geometry* geometry)
808        {
809            _geometry = geometry;
810        }
811       
812        void addTree(ForestTechniqueManager::Tree& tree)
813        {
814            _trees.push_back(osg::Vec4(tree._position.x(), tree._position.y(), tree._position.z(), tree._height));
815        }
816       
817        osg::ref_ptr<osg::Geometry> _geometry;
818
819        PositionSizeList _trees;
820
821    protected:
822   
823        virtual ~ShaderGeometry() {}
824       
825};
826
827osg::Geometry* shared_geometry = 0;
828
829osg::Node* ForestTechniqueManager::createShaderGraph(Cell* cell,osg::StateSet* stateset)
830{
831    if (shared_geometry==0)
832    {
833        shared_geometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
834        //shared_geometry->setUseDisplayList(false);
835    }
836
837
838    bool needGroup = !(cell->_cells.empty());
839    bool needTrees = !(cell->_trees.empty());
840   
841    osg::Geode* geode = 0;
842    osg::Group* group = 0;
843   
844    if (needTrees)
845    {
846        geode = new osg::Geode;
847       
848        ShaderGeometry* shader_geometry = new ShaderGeometry;
849        shader_geometry->setGeometry(shared_geometry);
850       
851       
852        for(TreeList::iterator itr=cell->_trees.begin();
853            itr!=cell->_trees.end();
854            ++itr)
855        {
856            Tree& tree = **itr;
857            shader_geometry->addTree(tree);
858
859        }
860
861        geode->setStateSet(stateset);
862        geode->addDrawable(shader_geometry);
863    }
864   
865    if (needGroup)
866    {
867        group = new osg::Group;
868        for(Cell::CellList::iterator itr=cell->_cells.begin();
869            itr!=cell->_cells.end();
870            ++itr)
871        {
872            group->addChild(createShaderGraph(itr->get(),stateset));
873        }
874       
875        if (geode) group->addChild(geode);
876       
877    }
878    if (group) return group;
879    else return geode;
880}
881
882osg::Node* ForestTechniqueManager::createHUDWithText(const std::string& str)
883{
884    osg::Geode* geode = new osg::Geode();
885   
886    std::string timesFont("fonts/arial.ttf");
887
888    // turn lighting off for the text and disable depth test to ensure its always ontop.
889    osg::StateSet* stateset = geode->getOrCreateStateSet();
890    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
891
892    // or disable depth test, and make sure that the hud is drawn after everything
893    // else so that it always appears ontop.
894    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
895    stateset->setRenderBinDetails(11,"RenderBin");
896
897    osg::Vec3 position(150.0f,800.0f,0.0f);
898    osg::Vec3 delta(0.0f,-120.0f,0.0f);
899
900    {
901        osgText::Text* text = new  osgText::Text;
902        geode->addDrawable( text );
903
904        text->setFont(timesFont);
905        text->setPosition(position);
906        text->setText(str);
907       
908        position += delta;
909    }   
910
911   
912    // create the hud.
913    osg::MatrixTransform* modelview_abs = new osg::MatrixTransform;
914    modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
915    modelview_abs->setMatrix(osg::Matrix::identity());
916    modelview_abs->addChild(geode);
917
918    osg::Projection* projection = new osg::Projection;
919    projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
920    projection->addChild(modelview_abs);
921
922    return projection;
923}
924
925osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates)
926{
927    osg::Vec3 origin(0.0f,0.0f,0.0f);
928    osg::Vec3 size(1000.0f,1000.0f,200.0f);
929
930    std::cout<<"Creating terrain...";
931    osg::ref_ptr<osg::Node> terrain = createTerrain(origin,size);
932    std::cout<<"done."<<std::endl;
933   
934    std::cout<<"Creating tree locations...";std::cout.flush();
935    TreeList trees;
936    createTreeList(terrain.get(),origin,size,numTreesToCreates,trees);
937    std::cout<<"done."<<std::endl;
938   
939    std::cout<<"Creating cell subdivision...";
940    osg::ref_ptr<Cell> cell = new Cell;
941    cell->addTrees(trees);
942    cell->divide();
943     std::cout<<"done."<<std::endl;
944   
945   
946    osg::Texture2D *tex = new osg::Texture2D;
947    tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
948    tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
949    tex->setImage(osgDB::readImageFile("Images/tree0.rgba"));
950
951    osg::StateSet *dstate = new osg::StateSet;
952    {   
953        dstate->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
954        dstate->setTextureAttribute(0, new osg::TexEnv );
955
956        dstate->setAttributeAndModes( new osg::BlendFunc, osg::StateAttribute::ON );
957
958        osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
959        alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
960        dstate->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );
961
962        dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
963
964        dstate->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
965    }
966   
967
968    _techniqueSwitch = new osg::Switch;
969   
970    {
971        std::cout<<"Creating billboard based forest...";
972        osg::Group* group = new osg::Group;
973        group->addChild(createBillboardGraph(cell.get(),dstate));
974        group->addChild(createHUDWithText("Using osg::Billboard's to create a forest\n\nPress left cursor key to select OpenGL shader based forest\nPress right cursor key to select double quad based forest"));
975        _techniqueSwitch->addChild(group);
976        std::cout<<"done."<<std::endl;
977    }
978   
979    {
980        std::cout<<"Creating billboard based forest...";
981        osg::Group* group = new osg::Group;
982        group->addChild(createXGraph(cell.get(),dstate));
983        group->addChild(createHUDWithText("Using double quads to create a forest\n\nPress left cursor key to select osg::Billboard based forest\nPress right cursor key to select osg::MatrixTransform based forest\n"));
984        _techniqueSwitch->addChild(group);
985        std::cout<<"done."<<std::endl;
986    }
987
988    {
989        std::cout<<"Creating billboard based forest...";
990        osg::Group* group = new osg::Group;
991        group->addChild(createTransformGraph(cell.get(),dstate));
992        group->addChild(createHUDWithText("Using osg::MatrixTransform's to create a forest\n\nPress left cursor key to select double quad based forest\nPress right cursor key to select OpenGL shder based forest"));
993        _techniqueSwitch->addChild(group);
994        std::cout<<"done."<<std::endl;
995    }
996   
997    {
998        osg::Group* group = new osg::Group;
999       
1000
1001        osg::StateSet* stateset = new osg::StateSet;
1002
1003        stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
1004        stateset->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
1005
1006        {
1007            ///////////////////////////////////////////////////////////////////
1008            // vertex shader using just Vec4 coefficients
1009            char vertexShaderSource[] =
1010                "void main(void) \n"
1011                "{ \n"
1012                "\n"
1013                "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
1014                "}\n";
1015
1016            //////////////////////////////////////////////////////////////////
1017            // fragment shader
1018            //
1019            char fragmentShaderSource[] =
1020                "uniform sampler2D baseTexture; \n"
1021                "\n"
1022                "void main(void) \n"
1023                "{ \n"
1024                "    gl_FragColor = texture2D( baseTexture, gl_TexCoord[0].xy); \n"
1025                "}\n";
1026
1027
1028            osg::Program* program = new osg::Program;
1029            stateset->setAttribute(program);
1030
1031            osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
1032            program->addShader(vertex_shader);
1033
1034            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
1035            program->addShader(fragment_shader);
1036
1037            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
1038            stateset->addUniform(baseTextureSampler);
1039        }
1040
1041        std::cout<<"Creating billboard based forest...";
1042        group->addChild(createShaderGraph(cell.get(),stateset));
1043        group->addChild(createHUDWithText("Using OpenGL Shader to create a forest\n\nPress left cursor key to select osg::MatrixTransform based forest\nPress right cursor key to select osg::Billboard based forest"));
1044        _techniqueSwitch->addChild(group);
1045        std::cout<<"done."<<std::endl;
1046    }
1047
1048    _currentTechnique = 0;
1049    _techniqueSwitch->setSingleChildOn(_currentTechnique);
1050   
1051
1052    osg::Group* scene = new osg::Group;
1053   
1054    scene->addChild(terrain.get());
1055    scene->addChild(_techniqueSwitch.get());
1056
1057    return scene;
1058}
1059
1060int main( int argc, char **argv )
1061{
1062
1063    // use an ArgumentParser object to manage the program arguments.
1064    osg::ArgumentParser arguments(&argc,argv);
1065
1066    // set up the usage document, in case we need to print out how to use this program.
1067    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates the osg::Shape classes.");
1068    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
1069    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
1070    arguments.getApplicationUsage()->addCommandLineOption("--trees <number>","Set the number of trees to create");
1071   
1072    // construct the viewer.
1073    osgProducer::Viewer viewer(arguments);
1074
1075    float numTreesToCreates = 10000;
1076    arguments.read("--trees",numTreesToCreates);
1077
1078    // set up the value with sensible default event handlers.
1079    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
1080   
1081    osg::ref_ptr<ForestTechniqueManager> ttm = new ForestTechniqueManager;
1082   
1083    viewer.getEventHandlerList().push_front(new TechniqueEventHandler(ttm.get()));
1084
1085    // get details on keyboard and mouse bindings used by the viewer.
1086    viewer.getUsage(*arguments.getApplicationUsage());
1087
1088    // if user request help write it out to cout.
1089    if (arguments.read("-h") || arguments.read("--help"))
1090    {
1091        arguments.getApplicationUsage()->write(std::cout);
1092        return 1;
1093    }
1094
1095    // any option left unread are converted into errors to write out later.
1096    arguments.reportRemainingOptionsAsUnrecognized();
1097
1098    // report any errors if they have occured when parsing the program aguments.
1099    if (arguments.errors())
1100    {
1101        arguments.writeErrorMessages(std::cout);
1102        return 1;
1103    }
1104   
1105    osg::Node* node = ttm->createScene((unsigned int)numTreesToCreates);
1106
1107    // add model to viewer.
1108    viewer.setSceneData( node );
1109
1110    // create the windows and run the threads.
1111    viewer.realize();
1112
1113    while( !viewer.done() )
1114    {
1115        // wait for all cull and draw threads to complete.
1116        viewer.sync();
1117
1118        // update the scene by traversing it with the the update visitor which will
1119        // call all node update callbacks and animations.
1120        viewer.update();
1121         
1122        // fire off the cull and draw traversals of the scene.
1123        viewer.frame();
1124       
1125    }
1126   
1127    // wait for all cull and draw threads to complete before exit.
1128    viewer.sync();
1129
1130    return 0;
1131}
Note: See TracBrowser for help on using the browser.