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