VR-Forces 4.3 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
exampleOsgParticles

Table of Contents

Overview

This example shows how to create an OpenSceneGraph application. This particular example demonstrates the structure of a simple particle system.

A specific set of classes need to be configured correctly to produce a working OSG particle system; osgParticle::Particle, osgParticle::ParticleSystem, osgParticle::ParticleSystemUpdater, and osgParticle::ModularEmitter. The ModularEmitter also contains a particle placer, counter, and shooter which need to be configured. This example includes two optional custom osgParticle::Interpolator objects to demonstrate changing the size and color of each particle over its lifetime.

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 SimpleParticles is an osg::Group so it can just be placed in the scene-graph to work. At construction time, SimpleParticles 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 SimpleParticles 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 two custom osgParticle::Interpolator objects which are used to change the size and color of the particles over their lifetime. Without these custom Interpolators, each particle will change in a linear form from a beginning size or color to an ending size or color. These custorm Interpolator objects are used to demponstrate changes from the default values, but are not required for a minimal particle system.

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/exampleOsgParticles.exe (on Windows) or ./bin/exampleOsgParticles (on Linux). For more information about running examples, please see Running Applications and Examples.

Learn More

Example Source Files


exampleOsgParticles.cxx

/******************************************************************************
** Copyright (c) 2012 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <string>
#include <osg/Light>
#include <osgViewer/Viewer>
#include <osgDB/WriteFile>
// 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[])
{
// Create the particle system as the root Node for the scene.
// Create the Viewer to display the scene.
osgViewer::Viewer viewer;
viewer.setUpViewInWindow(100, 100, 1280, 960);
// 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();
// If the user supplied the name of an osg file, write out the scene graph.
for ( int ii(1); ii < argc; ++ii )
{
static const std::string ext("osg");
std::string arg( argv[ii] );
const int s( arg.size() );
const int d( arg.rfind('.') );
if ( d != std::string::npos && d == s - 4 &&
arg.substr( d + 1, s ) == ext )
{
osgDB::writeNodeFile( *root, arg );
break;
}
}
return 0;
}

SimpleParticleSystem.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 ModularProgram;
class RandomRateCounter;
class PointPlacer;
class RadialShooter;
}
class SimpleParticles : public osg::Group
{
public:
virtual ~SimpleParticles();
osg::PositionAttitudeTransform* positionAttitudeTransform() const { return myPat.get(); }
osgParticle::Particle* particle() const { return myParticle; }
osgParticle::ParticleSystem* particleSystem() const { return myParticleSystem.get(); }
osgParticle::ParticleSystemUpdater* particleSystemUpdater() const { return myParticleSystemUpdater.get(); }
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::ModularProgram* modularProgram() const { return myModularProgram.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::ModularProgram> myModularProgram;
osg::ref_ptr<osgParticle::RandomRateCounter> myRandomRateCounter;
osg::ref_ptr<osgParticle::PointPlacer> myPointPlacer;
osg::ref_ptr<osgParticle::RadialShooter> myRadialShooter;
};

SimpleParticleSystem.cxx

/******************************************************************************
** Copyright (c) 2012 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#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/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 Colerp : public osgParticle::Interpolator
{
public:
Colerp()
: osgParticle::Interpolator()
, myColors()
{
setColorList();
}
Colerp(const Interpolator& copy, const osg::CopyOp& copyop =
osg::CopyOp::SHALLOW_COPY)
: osgParticle::Interpolator(copy, copyop)
, myColors()
{
setColorList();
}
virtual ~Colerp() {}
META_Object(test, Colerp)
void setColorList()
{
myColors.push_back(Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); // white
myColors.push_back(Vec4f(1.0f, 0.0f, 0.0f, 1.0f)); // red
myColors.push_back(Vec4f(1.0f, 1.0f, 0.0f, 1.0f)); // yellow
myColors.push_back(Vec4f(0.0f, 1.0f, 0.0f, 1.0f)); // green
myColors.push_back(Vec4f(0.0f, 1.0f, 1.0f, 1.0f)); // cyan
myColors.push_back(Vec4f(0.0f, 0.0f, 1.0f, 1.0f)); // blue
myColors.push_back(Vec4f(1.0f, 0.0f, 1.0f, 1.0f)); // magenta
myColors.push_back(Vec4f(0.0f, 0.0f, 0.0f, 1.0f)); // black
}
virtual float interpolate(float t, float y1, float y2) const
{
// linear interpolation
return y1 + (y2 - y1) * t;
}
virtual osg::Vec4 interpolate(
float t, const osg::Vec4& y1, const osg::Vec4& y2) const
{
float count(myColors.size() - 1.0f);
float inv(1.0f / count);
myColors.at(0).set(y1.r(), y1.g(), y1.b(), y1.a());
myColors.at(count).set(y2.r(), y2.g(), y2.b(), y2.a());
for (float step(0.0f); step < count; ++step)
{
if (t <= inv * (step + 1.0))
{
return osgParticle::Interpolator::interpolate(
(t - (inv * step)) * count,
myColors.at(step),
myColors.at(step + 1));
}
}
return osgParticle::Interpolator::interpolate(t, y1, y2);
}
private:
mutable std::vector<Vec4f> myColors;
};
class Sizerp : public osgParticle::Interpolator
{
public:
Sizerp() : osgParticle::Interpolator() {}
Sizerp(const Interpolator& copy, const osg::CopyOp& copyop =
osg::CopyOp::SHALLOW_COPY)
: osgParticle::Interpolator(copy, copyop) {}
virtual ~Sizerp() { }
META_Object(test, Sizerp)
float doubleSize(float t, float y1, float y2) const
{
return y1 + (y2 - y1) * t * 2.0;
}
virtual float interpolate(float t, float y1, float y2) const
{
float r = doubleSize(t, y1, y2);
if (r > y2)
{
r = y2 - (r - y2);
}
return r;
}
};
: osg::Group()
, myPat(new osg::PositionAttitudeTransform)
, myParticle(new osgParticle::Particle)
, myParticleSystem(new osgParticle::ParticleSystem)
, myParticleSystemUpdater(new osgParticle::ParticleSystemUpdater)
, myModularEmitter(new osgParticle::ModularEmitter)
, myModularProgram(new osgParticle::ModularProgram)
, myRandomRateCounter(dynamic_cast<osgParticle::RandomRateCounter*>(myModularEmitter->getCounter()))
, myPointPlacer(dynamic_cast<osgParticle::PointPlacer*>(myModularEmitter->getPlacer()))
, myRadialShooter(dynamic_cast<osgParticle::RadialShooter*>(myModularEmitter->getShooter()))
{
//
// 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->setPosition(osg::Vec3f(0.0f, 0.0f, -1.0f));
myPat->setAttitude(osg::Quat(osg::DegreesToRadians(90.0f), osg::Vec3f(0.0f, 0.0f, 1.0f)));
//
// Create a particle to be used as a templat for all particles.
myParticle->setShape(osgParticle::Particle::QUAD);
myParticle->setLifeTime(10.0f);
myParticle->setRadius(5.0f);
myParticle->setMass(0.01f);
myParticle->setSizeRange(osgParticle::rangef(0.1f, 5.0f));
myParticle->setSizeInterpolator(new Sizerp());
myParticle->setColorRange(osgParticle::rangev4(
osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f),
osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f)));
myParticle->setColorInterpolator(new Colerp());
myParticle->setAngularVelocity(
Vec3f(osg::DegreesToRadians(90.0f), 0.0f, 0.0f));
//
// Assign a texture and particle templat 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(10.0f, 20.0f);
//
// Set a slightly pseudo-random initial velocities for each particle.
myRadialShooter->setThetaRange(osgParticle::rangef(0.0f, osg::DegreesToRadians(90.0f)));
myRadialShooter->setPhiRange(osgParticle::rangef(0.0f, osg::DegreesToRadians(90.0f)));
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->setParticleSystem(myParticleSystem);
myPat->addChild(myModularEmitter);
osgParticle::AccelOperator* accelUp(new osgParticle::AccelOperator());
accelUp->setToGravity(-1.0f);
myModularProgram->addOperator(accelUp);
osgParticle::FluidFrictionOperator*
airFriction(new osgParticle::FluidFrictionOperator());
airFriction->setFluidToAir();
// myModularProgram->addOperator(airFriction);
myModularProgram->setParticleSystem(myParticleSystem);
// addChild(myModularProgram);
}
{
// 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 Mar 11 21:20:57 EDT 2015 from SVN revision 150940
Copyright © 2005-2014 VT MÄK. All Rights Reserved (www.mak.com)