VR-Forces 4.6.1 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleOsgParticlesGaussian

Table of Contents

Overview

This example shows how to create an OpenSceneGraph application. This particular example demonstrates the use of an osgParticle::Interpolator to provide a Gaussian transform of each particle.

A new Gaussian interpolator is derived from osgParticle::Interpolator and performs a transform from the linear life time to a Gaussian curve which is then applied to the alpha value of the particle. This allows each particle to fade from opaque to invisible according to a Gaussian curve.

Example details

The example creates a single class which encompasses the entire particle system (It is a convinience to create the particle system as one object but not necessary). This particle system is designed to emit one type of particle; a puff of smoke. The class GaussianParticles is an osg::Group so it can just be placed in the scene-graph to work. At construction time, GaussianParticles creates instances of all the necessary classes to construct a working particle system. The scene structure (how the objects are parented) is important to how the particle system works. This class is given a child osg::Group which parents the osgParticle::ParticleSytemUpdater and an osg::Geode. The osg::Geode is given an osgParticle::ParticleSystem as a drawable. The ParticleSystemUpdater is given the same ParticleSystem for it to manipulate. The ParticleSystem is given an osgParticle::Particle as a template for how to construct new particles. This main GaussianParticles class is also given a child osg::PositionAttitudeTransform to place the emitter of the particles. The PositionAttitudeTransform parents an osgParticle::ModularEmitter which controls how the particles are emitted. The ModularEmitter constructs its own default placer, counter and shooter objects. The placer sets the intiaitial position of each particle, the counter sets a range of particles to create each frame, and the shooter sets an initial velocity for each particle.

The example also creates custom osgParticle::Interpolator object which is used to change the transparency of the particles over their lifetime. Without these custom Interpolator, each particle will change in a linear form from a beginning opaqueness to an ending opaqueness.

Building the Example

VR-Vantage includes pre-built versions of the example application. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.

Running the Example

This example is an application. You can run it by running ./bin/exampleOsgParticlesGaussian.exe (on Windows) or ./bin/exampleOsgParticlesGaussian (on Linux). For more information about running examples, please see Running Applications and Examples.

Learn More

Example Source Files


exampleOsgParticlesGaussian.cxx

/******************************************************************************
** Copyright ( c ) 2012 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <osg/Light>
#include <osgViewer/Viewer>
#include <osgDB/WriteFile>
#include "XYZAxis.h"
// The main function sets up the scene-graph hierarchy, then creates a viewer
// to render the scene, modifies the global light then starts rendering.
int main( int argc, char* argv[] )
{
// Get various options from the command line.
double theta ( 360.0 );
double phi ( 360.0 );
double sigma( 1.0 ); // Gaussian: Sigma value; should be 1, 2, 3...
double life( 4.0 ); // Gaussian: scale particle lifetime
double height( 1.0 ); // Gaussian: scale interpolated value
for ( int ii( 1 ); ii < argc; ++ii )
{
std::string arg( argv[ii] );
if ( arg == "-h" || arg == "--help" || arg == "help" )
{
std::cout << "Usage:" << std::endl
<< argv[0] << "[options]" << std::endl
<< "\tWhere 'options' are as follows:" << std::endl
<< "\t\t'theta t' where t is an angle between 0.0 and 360.0" << std::endl
<< "\t\t'phi p' where p is an angle between 0.0 and 360.0" << std::endl
<< "\t\t'sigma s' where s is the sigma value for a Gaussian interpolator" << std::endl
<< "\t\t'life l' where l is a scaling value to adjust percentage of life each frame" << std::endl
<< "\t\t'height h' where h is a scaling value to adjust the interpolated value" << std::endl
<< std::endl;
return 1;
}
if ( ii == argc - 1 )
{
break;
}
if ( arg == "theta")
{
double val = std::strtod( argv[ii + 1], NULL );
if ( val > 0.0 && val <= 360.0 )
{
theta = val;
++ii;
}
continue;
}
if ( arg == "phi")
{
double val = std::strtod( argv[ii + 1], NULL );
if ( val > 0.0 && val <= 360.0 )
{
phi = val;
++ii;
}
continue;
}
if ( arg == "sigma")
{
long int val = std::strtol( argv[ii + 1], NULL, 10 );
if ( val > 0 )
{
sigma = static_cast<double>( val );
++ii;
}
continue;
}
if ( arg == "life")
{
double val = std::strtod( argv[ii + 1], NULL );
if ( val > 0.0 )
{
life = val;
++ii;
}
continue;
}
if ( arg == "height")
{
double val = std::strtod( argv[ii + 1], NULL );
if ( val > 0.0 )
{
height = val;
++ii;
}
continue;
}
}
// Create the root and axis geometry
osg::Group* root = new osg::Group();
root->addChild( new XYZAxis() );
// Create the particle system and add to the scene.
root->addChild( new GaussianParticles( theta, phi, sigma, life, height ) );
// Create the Viewer to display the scene.
osgViewer::Viewer viewer;
// viewer.setUpViewInWindow( 100, 100, 1280, 960 );
viewer.setUpViewInWindow( 100, 100, 600, 600 );
// Set the global light. By default the Viewer has a single directional
// light for the scene. We'll get the light from the viewer and make sure
// its diffuse color to white.
osg::Light* light = viewer.getLight();
light->setDiffuse( osg::Vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
// The final step is to enter a simulation loop.
// Add the root of the scene to the viewer and start rendering.
viewer.setSceneData( root );
viewer.run();
return 0;
}

GaussianParticleSystem.h

/******************************************************************************
** Copyright (c) 2012 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <osg/Group>
#include <osg/Referenced>
namespace osg {
class PositionAttitudeTransform;
}
namespace osgParticle {
class Particle;
class ParticleSystem;
class ParticleSystemUpdater;
class Program;
class RandomRateCounter;
class PointPlacer;
class RadialShooter;
}
class GaussianParticles : public osg::Group
{
public:
GaussianParticles( double theta, double phi, double sigma=1.0,
double life=4.0, double height=1.0 );
virtual ~GaussianParticles();
osg::PositionAttitudeTransform* positionAttitudeTransform() const
{
return myPat.get();
}
osgParticle::Particle* particle() const
{
return myParticle;
}
osgParticle::ParticleSystem* particleSystem() const
{
return myParticleSystem.get();
}
osgParticle::ParticleSystemUpdater* particleSystemUpdater() const
{
}
osgParticle::ModularEmitter* modularEmitter() const
{
return myModularEmitter.get();
}
osgParticle::RandomRateCounter* randomRateCounter() const
{
return myRandomRateCounter.get();
}
osgParticle::PointPlacer* pointPlacer() const
{
return myPointPlacer.get();
}
osgParticle::RadialShooter* radialShooter() const
{
return myRadialShooter.get();
}
osgParticle::Program* program() const
{
return myProgram.get();
}
private:
osg::ref_ptr<osg::PositionAttitudeTransform> myPat;
osgParticle::Particle* myParticle; // not an osg::Object - no ref counting.
osg::ref_ptr<osgParticle::ParticleSystem> myParticleSystem;
osg::ref_ptr<osgParticle::ParticleSystemUpdater> myParticleSystemUpdater;
osg::ref_ptr<osgParticle::ModularEmitter> myModularEmitter;
osg::ref_ptr<osgParticle::Program> myProgram;
osg::ref_ptr<osgParticle::RandomRateCounter> myRandomRateCounter;
osg::ref_ptr<osgParticle::PointPlacer> myPointPlacer;
osg::ref_ptr<osgParticle::RadialShooter> myRadialShooter;
};

GaussianParticleSystem.cxx

/******************************************************************************
** Copyright (c) 2012 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <osg/Geode>
#include <osg/Object>
#include <osg/PositionAttitudeTransform>
#include <osg/Math>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osgParticle/AccelOperator>
#include <osgParticle/FluidFrictionOperator>
#include <osgParticle/FluidProgram>
#include <osgParticle/LinearInterpolator>
#include <osgParticle/ModularEmitter>
#include <osgParticle/ModularProgram>
#include <osgParticle/Particle>
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleSystemUpdater>
#include <osgParticle/PointPlacer>
#include <osgParticle/RandomRateCounter>
#include <osgParticle/RadialShooter>
static const std::string textureImage("../data/Vehicles/Smoke.rgb");
using namespace osg;
class Gausserp : public osgParticle::Interpolator
{
public:
Gausserp( double sigma = 1.0, double life = 4.0, double height = 2.5 )
: osgParticle::Interpolator()
, mySigma( sigma )
, myLife( life )
, myHeight( height )
{}
Gausserp( const Interpolator& copy, const osg::CopyOp& copyop =
osg::CopyOp::SHALLOW_COPY )
: osgParticle::Interpolator( copy, copyop )
, mySigma( dynamic_cast<const Gausserp&>( copy ).mySigma )
, myLife( dynamic_cast<const Gausserp&>( copy ).myLife )
, myHeight( dynamic_cast<const Gausserp&>( copy ).myHeight )
{}
virtual ~Gausserp() {}
META_Object( test, Gausserp );
double gaussian( double x ) const
{
static const double f1 = 1.0 / ( mySigma * std::sqrt( 2.0 * osg::PI ) );
static const double f2 = 1.0 / ( 2.0 * std::pow( mySigma, 2.0 ) );
return f1 * std::exp( ( -std::pow( x, 2.0 ) ) * f2 );
}
virtual float interpolate( float t, float y1, float y2 ) const
{
// t ranges from 0.0 to 1.0, at these boundaries the transformed values
// are approximately 0.4 to 0.2 respectively. Adjustments are needed
// to increase the range into a bell curve from approximately 1.0 to 0.0.
double x = static_cast<double>( t * myLife );
double y = gaussian( x ) * myHeight;
return y1 + ( y2 - y1 ) * static_cast<float>( y );
}
double mySigma;
double myLife;
double myHeight;
};
GaussianParticles::GaussianParticles( double theta, double phi, double sigma,
double life, double height )
: osg::Group()
, myPat( new osg::PositionAttitudeTransform )
, myParticle( new osgParticle::Particle )
, myParticleSystem( new osgParticle::ParticleSystem )
, myParticleSystemUpdater( new osgParticle::ParticleSystemUpdater )
, myModularEmitter( new osgParticle::ModularEmitter )
, myProgram( new osgParticle::ModularProgram )
, myRandomRateCounter( dynamic_cast<osgParticle::RandomRateCounter*>( myModularEmitter->getCounter() ) )
, myPointPlacer( dynamic_cast<osgParticle::PointPlacer*>( myModularEmitter->getPlacer() ) )
, myRadialShooter( dynamic_cast<osgParticle::RadialShooter*>( myModularEmitter->getShooter() ) )
{
std::cout << "Theta " << theta << ", Phi " << phi << std::endl;
//
// Set up the root of this particle system scene graph.
osg::Group* group( new osg::Group() );
osg::Geode* geode( new osg::Geode() );
addChild( group );
addChild( myPat );
myPat->setAttitude( osg::Quat(
osg::DegreesToRadians( 0.0f ), osg::Vec3f( 0.0f, 0.0f, 1.0f ) ) );
myPat->setPosition( osg::Vec3f( 0.0f, 0.0f, 0.0f ) );
//
// Create a particle to be used as a template for all particles.
myParticle->setShape( osgParticle::Particle::QUAD );
myParticle->setLifeTime( 10.0f );
myParticle->setRadius( 5.0f );
myParticle->setMass( 0.01f );
//
// Set the interpolators on the particles
myParticle->setSizeRange( osgParticle::rangef( 5.0f, 5.0f ) );
myParticle->setColorRange( osgParticle::rangev4(
osg::Vec4f( 1.0f, 1.0f, 1.0f, 1.0f ),
osg::Vec4f( 1.0f, 1.0f, 1.0f, 1.0f ) ) );
std::cout << "Gauss interpolation: sigma " << sigma
<< ", life " << life << ", height " << height << std::endl;
myParticle->setAlphaRange( osgParticle::rangef( 0.0f, 1.0f ) );
myParticle->setAlphaInterpolator( new Gausserp( sigma, life, height ) );
myParticle->setAngularVelocity(
Vec3f( osg::DegreesToRadians( 90.0f ), 0.0f, 0.0f ) );
float radius = 0.5f;
float density = 1.0f;
myParticle->setRadius( radius );
myParticle->setMass(
density * radius * radius * radius * osg::PI * 4.0f / 3.0f );
//
// Assign a texture and particle template to be used by the system.
myParticleSystem->setDefaultAttributes( textureImage, false, false );
myParticleSystem->setDefaultParticleTemplate( *myParticle );
geode->addDrawable( myParticleSystem );
group->addChild( geode );
//
// Set the particle system to be managed by the updater
myParticleSystemUpdater->addParticleSystem( myParticleSystem );
group->addChild( myParticleSystemUpdater );
//
// Set a range of particles to be created each frame.
myRandomRateCounter->setRateRange( 200.0f, 200.0f );
//
// Set a slightly pseudo-random initial velocities for each particle.
myRadialShooter->setThetaRange(
osgParticle::rangef( 0.0f, osg::DegreesToRadians( theta ) ) );
myRadialShooter->setPhiRange(
osgParticle::rangef( 0.0f, osg::DegreesToRadians( phi ) ) );
myRadialShooter->setInitialSpeedRange( osgParticle::rangef( 5.0f, 5.0f ) );
//
// Set which particle system to be used by the emitter and then place the
// emitter in the scene.
myModularEmitter->setNumParticlesToCreateMovementCompensationRatio( 1.5f );
myModularEmitter->setParticleSystem( myParticleSystem );
myPat->addChild( myModularEmitter );
#if 0
osgParticle::AccelOperator* accelUp( new osgParticle::AccelOperator() );
accelUp->setToGravity( -1.0f );
myProgram->addOperator( accelUp );
osgParticle::FluidFrictionOperator*
airFriction( new osgParticle::FluidFrictionOperator() );
airFriction->setFluidToAir();
myProgram->addOperator( airFriction );
#else
myProgram = new osgParticle::FluidProgram();
osgParticle::FluidProgram* fp =
dynamic_cast<osgParticle::FluidProgram*>( myProgram.get() );
fp->setWind( osg::Vec3f( 0.0f, 0.0f, 0.0f ) );
#endif
#if 0
myProgram->setParticleSystem( myParticleSystem.get() );
addChild( myProgram );
#endif
}
{
// These objects are ref counted, so just set their pointers to null.
myPointPlacer = NULL;
// The particle is not ref-counted so it should be manually deleted.
delete myParticle;
myParticle = NULL;
}

Document ID: Generated on Wed Jul 25 16:57:45 EDT 2018 from SVN revision 190790
Copyright © 2005-2018 VT MÄK. All Rights Reserved (www.mak.com)