root/OpenSceneGraph/trunk/examples/osgparticleshader/osgparticleshader.cpp @ 13348

Revision 12292, 9.2 kB (checked in by robert, 4 years ago)

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
Line 
1/* OpenSceneGraph example, osgparticleshader.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <iostream>
20
21#include <osg/ShapeDrawable>
22#include <osg/MatrixTransform>
23#include <osg/Point>
24#include <osg/PointSprite>
25#include <osgDB/ReadFile>
26#include <osgDB/WriteFile>
27#include <osgGA/TrackballManipulator>
28#include <osgGA/StateSetManipulator>
29#include <osgViewer/ViewerEventHandlers>
30#include <osgViewer/Viewer>
31
32#include <osgParticle/ParticleSystem>
33#include <osgParticle/ParticleSystemUpdater>
34#include <osgParticle/ModularEmitter>
35#include <osgParticle/ModularProgram>
36
37#include <osgParticle/AccelOperator>
38#include <osgParticle/DampingOperator>
39#include <osgParticle/BounceOperator>
40#include <osgParticle/SinkOperator>
41
42void createFountainEffect( osgParticle::ModularEmitter* emitter, osgParticle::ModularProgram* program )
43{
44    // Emit specific number of particles every frame
45    osg::ref_ptr<osgParticle::RandomRateCounter> rrc = new osgParticle::RandomRateCounter;
46    rrc->setRateRange( 500, 2000 );
47   
48    // Accelerate particles in the given gravity direction.
49    osg::ref_ptr<osgParticle::AccelOperator> accel = new osgParticle::AccelOperator;
50    accel->setToGravity();
51   
52    // Multiply each particle's velocity by a damping constant.
53    osg::ref_ptr<osgParticle::DampingOperator> damping = new osgParticle::DampingOperator;
54    damping->setDamping( 0.9f );
55   
56    // Bounce particles off objects defined by one or more domains.
57    // Supported domains include triangle, rectangle, plane, disk and sphere.
58    // Since a bounce always happens instantaneously, it will not work correctly with unstable delta-time.
59    // At present, even the floating error of dt (which are applied to ParticleSystem and Operator seperately)
60    // causes wrong bounce results. Some one else may have better solutions for this.
61    osg::ref_ptr<osgParticle::BounceOperator> bounce = new osgParticle::BounceOperator;
62    bounce->setFriction( -0.05 );
63    bounce->setResilience( 0.35 );
64    bounce->addDiskDomain( osg::Vec3(0.0f, 0.0f, -2.0f), osg::Z_AXIS, 8.0f );
65    bounce->addPlaneDomain( osg::Plane(osg::Z_AXIS, 5.0f) );
66   
67    // Kill particles going inside/outside of specified domains.
68    osg::ref_ptr<osgParticle::SinkOperator> sink = new osgParticle::SinkOperator;
69    sink->setSinkStrategy( osgParticle::SinkOperator::SINK_OUTSIDE );
70    sink->addSphereDomain( osg::Vec3(), 20.0f );
71   
72    emitter->setCounter( rrc.get() );
73    program->addOperator( accel.get() );
74    program->addOperator( damping.get() );
75    program->addOperator( bounce.get() );
76    program->addOperator( sink.get() );
77}
78
79int main( int argc, char** argv )
80{
81    osg::ArgumentParser arguments( &argc, argv );
82   
83    std::string textureFile("Images/smoke.rgb");
84    while ( arguments.read("--texture", textureFile) ) {}
85   
86    float pointSize = 20.0f;
87    while ( arguments.read("--point", pointSize) ) {}
88   
89    double visibilityDistance = -1.0f;
90    while ( arguments.read("--visibility", visibilityDistance) ) {}
91   
92    bool customShape = false;
93    while ( arguments.read("--enable-custom") ) { customShape = true; }
94   
95    bool useShaders = true;
96    while ( arguments.read("--disable-shaders") ) { useShaders = false; }
97   
98    /***
99    Customize particle template and system attributes
100    ***/
101    osg::ref_ptr<osgParticle::ParticleSystem> ps = new osgParticle::ParticleSystem;
102   
103    ps->getDefaultParticleTemplate().setLifeTime( 5.0f );
104   
105    if ( customShape )
106    {
107        // osgParticle now supports making use of customized drawables. The draw() method will be executed
108        // and display lists will be called for each particle. It is always a huge consumption of memory, and
109        // hardly to use shaders to render them, so please be careful using this feature.
110        ps->getDefaultParticleTemplate().setShape( osgParticle::Particle::USER );
111        ps->getDefaultParticleTemplate().setDrawable( new osg::ShapeDrawable(new osg::Box(osg::Vec3(), 1.0f)) );
112        useShaders = false;
113    }
114    else
115    {
116        // The shader only supports rendering points at present.
117        ps->getDefaultParticleTemplate().setShape( osgParticle::Particle::POINT );
118    }
119   
120    // Set the visibility distance of particles, due to their Z-value in the eye coordinates.
121    // Particles that are out of the distance (or behind the eye) will not be rendered.
122    ps->setVisibilityDistance( visibilityDistance );
123   
124    if ( useShaders )
125    {
126        // Set using local GLSL shaders to render particles.
127        // At present, this is slightly efficient than ordinary methods. The bottlenack here seems to be the cull
128        // traversal time. Operators go through the particle list again and again...
129        ps->setDefaultAttributesUsingShaders( textureFile, true, 0 );
130    }
131    else
132    {
133        // The default methods uses glBegin()/glEnd() pairs. Fortunately the GLBeginEndAdapter does improve the
134        // process, which mimics the immediate mode with glDrawArrays().
135        ps->setDefaultAttributes( textureFile, true, false, 0 );
136       
137        // Without the help of shaders, we have to sort particles to make the visibility distance work. Sorting is
138        // also useful in rendering transparent particles in back-to-front order.
139        if ( visibilityDistance>0.0 )
140            ps->setSortMode( osgParticle::ParticleSystem::SORT_BACK_TO_FRONT );
141    }
142   
143    // At last, to make the point sprite work, we have to set the points size and the sprite attribute.
144    osg::StateSet* stateset = ps->getOrCreateStateSet();
145    stateset->setAttribute( new osg::Point(pointSize) );
146    stateset->setTextureAttributeAndModes( 0, new osg::PointSprite, osg::StateAttribute::ON );
147   
148    /***
149    Construct other particle system elements, including the emitter and program
150    ***/
151    osg::ref_ptr<osgParticle::ModularEmitter> emitter = new osgParticle::ModularEmitter;
152    emitter->setParticleSystem( ps.get() );
153   
154    osg::ref_ptr<osgParticle::ModularProgram> program = new osgParticle::ModularProgram;
155    program->setParticleSystem( ps.get() );
156   
157    createFountainEffect( emitter.get(), program.get() );
158   
159    /***
160    Add the entire particle system to the scene graph
161    ***/
162    osg::ref_ptr<osg::MatrixTransform> parent = new osg::MatrixTransform;
163    parent->addChild( emitter.get() );
164    parent->addChild( program.get() );
165   
166    // The updater can receive particle systems as child drawables now. The addParticleSystem() method
167    // is still usable, with which we should define another geode to contain a particle system.
168    osg::ref_ptr<osgParticle::ParticleSystemUpdater> updater = new osgParticle::ParticleSystemUpdater;
169    //updater->addDrawable( ps.get() );
170   
171    osg::ref_ptr<osg::Group> root = new osg::Group;
172    root->addChild( parent.get() );
173    root->addChild( updater.get() );
174   
175    // FIXME 2010.9.19: the updater can't be a drawable; otehrwise the ParticleEffect will not work properly. why?
176    updater->addParticleSystem( ps.get() );
177   
178    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
179    geode->addDrawable( ps.get() );
180    root->addChild( geode.get() );
181   
182    /***
183    Start the viewer
184    ***/
185    osgViewer::Viewer viewer;
186    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
187    viewer.addEventHandler( new osgViewer::StatsHandler );
188    viewer.addEventHandler( new osgViewer::WindowSizeHandler );
189    viewer.setSceneData( root.get() );
190    viewer.setCameraManipulator( new osgGA::TrackballManipulator );
191   
192    // A floating error of delta-time should be explained here:
193    // The particles emitter, program and updater all use a 'dt' to compute the time value in every frame.
194    // Because the 'dt' is a double value, it is not suitable to keep three copies of it seperately, which
195    // is the previous implementation. The small error makes some opeartors unable to work correctly, e.g.
196    // the BounceOperator.
197    // Now we make use of the getDeltaTime() of ParticleSystem to maintain and dispatch the delta time. But..
198    // it is not the best solution so far, since there are still very few particles acting unexpectedly.
199    return viewer.run();
200   
201    // FIXME 2010.9.19: At present, getDeltaTime() is not used and the implementations in the updater and processors still
202    // use a (t - _t0) as the delta time, which is of course causing floating errors. ParticleEffect will not work if we
203    // replace the delta time with getDeltaTime()... Need to find a solution.
204}
Note: See TracBrowser for help on using the browser.