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

Revision 2315, 13.3 kB (checked in by robert, 11 years ago)

Added the beginnings of a new osgforest example.

Added support into osg::TriangleFunctor? for specifying whether the vertices
being generates are temporary or not.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Geode>
2#include <osg/ShapeDrawable>
3#include <osg/Material>
4#include <osg/Texture2D>
5#include <osg/Billboard>
6#include <osg/AlphaFunc>
7#include <osg/BlendFunc>
8#include <osg/StateSet>
9#include <osg/Geometry>
10#include <osg/MatrixTransform>
11#include <osg/Switch>
12
13#include <osgProducer/Viewer>
14
15#include <osgDB/ReadFile>
16#include <osgUtil/IntersectVisitor>
17#include <osgUtil/SmoothingVisitor>
18
19#include <osg/Math>
20
21// for the grid data..
22#include "../osghangglide/terrain_coords.h"
23
24class Tree : public osg::Referenced
25{
26public:
27
28    Tree():
29        _color(255,255,255,255),
30        _width(1.0f),
31        _height(1.0f),
32        _type(0) {}
33
34    Tree(const osg::Vec3& position, const osg::UByte4& color, float width, float height, unsigned int type):
35        _position(position),
36        _color(color),
37        _width(width),
38        _height(height),
39        _type(type) {}
40
41    osg::Vec3       _position;
42    osg::UByte4     _color;
43    float           _width;
44    float           _height;
45    unsigned int    _type;
46};
47
48
49osg::Geode* createTerrain(const osg::Vec3& origin, const osg::Vec3& size)
50{
51    osg::Geode* geode = new osg::Geode();
52
53    // ---------------------------------------
54    // Set up a StateSet to texture the objects
55    // ---------------------------------------
56    osg::StateSet* stateset = new osg::StateSet();
57
58    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
59    if (image)
60    {
61        osg::Texture2D* texture = new osg::Texture2D;
62        texture->setImage(image);
63        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
64    }
65   
66    geode->setStateSet( stateset );
67   
68    unsigned int numColumns = 38;
69    unsigned int numRows = 39;
70    unsigned int r;
71    unsigned int c;
72
73    // compute z range of z values of grid data so we can scale it.
74    float min_z = FLT_MAX;
75    float max_z = -FLT_MAX;
76    for(r=0;r<numRows;++r)
77    {
78        for(c=0;c<numColumns;++c)
79        {
80            min_z = osg::minimum(min_z,vertex[r+c*numRows][2]);
81            max_z = osg::maximum(max_z,vertex[r+c*numRows][2]);
82        }
83    }
84   
85    float scale_z = size.z()/(max_z-min_z);
86
87
88    bool createGrid = false;
89    if (createGrid)
90    {
91
92        osg::Grid* grid = new osg::Grid;
93        grid->allocateGrid(numColumns,numRows);
94        grid->setOrigin(origin);
95        grid->setXInterval(size.x()/(float)(numColumns-1));
96        grid->setYInterval(size.y()/(float)(numRows-1));
97
98        for(r=0;r<numRows;++r)
99        {
100            for(c=0;c<numColumns;++c)
101            {
102                grid->setHeight(c,r,(vertex[r+c*numRows][2]-min_z)*scale_z);
103            }
104        }
105       
106        geode->addDrawable(new osg::ShapeDrawable(grid));
107    }
108    else
109    {
110        osg::Geometry* geometry = new osg::Geometry;
111       
112        osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
113        osg::Vec2Array& t = *(new osg::Vec2Array(numColumns*numRows));
114        osg::UByte4Array& color = *(new osg::UByte4Array(1));
115       
116        color[0].set(255,255,255,255);
117
118        float rowCoordDelta = size.y()/(float)(numRows-1);
119        float columnCoordDelta = size.x()/(float)(numColumns-1);
120       
121        float rowTexDelta = 1.0f/(float)(numRows-1);
122        float columnTexDelta = 1.0f/(float)(numColumns-1);
123
124        osg::Vec3 pos = origin;
125        osg::Vec2 tex(0.0f,0.0f);
126        int vi=0;
127        for(r=0;r<numRows;++r)
128        {
129            pos.x() = origin.x();
130            tex.x() = 0.0f;
131            for(c=0;c<numColumns;++c)
132            {
133                v[vi].set(pos.x(),pos.y(),pos.z()+(vertex[r+c*numRows][2]-min_z)*scale_z);
134                t[vi].set(tex.x(),tex.y());
135                pos.x()+=columnCoordDelta;
136                tex.x()+=columnTexDelta;
137                ++vi;
138            }
139            pos.y() += rowCoordDelta;
140            tex.y() += rowTexDelta;
141        }
142       
143        geometry->setVertexArray(&v);
144        geometry->setColorArray(&color);
145        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
146        geometry->setTexCoordArray(0,&t);
147       
148        for(r=0;r<numRows-1;++r)
149        {
150            osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
151            geometry->addPrimitiveSet(&drawElements);
152            int ei=0;
153            for(c=0;c<numColumns;++c)
154            {
155                drawElements[ei++] = (r+1)*numColumns+c;
156                drawElements[ei++] = (r)*numColumns+c;
157            }
158        }
159       
160        geode->addDrawable(geometry);
161       
162        osgUtil::SmoothingVisitor sv;
163        sv.smooth(*geometry);
164    }
165   
166    return geode;
167}
168
169typedef std::vector< osg::ref_ptr<Tree> > TreeList;
170
171float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
172int random(int min,int max) { return min + (int)((float)(max-min)*(float)rand()/(float)RAND_MAX); }
173
174void createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees)
175{
176
177    float max_TreeHeight = sqrtf(size.length2()/(float)numTreesToCreate);
178    float max_TreeWidth = max_TreeHeight*0.5f;
179   
180    float min_TreeHeight = max_TreeHeight*0.3f;
181    float min_TreeWidth = min_TreeHeight*0.5f;
182
183    trees.reserve(trees.size()+numTreesToCreate);
184
185
186    for(unsigned int i=0;i<numTreesToCreate;++i)
187    {
188        Tree* tree = new Tree;
189        tree->_position.set(random(origin.x(),origin.x()+size.x()),random(origin.y(),origin.y()+size.y()),origin.z());
190        tree->_color.set(random(128,255),random(128,255),random(128,255),255);
191        tree->_width = random(min_TreeWidth,max_TreeWidth);
192        tree->_height = random(min_TreeHeight,max_TreeHeight);
193        tree->_type = 0;
194       
195        if (terrain)
196        {
197            osgUtil::IntersectVisitor iv;
198            osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
199
200            segDown->set(tree->_position,tree->_position+osg::Vec3(0.0f,0.0f,size.z()));
201            iv.addLineSegment(segDown.get());
202           
203            terrain->accept(iv);
204
205            if (iv.hits())
206            {
207                osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
208                if (!hitList.empty())
209                {
210                    osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
211                    osg::Vec3 np = hitList.front().getWorldIntersectNormal();
212                    tree->_position = ip;
213                }
214            }
215        }
216       
217        trees.push_back(tree);
218    }
219}
220
221osg::Geometry* createSprite( float w, float h, osg::UByte4 color )
222{
223    // set up the coords
224    osg::Vec3Array& v = *(new osg::Vec3Array(4));
225    osg::Vec2Array& t = *(new osg::Vec2Array(4));
226    osg::UByte4Array& c = *(new osg::UByte4Array(1));
227
228    v[0].set(-w*0.5f,0.0f,0.0f);
229    v[1].set( w*0.5f,0.0f,0.0f);
230    v[2].set( w*0.5f,0.0f,h);
231    v[3].set(-w*0.5f,0.0f,h);
232
233    c[0] = color;
234
235    t[0].set(0.0f,0.0f);
236    t[1].set(1.0f,0.0f);
237    t[2].set(1.0f,1.0f);
238    t[3].set(0.0f,1.0f);
239
240    osg::Geometry *geom = new osg::Geometry;
241
242    geom->setVertexArray( &v );
243
244    geom->setTexCoordArray( 0, &t );
245
246    geom->setColorArray( &c );
247    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
248
249    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4) );
250
251    return geom;
252}
253
254osg::Geometry* createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::UByte4 color )
255{
256    // set up the coords
257    osg::Vec3Array& v = *(new osg::Vec3Array(8));
258    osg::Vec2Array& t = *(new osg::Vec2Array(8));
259    osg::UByte4Array& c = *(new osg::UByte4Array(1));
260   
261    float rotation = random(0.0f,osg::PI/2.0f);
262    float sw = sinf(rotation)*w*0.5f;
263    float cw = cosf(rotation)*w*0.5f;
264
265    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
266    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
267    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
268    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
269
270    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
271    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
272    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
273    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
274
275    c[0] = color;
276
277    t[0].set(0.0f,0.0f);
278    t[1].set(1.0f,0.0f);
279    t[2].set(1.0f,1.0f);
280    t[3].set(0.0f,1.0f);
281
282    t[4].set(0.0f,0.0f);
283    t[5].set(1.0f,0.0f);
284    t[6].set(1.0f,1.0f);
285    t[7].set(0.0f,1.0f);
286
287    osg::Geometry *geom = new osg::Geometry;
288
289    geom->setVertexArray( &v );
290
291    geom->setTexCoordArray( 0, &t );
292
293    geom->setColorArray( &c );
294    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
295
296    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
297
298    return geom;
299}
300
301osg::Node* createScene()
302{
303    osg::Vec3 origin(0.0f,0.0f,0.0f);
304    osg::Vec3 size(1000.0f,1000.0f,200.0f);
305    unsigned int numTreesToCreates = 10000;
306
307    osg::ref_ptr<osg::Node> terrain = createTerrain(origin,size);
308   
309    TreeList trees;
310    createTreeList(terrain.get(),origin,size,numTreesToCreates,trees);
311   
312    osg::Texture2D *tex = new osg::Texture2D;
313    tex->setImage(osgDB::readImageFile("Images/tree0.rgba"));
314
315    osg::StateSet *dstate = new osg::StateSet;
316    {   
317        dstate->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
318        dstate->setTextureAttribute(0, new osg::TexEnv );
319
320        dstate->setAttributeAndModes( new osg::BlendFunc, osg::StateAttribute::ON );
321
322        osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
323        alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
324        dstate->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );
325
326        dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
327
328        dstate->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
329    }
330   
331
332    osg::Switch* switchNode = new osg::Switch;
333   
334    {
335        osg::Billboard* billboard = new osg::Billboard;
336        billboard->setStateSet(dstate);
337
338        for(TreeList::iterator itr=trees.begin();
339            itr!=trees.end();
340            ++itr)
341        {
342            Tree& tree = **itr;
343            billboard->addDrawable(createSprite(tree._width,tree._height,tree._color),tree._position);   
344        }
345   
346        switchNode->addChild(billboard);
347    }
348
349    {
350        osg::Geode* geode = new osg::Geode;
351        geode->setStateSet(dstate);
352       
353        for(TreeList::iterator itr=trees.begin();
354            itr!=trees.end();
355            ++itr)
356        {
357            Tree& tree = **itr;
358            geode->addDrawable(createOrthogonalQuads(tree._position,tree._width,tree._height,tree._color));
359        }
360       
361        switchNode->addChild(geode);
362    }
363
364    {
365
366        osg::Group* transform_group = new osg::Group;
367        //group->setStateSet(dstate);
368       
369        osg::Geometry* geometry = createOrthogonalQuads(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f,osg::UByte4(255,255,255,255));
370       
371        for(TreeList::iterator itr=trees.begin();
372            itr!=trees.end();
373            ++itr)
374        {
375            Tree& tree = **itr;
376            osg::MatrixTransform* transform = new osg::MatrixTransform;
377            transform->setMatrix(osg::Matrix::scale(tree._width,tree._width,tree._height)*osg::Matrix::translate(tree._position));
378   
379            osg::Geode* geode = new osg::Geode;
380            geode->setStateSet(dstate);
381            geode->addDrawable(geometry);
382            transform->addChild(geode);
383            transform_group->addChild(transform);
384        }
385       
386        switchNode->addChild(transform_group);
387    }
388   
389    switchNode->setSingleChildOn(1);
390
391    osg::Group* scene = new osg::Group;
392   
393    scene->addChild(terrain.get());
394    scene->addChild(switchNode);
395
396    return scene;
397}
398
399int main( int argc, char **argv )
400{
401
402    // use an ArgumentParser object to manage the program arguments.
403    osg::ArgumentParser arguments(&argc,argv);
404
405    // set up the usage document, in case we need to print out how to use this program.
406    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates the osg::Shape classes.");
407    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
408    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
409   
410    // construct the viewer.
411    osgProducer::Viewer viewer(arguments);
412
413    // set up the value with sensible default event handlers.
414    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
415
416    // get details on keyboard and mouse bindings used by the viewer.
417    viewer.getUsage(*arguments.getApplicationUsage());
418
419    // if user request help write it out to cout.
420    if (arguments.read("-h") || arguments.read("--help"))
421    {
422        arguments.getApplicationUsage()->write(std::cout);
423        return 1;
424    }
425
426    // any option left unread are converted into errors to write out later.
427    arguments.reportRemainingOptionsAsUnrecognized();
428
429    // report any errors if they have occured when parsing the program aguments.
430    if (arguments.errors())
431    {
432        arguments.writeErrorMessages(std::cout);
433        return 1;
434    }
435   
436    osg::Node* node = createScene();
437
438    // add model to viewer.
439    viewer.setSceneData( node );
440
441    // create the windows and run the threads.
442    viewer.realize();
443
444    while( !viewer.done() )
445    {
446        // wait for all cull and draw threads to complete.
447        viewer.sync();
448
449        // update the scene by traversing it with the the update visitor which will
450        // call all node update callbacks and animations.
451        viewer.update();
452         
453        // fire off the cull and draw traversals of the scene.
454        viewer.frame();
455       
456    }
457   
458    // wait for all cull and draw threads to complete before exit.
459    viewer.sync();
460
461    return 0;
462}
Note: See TracBrowser for help on using the browser.