root/OpenSceneGraph/trunk/examples/osgparticleeffects/osgparticleeffects.cpp @ 5954

Revision 5954, 16.3 kB (checked in by robert, 7 years ago)

Ported following examples to osgViewer:

osgparticleeffects
osgphotoalbum
osgpick
osgpoints
osgpointsprite
osgprecipitation
osgprerender
osgprerendercubemap
osgreflect
osgscalarbar
osgscribe
osgsequence
osgplanets

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osgViewer/Viewer>
2
3#include <osg/Group>
4#include <osg/Geode>
5#include <osg/ShapeDrawable>
6#include <osg/Texture2D>
7#include <osg/PositionAttitudeTransform>
8#include <osg/MatrixTransform>
9#include <osg/io_utils>
10
11#include <osgUtil/Optimizer>
12#include <osgUtil/IntersectVisitor>
13
14#include <osgDB/ReadFile>
15
16#include <osgText/Text>
17
18#include <osgParticle/ExplosionEffect>
19#include <osgParticle/ExplosionDebrisEffect>
20#include <osgParticle/SmokeEffect>
21#include <osgParticle/SmokeTrailEffect>
22#include <osgParticle/FireEffect>
23
24// for the grid data..
25#include "../osghangglide/terrain_coords.h"
26
27osg::Vec3 wind(1.0f,0.0f,0.0f);           
28
29osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
30{
31    // set up the animation path
32    osg::AnimationPath* animationPath = new osg::AnimationPath;
33    animationPath->setLoopMode(osg::AnimationPath::LOOP);
34   
35    int numSamples = 40;
36    float yaw = 0.0f;
37    float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
38    float roll = osg::inDegrees(30.0f);
39   
40    double time=0.0f;
41    double time_delta = looptime/(double)numSamples;
42    for(int i=0;i<numSamples;++i)
43    {
44        osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
45        osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));
46       
47        animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
48
49        yaw += yaw_delta;
50        time += time_delta;
51
52    }
53    return animationPath;   
54}
55
56osg::Node* createMovingModel(const osg::Vec3& center, float radius)
57{
58    float animationLength = 10.0f;
59
60    osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);
61
62    osg::Group* model = new osg::Group;
63
64    osg::Node* glider = osgDB::readNodeFile("glider.osg");
65    if (glider)
66    {
67        const osg::BoundingSphere& bs = glider->getBound();
68        float size = radius/bs.radius()*0.15f;
69
70        osg::MatrixTransform* positioned = new osg::MatrixTransform;
71        positioned->setDataVariance(osg::Object::STATIC);
72        positioned->setMatrix(osg::Matrix::translate(-bs.center())*
73                                     osg::Matrix::scale(size,size,size)*
74                                     osg::Matrix::rotate(osg::inDegrees(-90.0f),0.0f,0.0f,1.0f));
75   
76        positioned->addChild(glider);
77   
78        osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform;   
79        xform->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
80        xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,0.5));
81        xform->addChild(positioned);
82
83        model->addChild(xform);
84    }
85 
86    osg::Node* cessna = osgDB::readNodeFile("cessna.osg");
87    if (cessna)
88    {
89        const osg::BoundingSphere& bs = cessna->getBound();
90        float size = radius/bs.radius()*0.15f;
91
92        osg::MatrixTransform* positioned = new osg::MatrixTransform;
93        positioned->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
94        positioned->setDataVariance(osg::Object::STATIC);
95        positioned->setMatrix(osg::Matrix::translate(-bs.center())*
96                                     osg::Matrix::scale(size,size,size)*
97                                     osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,1.0f));
98   
99        //positioned->addChild(cessna);
100        positioned->addChild(cessna);
101   
102        osg::MatrixTransform* xform = new osg::MatrixTransform;
103        xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,1.0));
104        xform->addChild(positioned);
105
106        model->addChild(xform);
107    }
108   
109    return model;
110}
111
112
113osg::Vec3 computeTerrainIntersection(osg::Node* subgraph,float x,float y)
114{
115    osgUtil::IntersectVisitor iv;
116    osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
117
118    const osg::BoundingSphere& bs = subgraph->getBound();
119    float zMax = bs.center().z()+bs.radius();
120    float zMin = bs.center().z()-bs.radius();
121   
122    segDown->set(osg::Vec3(x,y,zMin),osg::Vec3(x,y,zMax));
123    iv.addLineSegment(segDown.get());
124
125    subgraph->accept(iv);
126
127    if (iv.hits())
128    {
129        osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
130        if (!hitList.empty())
131        {
132            osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
133            return  ip;
134        }
135    }
136
137    return osg::Vec3(x,y,0.0f);
138}
139
140
141//////////////////////////////////////////////////////////////////////////////
142// MAIN SCENE GRAPH BUILDING FUNCTION
143//////////////////////////////////////////////////////////////////////////////
144
145void build_world(osg::Group *root)
146{
147
148    osg::Geode* terrainGeode = new osg::Geode;
149    // create terrain
150    {
151        osg::StateSet* stateset = new osg::StateSet();
152        osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
153        if (image)
154        {
155            osg::Texture2D* texture = new osg::Texture2D;
156            texture->setImage(image);
157            stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
158        }
159
160        terrainGeode->setStateSet( stateset );
161
162        float size = 1000; // 10km;
163        float scale = size/39.0f; // 10km;
164        float z_scale = scale*3.0f;
165
166        osg::HeightField* grid = new osg::HeightField;
167        grid->allocate(38,39);
168        grid->setXInterval(scale);
169        grid->setYInterval(scale);
170
171        for(unsigned int r=0;r<39;++r)
172        {
173            for(unsigned int c=0;c<38;++c)
174            {
175                grid->setHeight(c,r,z_scale*vertex[r+c*39][2]);
176            }
177        }
178        terrainGeode->addDrawable(new osg::ShapeDrawable(grid));
179       
180        root->addChild(terrainGeode);
181    }   
182
183
184    // create particle effects
185    {   
186        osg::Vec3 position = computeTerrainIntersection(terrainGeode,100.0f,100.0f);
187
188        osgParticle::ExplosionEffect* explosion = new osgParticle::ExplosionEffect(position, 10.0f);
189        osgParticle::ExplosionDebrisEffect* explosionDebri = new osgParticle::ExplosionDebrisEffect(position, 10.0f);
190        osgParticle::SmokeEffect* smoke = new osgParticle::SmokeEffect(position, 10.0f);
191        osgParticle::FireEffect* fire = new osgParticle::FireEffect(position, 10.0f);
192
193        explosion->setWind(wind);
194        explosionDebri->setWind(wind);
195        smoke->setWind(wind);
196        fire->setWind(wind);
197
198        root->addChild(explosion);
199        root->addChild(explosionDebri);
200        root->addChild(smoke);
201        root->addChild(fire);
202    }
203   
204    // create particle effects
205    {   
206        osg::Vec3 position = computeTerrainIntersection(terrainGeode,200.0f,100.0f);
207
208        osgParticle::ExplosionEffect* explosion = new osgParticle::ExplosionEffect(position, 1.0f);
209        osgParticle::ExplosionDebrisEffect* explosionDebri = new osgParticle::ExplosionDebrisEffect(position, 1.0f);
210        osgParticle::SmokeEffect* smoke = new osgParticle::SmokeEffect(position, 1.0f);
211        osgParticle::FireEffect* fire = new osgParticle::FireEffect(position, 1.0f);
212
213        explosion->setWind(wind);
214        explosionDebri->setWind(wind);
215        smoke->setWind(wind);
216        fire->setWind(wind);
217
218        root->addChild(explosion);
219        root->addChild(explosionDebri);
220        root->addChild(smoke);
221        root->addChild(fire);
222    }
223
224    // create the moving models.
225    {
226        root->addChild(createMovingModel(osg::Vec3(500.0f,500.0f,500.0f),300.0f));
227    }
228}
229
230
231// class to handle events with a pick
232class PickHandler : public osgGA::GUIEventHandler {
233public:
234
235    PickHandler() {}       
236   
237    bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
238    {
239        switch(ea.getEventType())
240        {
241            case(osgGA::GUIEventAdapter::PUSH):
242            {
243                osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
244                pick(viewer,ea);
245            }
246            return false;
247
248        default:
249            return false;
250        }
251    }
252
253    void pick(osgViewer::Viewer* viewer, const osgGA::GUIEventAdapter& ea)
254    {
255        osg::Group* root = dynamic_cast<osg::Group*>(viewer->getSceneData());       
256        if (!root) return;
257
258        osgUtil::LineSegmentIntersector::Intersections intersections;
259        if (viewer->computeIntersections(ea.getX(),ea.getY(),intersections))
260        {
261            const osgUtil::LineSegmentIntersector::Intersection& hit = *intersections.begin();
262
263            bool handleMovingModels = false;
264            const osg::NodePath& nodePath = hit.nodePath;
265            for(osg::NodePath::const_iterator nitr=nodePath.begin();
266                nitr!=nodePath.end();
267                ++nitr)
268            {
269                const osg::Transform* transform = dynamic_cast<const osg::Transform*>(*nitr);
270                if (transform)
271                {
272                    if (transform->getDataVariance()==osg::Object::DYNAMIC) handleMovingModels=true;
273                }
274            }
275           
276            osg::Vec3 position = handleMovingModels ? hit.getLocalIntersectPoint() : hit.getWorldIntersectPoint();
277            float scale = 10.0f * ((float)rand() / (float)RAND_MAX);
278            float intensity = 1.0f;
279
280            osgParticle::ExplosionEffect* explosion = new osgParticle::ExplosionEffect(position, scale, intensity);
281            osgParticle::ExplosionDebrisEffect* explosionDebri = new osgParticle::ExplosionDebrisEffect(position, scale, intensity);
282            osgParticle::FireEffect* fire = new osgParticle::FireEffect(position, scale, intensity);
283            osgParticle::ParticleEffect* smoke = 0;
284            if (handleMovingModels)
285                smoke =  new osgParticle::SmokeTrailEffect(position, scale, intensity);
286            else
287                smoke =  new osgParticle::SmokeEffect(position, scale, intensity);
288           
289            explosion->setWind(wind);
290            explosionDebri->setWind(wind);
291            smoke->setWind(wind);
292            fire->setWind(wind);
293
294            osg::Group* effectsGroup = new osg::Group;
295            effectsGroup->addChild(explosion);
296            effectsGroup->addChild(explosionDebri);
297            effectsGroup->addChild(smoke);
298            effectsGroup->addChild(fire);
299           
300
301            if (handleMovingModels)
302            {
303                // insert particle effects alongside the hit node, therefore able to track that nodes movement,
304                // however, this does require us to insert the ParticleSystem itself into the root of the scene graph
305                // seperately from the the main particle effects group which contains the emitters and programs.
306                // the follow code block implements this, note the path for handling particle effects which arn't attached to
307                // moving models is easy - just a single line of code!
308           
309                // tell the effects not to attach to the particle system locally for rendering, as we'll handle add it into the
310                // scene graph ourselves.
311                explosion->setUseLocalParticleSystem(false);
312                explosionDebri->setUseLocalParticleSystem(false);
313                smoke->setUseLocalParticleSystem(false);
314                fire->setUseLocalParticleSystem(false);
315
316                // find a place to insert the particle effects group alongside the hit node.
317                // there are two possible ways that this can be done, either insert it into
318                // a pre-existing group along side the hit node, or if no pre existing group
319                // is found then this needs to be inserted above the hit node, and then the
320                // particle effect can be inserted into this.
321                osg::ref_ptr<osg::Node> hitNode = hit.nodePath.back();
322                osg::Node::ParentList parents = hitNode->getParents();               
323                osg::Group* insertGroup = 0;
324                unsigned int numGroupsFound = 0;
325                for(osg::Node::ParentList::iterator itr=parents.begin();
326                    itr!=parents.end();
327                    ++itr)
328                {
329                    if (typeid(*(*itr))==typeid(osg::Group))
330                    {
331                        ++numGroupsFound;
332                        insertGroup = *itr;
333                    }
334                }               
335                if (numGroupsFound==parents.size() && numGroupsFound==1 && insertGroup)
336                {
337                    osg::notify(osg::INFO)<<"PickHandler::pick(,) hit node's parent is a single osg::Group so we can simple the insert the particle effects group here."<<std::endl;
338
339                    // just reuse the existing group.
340                    insertGroup->addChild(effectsGroup);
341                }
342                else
343                {           
344                    osg::notify(osg::INFO)<<"PickHandler::pick(,) hit node doesn't have an appropriate osg::Group node to insert particle effects into, inserting a new osg::Group."<<std::endl;
345                    insertGroup = new osg::Group;
346                    for(osg::Node::ParentList::iterator itr=parents.begin();
347                        itr!=parents.end();
348                        ++itr)
349                    {
350                        (*itr)->replaceChild(hit.nodePath.back(),insertGroup);
351                    }
352                    insertGroup->addChild(hitNode.get());
353                    insertGroup->addChild(effectsGroup);
354                }
355
356                // finally insert the particle systems into a Geode and attach to the root of the scene graph so the particle system
357                // can be rendered.
358                osg::Geode* geode = new osg::Geode;
359                geode->addDrawable(explosion->getParticleSystem());
360                geode->addDrawable(explosionDebri->getParticleSystem());
361                geode->addDrawable(smoke->getParticleSystem());
362                geode->addDrawable(fire->getParticleSystem());
363               
364                root->addChild(geode);
365
366            }
367            else
368            {
369                // when we don't have moving models we can simple insert the particle effect into the root of the scene graph
370                osg::notify(osg::INFO)<<"PickHandler::pick(,) adding particle effects to root node."<<std::endl;
371                root->addChild(effectsGroup);
372            }
373
374#if 0           
375            osg::Geode* geode = new osg::Geode;
376            geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(position,scale)));
377            group->addChild(geode);
378#endif
379 
380        }
381    }
382   
383protected:
384    virtual ~PickHandler() {}
385};
386
387// function used in debugging
388void insertParticle(osg::Group* root, const osg::Vec3& center, float radius)
389{
390    bool handleMovingModels = false;
391
392    osg::Vec3 position = center +
393               osg::Vec3( radius * (((float)rand() / (float)RAND_MAX)-0.5)*2.0,
394                          radius * (((float)rand() / (float)RAND_MAX)-0.5)*2.0,
395                          0.0f);
396
397    float scale = 10.0f * ((float)rand() / (float)RAND_MAX);
398    float intensity = 1.0f;
399
400    osgParticle::ExplosionEffect* explosion = new osgParticle::ExplosionEffect(position, scale, intensity);
401    osgParticle::ExplosionDebrisEffect* explosionDebri = new osgParticle::ExplosionDebrisEffect(position, scale, intensity);
402    osgParticle::FireEffect* fire = new osgParticle::FireEffect(position, scale, intensity);
403    osgParticle::ParticleEffect* smoke = 0;
404    if (handleMovingModels)
405        smoke =  new osgParticle::SmokeTrailEffect(position, scale, intensity);
406    else
407        smoke =  new osgParticle::SmokeEffect(position, scale, intensity);
408
409    explosion->setWind(wind);
410    explosionDebri->setWind(wind);
411    smoke->setWind(wind);
412    fire->setWind(wind);
413
414    osg::Group* effectsGroup = new osg::Group;
415    effectsGroup->addChild(explosion);
416    effectsGroup->addChild(explosionDebri);
417    effectsGroup->addChild(smoke);
418    effectsGroup->addChild(fire);
419
420    root->addChild(effectsGroup);
421}
422
423//////////////////////////////////////////////////////////////////////////////
424// main()
425//////////////////////////////////////////////////////////////////////////////
426
427int main(int, char **)
428{
429    // construct the viewer.
430    osgViewer::Viewer viewer;
431
432    // register the pick handler
433    viewer.addEventHandler(new PickHandler());
434   
435    osg::Group *root = new osg::Group;
436    build_world(root);
437
438    osgUtil::Optimizer optimizer;
439    optimizer.optimize(root);
440   
441    // add a viewport to the viewer and attach the scene graph.
442    viewer.setSceneData(root);
443       
444    return viewer.run();
445}
Note: See TracBrowser for help on using the browser.