root/OpenSceneGraph/trunk/examples/osgshaderterrain/osgshaderterrain.cpp @ 4837

Revision 4837, 25.0 kB (checked in by robert, 9 years ago)

Changed the default value of Texture::_resizeNonPowerOfTwoHint to true, to
improve the backwards compatibility of peformance on systems that have OpenGL2.0
drivers but without hardware that can't handle non power of two textures.

  • 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/GL2Extensions>
8#include <osg/Material>
9#include <osg/Math>
10#include <osg/MatrixTransform>
11#include <osg/PolygonOffset>
12#include <osg/Program>
13#include <osg/Projection>
14#include <osg/Shader>
15#include <osg/ShapeDrawable>
16#include <osg/StateSet>
17#include <osg/Switch>
18#include <osg/Texture2D>
19#include <osg/Uniform>
20
21#include <osgDB/ReadFile>
22#include <osgDB/FileUtils>
23
24#include <osgUtil/IntersectVisitor>
25#include <osgUtil/SmoothingVisitor>
26
27#include <osgText/Text>
28
29#include <osgProducer/Viewer>
30
31// for the grid data..
32#include "../osghangglide/terrain_coords.h"
33
34// class to create the forest and manage the movement between various techniques.
35class ForestTechniqueManager : public osg::Referenced
36{
37public:
38
39    ForestTechniqueManager() {}
40
41    class Tree : public osg::Referenced
42    {
43    public:
44
45        Tree():
46            _color(255,255,255,255),
47            _width(1.0f),
48            _height(1.0f),
49            _type(0) {}
50
51        Tree(const osg::Vec3& position, const osg::Vec4ub& color, float width, float height, unsigned int type):
52            _position(position),
53            _color(color),
54            _width(width),
55            _height(height),
56            _type(type) {}
57
58        osg::Vec3       _position;
59        osg::Vec4ub     _color;
60        float           _width;
61        float           _height;
62        unsigned int    _type;
63    };
64   
65    typedef std::vector< osg::ref_ptr<Tree> > TreeList;
66   
67    class Cell : public osg::Referenced
68    {
69    public:
70        typedef std::vector< osg::ref_ptr<Cell> > CellList;
71
72        Cell():_parent(0) {}
73        Cell(osg::BoundingBox& bb):_parent(0), _bb(bb) {}
74       
75        void addCell(Cell* cell) { cell->_parent=this; _cells.push_back(cell); }
76
77        void addTree(Tree* tree) { _trees.push_back(tree); }
78       
79        void addTrees(const TreeList& trees) { _trees.insert(_trees.end(),trees.begin(),trees.end()); }
80       
81        void computeBound();
82       
83        bool contains(const osg::Vec3& position) const { return _bb.contains(position); }
84       
85        bool divide(unsigned int maxNumTreesPerCell=10);
86       
87        bool devide(bool xAxis, bool yAxis, bool zAxis);
88       
89        void bin();
90
91
92        Cell*               _parent;
93        osg::BoundingBox    _bb;
94        CellList            _cells;
95        TreeList            _trees;
96       
97    };
98
99    float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
100    int random(int min,int max) { return min + (int)((float)(max-min)*(float)rand()/(float)RAND_MAX); }
101
102    osg::Geode* createTerrain(const osg::Vec3& origin, const osg::Vec3& size);
103
104    void createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees);
105
106    osg::Geometry* createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h );
107
108    osg::Node* createShaderGraph(Cell* cell,osg::StateSet* stateset);
109
110    osg::Node* createScene(unsigned int numTreesToCreates);
111   
112
113};
114
115// event handler to capture keyboard events and use them to advance the technique used for rendering
116void ForestTechniqueManager::Cell::computeBound()
117{
118    _bb.init();
119    for(CellList::iterator citr=_cells.begin();
120        citr!=_cells.end();
121        ++citr)
122    {
123        (*citr)->computeBound();
124        _bb.expandBy((*citr)->_bb);
125    }
126
127    for(TreeList::iterator titr=_trees.begin();
128        titr!=_trees.end();
129        ++titr)
130    {
131        _bb.expandBy((*titr)->_position);
132    }
133}
134
135bool ForestTechniqueManager::Cell::divide(unsigned int maxNumTreesPerCell)
136{
137
138    if (_trees.size()<=maxNumTreesPerCell) return false;
139
140    computeBound();
141
142    float radius = _bb.radius();
143    float divide_distance = radius*0.7f;
144    if (devide((_bb.xMax()-_bb.xMin())>divide_distance,(_bb.yMax()-_bb.yMin())>divide_distance,(_bb.zMax()-_bb.zMin())>divide_distance))
145    {
146        // recusively divide the new cells till maxNumTreesPerCell is met.
147        for(CellList::iterator citr=_cells.begin();
148            citr!=_cells.end();
149            ++citr)
150        {
151            (*citr)->divide(maxNumTreesPerCell);
152        }
153        return true;
154   }
155   else
156   {
157        return false;
158   }
159}
160
161bool ForestTechniqueManager::Cell::devide(bool xAxis, bool yAxis, bool zAxis)
162{
163    if (!(xAxis || yAxis || zAxis)) return false;
164
165    if (_cells.empty())
166        _cells.push_back(new Cell(_bb));
167
168    if (xAxis)
169    {
170        unsigned int numCellsToDivide=_cells.size();
171        for(unsigned int i=0;i<numCellsToDivide;++i)
172        {
173            Cell* orig_cell = _cells[i].get();
174            Cell* new_cell = new Cell(orig_cell->_bb);
175
176            float xCenter = (orig_cell->_bb.xMin()+orig_cell->_bb.xMax())*0.5f;
177            orig_cell->_bb.xMax() = xCenter;
178            new_cell->_bb.xMin() = xCenter;
179
180            _cells.push_back(new_cell);
181        }
182    }
183
184    if (yAxis)
185    {
186        unsigned int numCellsToDivide=_cells.size();
187        for(unsigned int i=0;i<numCellsToDivide;++i)
188        {
189            Cell* orig_cell = _cells[i].get();
190            Cell* new_cell = new Cell(orig_cell->_bb);
191
192            float yCenter = (orig_cell->_bb.yMin()+orig_cell->_bb.yMax())*0.5f;
193            orig_cell->_bb.yMax() = yCenter;
194            new_cell->_bb.yMin() = yCenter;
195
196            _cells.push_back(new_cell);
197        }
198    }
199
200    if (zAxis)
201    {
202        unsigned int numCellsToDivide=_cells.size();
203        for(unsigned int i=0;i<numCellsToDivide;++i)
204        {
205            Cell* orig_cell = _cells[i].get();
206            Cell* new_cell = new Cell(orig_cell->_bb);
207
208            float zCenter = (orig_cell->_bb.zMin()+orig_cell->_bb.zMax())*0.5f;
209            orig_cell->_bb.zMax() = zCenter;
210            new_cell->_bb.zMin() = zCenter;
211
212            _cells.push_back(new_cell);
213        }
214    }
215
216    bin();
217
218    return true;
219
220}
221
222void ForestTechniqueManager::Cell::bin()
223{   
224    // put trees in apprpriate cells.
225    TreeList treesNotAssigned;
226    for(TreeList::iterator titr=_trees.begin();
227        titr!=_trees.end();
228        ++titr)
229    {
230        Tree* tree = titr->get();
231        bool assigned = false;
232        for(CellList::iterator citr=_cells.begin();
233            citr!=_cells.end() && !assigned;
234            ++citr)
235        {
236            if ((*citr)->contains(tree->_position))
237            {
238                (*citr)->addTree(tree);
239                assigned = true;
240            }
241        }
242        if (!assigned) treesNotAssigned.push_back(tree);
243    }
244
245    // put the unassigned trees back into the original local tree list.
246    _trees.swap(treesNotAssigned);
247
248
249    // prune empty cells.
250    CellList cellsNotEmpty;
251    for(CellList::iterator citr=_cells.begin();
252        citr!=_cells.end();
253        ++citr)
254    {
255        if (!((*citr)->_trees.empty()))
256        {
257            cellsNotEmpty.push_back(*citr);
258        }
259    }
260    _cells.swap(cellsNotEmpty);
261
262
263}
264
265
266void ForestTechniqueManager::createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees)
267{
268
269    float max_TreeHeight = sqrtf(size.length2()/(float)numTreesToCreate);
270    float max_TreeWidth = max_TreeHeight*0.5f;
271   
272    float min_TreeHeight = max_TreeHeight*0.3f;
273    float min_TreeWidth = min_TreeHeight*0.5f;
274
275    trees.reserve(trees.size()+numTreesToCreate);
276
277
278    for(unsigned int i=0;i<numTreesToCreate;++i)
279    {
280        Tree* tree = new Tree;
281        tree->_position.set(random(origin.x(),origin.x()+size.x()),random(origin.y(),origin.y()+size.y()),origin.z());
282        tree->_color.set(random(128,255),random(128,255),random(128,255),255);
283        tree->_width = random(min_TreeWidth,max_TreeWidth);
284        tree->_height = random(min_TreeHeight,max_TreeHeight);
285        tree->_type = 0;
286       
287        if (terrain)
288        {
289            osgUtil::IntersectVisitor iv;
290            osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
291
292            segDown->set(tree->_position,tree->_position+osg::Vec3(0.0f,0.0f,size.z()));
293            iv.addLineSegment(segDown.get());
294           
295            terrain->accept(iv);
296
297            if (iv.hits())
298            {
299                osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
300                if (!hitList.empty())
301                {
302                    osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
303                    osg::Vec3 np = hitList.front().getWorldIntersectNormal();
304                    tree->_position = ip;
305                }
306            }
307        }
308       
309        trees.push_back(tree);
310    }
311}
312
313osg::Geometry* ForestTechniqueManager::createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h)
314{
315    // set up the coords
316    osg::Vec3Array& v = *(new osg::Vec3Array(8));
317    osg::Vec2Array& t = *(new osg::Vec2Array(8));
318   
319    float rotation = random(0.0f,osg::PI/2.0f);
320    float sw = sinf(rotation)*w*0.5f;
321    float cw = cosf(rotation)*w*0.5f;
322
323    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
324    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
325    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
326    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
327
328    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
329    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
330    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
331    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
332
333    t[0].set(0.0f,0.0f);
334    t[1].set(1.0f,0.0f);
335    t[2].set(1.0f,1.0f);
336    t[3].set(0.0f,1.0f);
337
338    t[4].set(0.0f,0.0f);
339    t[5].set(1.0f,0.0f);
340    t[6].set(1.0f,1.0f);
341    t[7].set(0.0f,1.0f);
342
343    osg::Geometry *geom = new osg::Geometry;
344
345    geom->setVertexArray( &v );
346
347    geom->setTexCoordArray( 0, &t );
348
349    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
350
351    return geom;
352}
353
354class ShaderGeometry : public osg::Drawable
355{
356    public:
357        ShaderGeometry() { setUseDisplayList(false); }
358
359        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
360        ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
361            osg::Drawable(ShaderGeometry,copyop) {}
362
363        META_Object(osg,ShaderGeometry)
364
365        typedef std::vector<osg::Vec4> PositionSizeList;
366       
367        virtual void drawImplementation(osg::State& state) const
368        {
369            for(PositionSizeList::const_iterator itr = _trees.begin();
370                itr != _trees.end();
371                ++itr)
372            {
373                glColor4fv(itr->ptr());
374                _geometry->draw(state);
375            }
376        }
377
378        virtual osg::BoundingBox computeBound() const
379        {
380            osg::BoundingBox geom_box = _geometry->getBound();
381            osg::BoundingBox bb;
382            for(PositionSizeList::const_iterator itr = _trees.begin();
383                itr != _trees.end();
384                ++itr)
385            {
386                bb.expandBy(geom_box.corner(0)*(*itr)[3] +
387                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
388                bb.expandBy(geom_box.corner(7)*(*itr)[3] +
389                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
390            }
391            return bb;
392        }
393       
394        void setGeometry(osg::Geometry* geometry)
395        {
396            _geometry = geometry;
397        }
398       
399        void addTree(ForestTechniqueManager::Tree& tree)
400        {
401            _trees.push_back(osg::Vec4(tree._position.x(), tree._position.y(), tree._position.z(), tree._height));
402        }
403       
404        osg::ref_ptr<osg::Geometry> _geometry;
405
406        PositionSizeList _trees;
407
408    protected:
409   
410        virtual ~ShaderGeometry() {}
411       
412};
413
414osg::Geometry* shared_geometry = 0;
415
416osg::Node* ForestTechniqueManager::createShaderGraph(Cell* cell,osg::StateSet* stateset)
417{
418    if (shared_geometry==0)
419    {
420        shared_geometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
421        //shared_geometry->setUseDisplayList(false);
422    }
423
424
425    bool needGroup = !(cell->_cells.empty());
426    bool needTrees = !(cell->_trees.empty());
427   
428    osg::Geode* geode = 0;
429    osg::Group* group = 0;
430   
431    if (needTrees)
432    {
433        geode = new osg::Geode;
434       
435        ShaderGeometry* shader_geometry = new ShaderGeometry;
436        shader_geometry->setGeometry(shared_geometry);
437       
438       
439        for(TreeList::iterator itr=cell->_trees.begin();
440            itr!=cell->_trees.end();
441            ++itr)
442        {
443            Tree& tree = **itr;
444            shader_geometry->addTree(tree);
445
446        }
447
448        geode->setStateSet(stateset);
449        geode->addDrawable(shader_geometry);
450    }
451   
452    if (needGroup)
453    {
454        group = new osg::Group;
455        for(Cell::CellList::iterator itr=cell->_cells.begin();
456            itr!=cell->_cells.end();
457            ++itr)
458        {
459            group->addChild(createShaderGraph(itr->get(),stateset));
460        }
461       
462        if (geode) group->addChild(geode);
463       
464    }
465    if (group) return group;
466    else return geode;
467}
468
469osg::Node* ForestTechniqueManager::createScene(unsigned int /*numTreesToCreates*/)
470{
471    osg::Group* scene = new osg::Group;
472   
473    unsigned int numColumns = 38;
474    unsigned int numRows = 39;
475    unsigned int r;
476    unsigned int c;
477
478    osg::Vec3 origin(0.0f,0.0f,0.0f);
479    osg::Vec3 size(1000.0f,1000.0f,250.0f);
480    osg::Vec3 scaleDown(1.0f/size.x(),1.0f/size.y(),1.0f/size.z());
481
482    // ---------------------------------------
483    // Set up a StateSet to texture the objects
484    // ---------------------------------------
485    osg::StateSet* stateset = new osg::StateSet();
486
487
488    osg::Uniform* originUniform = new osg::Uniform("terrainOrigin",origin);
489    stateset->addUniform(originUniform);
490
491    osg::Uniform* sizeUniform = new osg::Uniform("terrainSize",size);
492    stateset->addUniform(sizeUniform);
493
494    osg::Uniform* scaleDownUniform = new osg::Uniform("terrainScaleDown",scaleDown);
495    stateset->addUniform(scaleDownUniform);
496
497    osg::Uniform* terrainTextureSampler = new osg::Uniform("terrainTexture",0);
498    stateset->addUniform(terrainTextureSampler);
499
500    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",1);
501    stateset->addUniform(baseTextureSampler);
502
503    osg::Uniform* treeTextureSampler = new osg::Uniform("treeTexture",1);
504    stateset->addUniform(treeTextureSampler);
505
506
507    // compute z range of z values of grid data so we can scale it.
508    float min_z = FLT_MAX;
509    float max_z = -FLT_MAX;
510    for(r=0;r<numRows;++r)
511    {
512        for(c=0;c<numColumns;++c)
513        {
514            min_z = osg::minimum(min_z,vertex[r+c*numRows][2]);
515            max_z = osg::maximum(max_z,vertex[r+c*numRows][2]);
516        }
517    }
518       
519    float scale_z = size.z()/(max_z-min_z);
520
521    osg::Image* terrainImage = new osg::Image;
522    terrainImage->allocateImage(numColumns,numRows,1,GL_LUMINANCE, GL_FLOAT);
523    terrainImage->setInternalTextureFormat(GL_LUMINANCE_FLOAT32_ATI);
524    for(r=0;r<numRows;++r)
525    {
526        for(c=0;c<numColumns;++c)
527        {
528            *((float*)(terrainImage->data(c,r))) = (vertex[r+c*numRows][2]-min_z)*scale_z;
529        }
530    }
531   
532    osg::Texture2D* terrainTexture = new osg::Texture2D;
533    terrainTexture->setImage(terrainImage);
534    terrainTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
535    terrainTexture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
536    terrainTexture->setResizeNonPowerOfTwoHint(false);
537    stateset->setTextureAttributeAndModes(0,terrainTexture,osg::StateAttribute::ON);
538
539
540    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
541    if (image)
542    {
543        osg::Texture2D* texture = new osg::Texture2D;
544       
545        texture->setImage(image);
546        stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON);
547    }
548
549    {   
550        std::cout<<"Creating terrain...";
551
552        osg::Geode* geode = new osg::Geode();
553        geode->setStateSet( stateset );
554
555
556        {
557            osg::Program* program = new osg::Program;
558            stateset->setAttribute(program);
559
560#if 1
561            // use inline shaders
562           
563            ///////////////////////////////////////////////////////////////////
564            // vertex shader using just Vec4 coefficients
565            char vertexShaderSource[] =
566               "uniform float osg_FrameTime;\n"
567               "uniform sampler2D terrainTexture;\n"
568               "uniform vec3 terrainOrigin;\n"
569               "uniform vec3 terrainScaleDown;\n"
570               "\n"
571               "varying vec2 texcoord;\n"
572               "\n"
573               "void main(void)\n"
574               "{\n"
575               "    texcoord = gl_Vertex.xy - terrainOrigin.xy;\n"
576               "    texcoord.x *= terrainScaleDown.x;\n"
577               "    texcoord.y *= terrainScaleDown.y;\n"
578               "\n"
579               "    vec4 position;\n"
580               "    position.x = gl_Vertex.x;\n"
581               "    position.y = gl_Vertex.y;\n"
582               "    position.z = texture2D(terrainTexture, texcoord).r;\n"
583               " \n"
584               "    gl_Position     = gl_ModelViewProjectionMatrix * position;\n"
585                "   gl_FrontColor = vec4(1.0,1.0,1.0,1.0);\n"
586               "}\n";
587
588            //////////////////////////////////////////////////////////////////
589            // fragment shader
590            //
591            char fragmentShaderSource[] =
592                "uniform sampler2D baseTexture; \n"
593                "varying vec2 texcoord;\n"
594                "\n"
595                "void main(void) \n"
596                "{\n"
597                "    gl_FragColor = texture2D( baseTexture, texcoord); \n"
598                "}\n";
599
600            program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
601            program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
602           
603#else
604
605            // get shaders from source
606            program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/terrain.vert")));
607            program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/terrain.frag")));
608
609#endif
610
611            // get shaders from source
612        }
613
614
615        {
616            osg::Geometry* geometry = new osg::Geometry;
617
618            osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
619            osg::Vec4ubArray& color = *(new osg::Vec4ubArray(1));
620
621            color[0].set(255,255,255,255);
622
623            float rowCoordDelta = size.y()/(float)(numRows-1);
624            float columnCoordDelta = size.x()/(float)(numColumns-1);
625
626            float rowTexDelta = 1.0f/(float)(numRows-1);
627            float columnTexDelta = 1.0f/(float)(numColumns-1);
628
629            osg::Vec3 pos = origin;
630            osg::Vec2 tex(0.0f,0.0f);
631            int vi=0;
632            for(r=0;r<numRows;++r)
633            {
634                pos.x() = origin.x();
635                tex.x() = 0.0f;
636                for(c=0;c<numColumns;++c)
637                {
638                    v[vi].set(pos.x(),pos.y(),pos.z());
639                    pos.x()+=columnCoordDelta;
640                    tex.x()+=columnTexDelta;
641                    ++vi;
642                }
643                pos.y() += rowCoordDelta;
644                tex.y() += rowTexDelta;
645            }
646
647            geometry->setVertexArray(&v);
648            geometry->setColorArray(&color);
649            geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
650
651            for(r=0;r<numRows-1;++r)
652            {
653                osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
654                geometry->addPrimitiveSet(&drawElements);
655                int ei=0;
656                for(c=0;c<numColumns;++c)
657                {
658                    drawElements[ei++] = (r+1)*numColumns+c;
659                    drawElements[ei++] = (r)*numColumns+c;
660                }
661            }
662           
663            geometry->setInitialBound(osg::BoundingBox(origin, origin+size));
664
665            geode->addDrawable(geometry);
666
667            scene->addChild(geode);
668        }
669    }
670       
671    std::cout<<"done."<<std::endl;
672   
673#if 0
674    std::cout<<"Creating tree locations...";std::cout.flush();
675    TreeList trees;
676    createTreeList(0,origin,size,numTreesToCreates,trees);
677    std::cout<<"done."<<std::endl;
678   
679    std::cout<<"Creating cell subdivision...";
680    osg::ref_ptr<Cell> cell = new Cell;
681    cell->addTrees(trees);
682    cell->divide();
683     std::cout<<"done."<<std::endl;
684   
685   
686    osg::Texture2D *tex = new osg::Texture2D;
687    tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
688    tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
689    tex->setImage(osgDB::readImageFile("Images/tree0.rgba"));
690    tex->setResizeNonPowerOfTwoHint(false);
691
692    osg::StateSet *dstate = new osg::StateSet;
693    {   
694        dstate->setTextureAttributeAndModes(1, tex, osg::StateAttribute::ON );
695
696        dstate->setAttributeAndModes( new osg::BlendFunc, osg::StateAttribute::ON );
697
698        osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
699        alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
700        dstate->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );
701
702        dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
703
704        dstate->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
705    }
706   
707
708    {
709        osg::StateSet* stateset = new osg::StateSet;
710
711        stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
712        stateset->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
713
714        {
715            osg::Program* program = new osg::Program;
716            stateset->setAttribute(program);
717
718            // get shaders from source
719            program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/forest2.vert")));
720            program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/forest2.frag")));
721        }
722
723        std::cout<<"Creating billboard based forest...";
724        scene->addChild(createShaderGraph(cell.get(),stateset));
725
726    }
727#endif
728
729    return scene;
730}
731
732int main( int argc, char **argv )
733{
734
735    // use an ArgumentParser object to manage the program arguments.
736    osg::ArgumentParser arguments(&argc,argv);
737
738    // set up the usage document, in case we need to print out how to use this program.
739    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates the osg::Shape classes.");
740    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
741    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
742    arguments.getApplicationUsage()->addCommandLineOption("--trees <number>","Set the number of trees to create");
743   
744    // construct the viewer.
745    osgProducer::Viewer viewer(arguments);
746
747    float numTreesToCreates = 10000;
748    arguments.read("--trees",numTreesToCreates);
749
750    // set up the value with sensible default event handlers.
751    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
752   
753    osg::ref_ptr<ForestTechniqueManager> ttm = new ForestTechniqueManager;
754   
755    // get details on keyboard and mouse bindings used by the viewer.
756    viewer.getUsage(*arguments.getApplicationUsage());
757
758    // if user request help write it out to cout.
759    if (arguments.read("-h") || arguments.read("--help"))
760    {
761        arguments.getApplicationUsage()->write(std::cout);
762        return 1;
763    }
764
765    // any option left unread are converted into errors to write out later.
766    arguments.reportRemainingOptionsAsUnrecognized();
767
768    // report any errors if they have occured when parsing the program aguments.
769    if (arguments.errors())
770    {
771        arguments.writeErrorMessages(std::cout);
772        return 1;
773    }
774   
775    osg::Node* node = ttm->createScene((unsigned int)numTreesToCreates);
776
777    // add model to viewer.
778    viewer.setSceneData( node );
779
780    // create the windows and run the threads.
781    viewer.realize();
782
783    // not all hardware can support vertex texturing, so check first.
784    for(unsigned int contextID = 0;
785        contextID<viewer.getDisplaySettings()->getMaxNumberOfGraphicsContexts();
786        ++contextID)
787    {
788        osg::GL2Extensions* gl2ext = osg::GL2Extensions::Get(contextID,false);
789        if( gl2ext )
790        {
791            if( !gl2ext->isGlslSupported() )
792            {
793                std::cout<<"ERROR: GLSL not supported by OpenGL driver."<<std::endl;
794                return 1;
795            }
796
797            GLint numVertexTexUnits = 0;
798            glGetIntegerv( GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &numVertexTexUnits );
799            if( numVertexTexUnits <= 0 )
800            {
801                std::cout<<"ERROR: vertex texturing not supported by OpenGL driver."<<std::endl;
802                return 1;
803            }
804        }
805    }
806
807    while( !viewer.done() )
808    {
809        // wait for all cull and draw threads to complete.
810        viewer.sync();
811
812        // update the scene by traversing it with the the update visitor which will
813        // call all node update callbacks and animations.
814        viewer.update();
815         
816        // fire off the cull and draw traversals of the scene.
817        viewer.frame();
818       
819    }
820   
821    // wait for all cull and draw threads to complete before exit.
822    viewer.sync();
823
824    return 0;
825}
Note: See TracBrowser for help on using the browser.