Here is the source code of the osgparticle example a bit modify to show the
issue with lighting.
The key is the lighting parameter of the setDefaultParameters() method.
I've created a box reacting both to ambient and diffuse to have a reference on
lighting conditions in the scene.
Diffuse lighting :
In fact, while playing a bit with this sample, it seems that the diffuse
lighting is taken into account when the lightsource is at 'one certain position
relative to the particles'. However, this one is unpredictable (there is no
normal per vertex set onto particles sprites, so how odd ?) and must surely vary
with the manner the particlesystem animation is set/implemented (emitters and
programs).
Ambient lighting :
If you set no diffuse light but an ambient in the scene the particles remain
unvariably black, unreacting to it.
If anybody has an idea of code modification to make it work. I'm highly
interested !
Again, just one of the two kind of lighting (diffuse or ambient) would be enough
for me to be happy ! ;)
Christophe
PS: I'm using myself customized PS subclasses (to ensure deterministic randoms,
and
other things) and a bit more complex lighting conditions model, but the problem
I notice
must be same.
--- Message d'origine ---
> De : MEDARD Christophe <[email protected]>
> À : OpenSceneGraph Users <[email protected]>
> Sujet : Re: [osg-users] Non emissive ParticleSystem and lighting
> Date : lun 23 fév 2009 09:56:12 CET
>
> Sukender's post lets me know I'm not the only one having the problem, so I
> must do things correctly.
>
> Sure, using the particles systems as emissive and changing on the run
> particles
> colors would work, but it's a pain (!).
> Having a specific set of classes taking care of the internals of the particle
> behaviour should allow the programmer to let them live they life whatever the
> changing of conditions. Besides, it's what the interface leads to expect, the
> emissive and lighting boolean being free to take the 'false' value (actually
> I don't understand why it doesn't work - at least concerning the ambient -,
> since
> in the implementation everything seems to be done to enable LIGHTING onto the
> stateset... but I must be missing something).
>
> If useful, I'll try today to find some time to modify the simple sample code
> to show the problem.
> As I recall, the key is the lighting parameter, the emissive_particles ones
> allowing just to have an additive blend func on sprites...
> I'm using myself customized PS subclasses (to ensure deterministic randoms,
> and other things) and a bit more complex lighting conditions model, but the
> anomaly will be same.
>
> Christophe
>
> --- Message d'origine ---
> > De : Robert Osfield <[email protected]>
> > À : OpenSceneGraph Users <[email protected]>
> > Sujet : Re: [osg-users] Non emissive ParticleSystem and lighting
> > Date : dim 22 fév 2009 11:41:45 CET
> >
> > Can't you change the particle colour to be appropriate for different
> > times of day?
> >
> > Robert.
>
/* OpenSceneGraph example, osgparticle.
*
* 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 <osgViewer/Viewer>
#include <osg/Group>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osg/LightModel>
#include <osgParticle/Particle>
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleSystemUpdater>
#include <osgParticle/ModularEmitter>
#include <osgParticle/ModularProgram>
#include <osgParticle/RandomRateCounter>
#include <osgParticle/SectorPlacer>
#include <osgParticle/RadialShooter>
#include <osgParticle/AccelOperator>
#include <osgParticle/FluidFrictionOperator>
//////////////////////////////////////////////////////////////////////////////
// CUSTOM OPERATOR CLASS
//////////////////////////////////////////////////////////////////////////////
// This class demonstrates Operator subclassing. This way you can create
// custom operators to apply your motion effects to the particles. See docs
// for more details.
class VortexOperator: public osgParticle::Operator {
public:
VortexOperator()
: osgParticle::Operator(), center_(0, 0, 0), axis_(0, 0, 1),
intensity_(0.1f) {}
VortexOperator(const VortexOperator ©, const osg::CopyOp ©op =
osg::CopyOp::SHALLOW_COPY)
: osgParticle::Operator(copy, copyop), center_(copy.center_),
axis_(copy.axis_), intensity_(copy.intensity_) {}
META_Object(osgParticle, VortexOperator);
void setCenter(const osg::Vec3 &c)
{
center_ = c;
}
void setAxis(const osg::Vec3 &a)
{
axis_ = a / a.length();
}
// this method is called by ModularProgram before applying
// operators on the particle set via the operate() method.
void beginOperate(osgParticle::Program *prg)
{
// we have to check whether the reference frame is RELATIVE_RF to
parents
// or it's absolute; in the first case, we must transform the vectors
// from local to world space.
if (prg->getReferenceFrame() == osgParticle::Program::RELATIVE_RF) {
// transform the center point (full transformation)
xf_center_ = prg->transformLocalToWorld(center_);
// transform the axis vector (only rotation and scale)
xf_axis_ = prg->rotateLocalToWorld(axis_);
} else {
xf_center_ = center_;
xf_axis_ = axis_;
}
}
// apply a vortex-like acceleration. This code is not optimized,
// it's here only for demonstration purposes.
void operate(osgParticle::Particle *P, double dt)
{
float l = xf_axis_ * (P->getPosition() - xf_center_);
osg::Vec3 lc = xf_center_ + xf_axis_ * l;
osg::Vec3 R = P->getPosition() - lc;
osg::Vec3 v = (R ^ xf_axis_) * P->getMassInv() * intensity_;
// compute new position
osg::Vec3 newpos = P->getPosition() + v * dt;
// update the position of the particle without modifying its
// velocity vector (this is unusual, normally you should call
// the Particle::setVelocity() or Particle::addVelocity()
// methods).
P->setPosition(newpos);
}
protected:
virtual ~VortexOperator() {}
private:
osg::Vec3 center_;
osg::Vec3 xf_center_;
osg::Vec3 axis_;
osg::Vec3 xf_axis_;
float intensity_;
};
//////////////////////////////////////////////////////////////////////////////
// SIMPLE PARTICLE SYSTEM CREATION
//////////////////////////////////////////////////////////////////////////////
osgParticle::ParticleSystem *create_simple_particle_system(osg::Group *root)
{
// Ok folks, this is the first particle system we build; it will be
// very simple, with no textures and no special effects, just default
// values except for a couple of attributes.
// First of all, we create the ParticleSystem object; it will hold
// our particles and expose the interface for managing them; this object
// is a Drawable, so we'll have to add it to a Geode later.
osgParticle::ParticleSystem *ps = new osgParticle::ParticleSystem;
// As for other Drawable classes, the aspect of graphical elements of
// ParticleSystem (the particles) depends on the StateAttribute's we
// give it. The ParticleSystem class has an helper function that let
// us specify a set of the most common attributes: setDefaultAttributes().
// This method can accept up to three parameters; the first is a texture
// name (std::string), which can be empty to disable texturing, the second
// sets whether particles have to be "emissive" (additive blending) or not;
// the third parameter enables or disables lighting.
ps->setDefaultAttributes("", true, true); // MODIFICATION HERE : shouldn't
3rd parmater allow lighting to take effect ?
// ps->setDefaultAttributes("", true, false); // Code before
modification
// Now that our particle system is set we have to create an emitter, that is
// an object (actually a Node descendant) that generate new particles at
// each frame. The best choice is to use a ModularEmitter, which allow us to
// achieve a wide variety of emitting styles by composing the emitter using
// three objects: a "counter", a "placer" and a "shooter". The counter must
// tell the ModularEmitter how many particles it has to create for the
// current frame; then, the ModularEmitter creates these particles, and for
// each new particle it instructs the placer and the shooter to set its
// position vector and its velocity vector, respectively.
// By default, a ModularEmitter object initializes itself with a counter of
// type RandomRateCounter, a placer of type PointPlacer and a shooter of
// type RadialShooter (see documentation for details). We are going to leave
// these default objects there, but we'll modify the counter so that it
// counts faster (more particles are emitted at each frame).
osgParticle::ModularEmitter *emitter = new osgParticle::ModularEmitter;
// the first thing you *MUST* do after creating an emitter is to set the
// destination particle system, otherwise it won't know where to create
// new particles.
emitter->setParticleSystem(ps);
// Ok, get a pointer to the emitter's Counter object. We could also
// create a new RandomRateCounter object and assign it to the emitter,
// but since the default counter is already a RandomRateCounter, we
// just get a pointer to it and change a value.
osgParticle::RandomRateCounter *rrc =
static_cast<osgParticle::RandomRateCounter *>(emitter->getCounter());
// Now set the rate range to a better value. The actual rate at each frame
// will be chosen randomly within that range.
rrc->setRateRange(20, 30); // generate 20 to 30 particles per second
// The emitter is done! Let's add it to the scene graph. The cool thing is
// that any emitter node will take into account the accumulated
local-to-world
// matrix, so you can attach an emitter to a transform node and see it move.
root->addChild(emitter);
// Ok folks, we have almost finished. We don't add any particle modifier
// here (see ModularProgram and Operator classes), so all we still need is
// to create a Geode and add the particle system to it, so it can be
// displayed.
osg::Geode *geode = new osg::Geode;
geode->addDrawable(ps);
// add the geode to the scene graph
root->addChild(geode);
return ps;
}
//////////////////////////////////////////////////////////////////////////////
// COMPLEX PARTICLE SYSTEM CREATION
//////////////////////////////////////////////////////////////////////////////
osgParticle::ParticleSystem *create_complex_particle_system(osg::Group *root)
{
// Are you ready for a more complex particle system? Well, read on!
// Now we take one step we didn't before: create a particle template.
// A particle template is simply a Particle object for which you set
// the desired properties (see documentation for details). When the
// particle system has to create a new particle and it's been assigned
// a particle template, the new particle will inherit the template's
// properties.
// You can even assign different particle templates to each emitter; in
// this case, the emitter's template will override the particle system's
// default template.
osgParticle::Particle ptemplate;
ptemplate.setLifeTime(3); // 3 seconds of life
// the following ranges set the envelope of the respective
// graphical properties in time.
ptemplate.setSizeRange(osgParticle::rangef(0.75f, 3.0f));
ptemplate.setAlphaRange(osgParticle::rangef(0.0f, 1.5f));
ptemplate.setColorRange(osgParticle::rangev4(
osg::Vec4(1, 0.5f, 0.3f, 1.5f),
osg::Vec4(0, 0.7f, 1.0f, 0.0f)));
// these are physical properties of the particle
ptemplate.setRadius(0.05f); // 5 cm wide particles
ptemplate.setMass(0.05f); // 50 g heavy
// As usual, let's create the ParticleSystem object and set its
// default state attributes. This time we use a texture named
// "smoke.rgb", you can find it in the data distribution of OSG.
// We turn off the additive blending, because smoke has no self-
// illumination.
osgParticle::ParticleSystem *ps = new osgParticle::ParticleSystem;
ps->setDefaultAttributes("Images/smoke.rgb", false, true); // MODIFICATION
HERE : shouldn't 3rd parmater allow lighting to take effect ?
//ps->setDefaultAttributes("Images/smoke.rgb", false, false); // Code
before modification
// assign the particle template to the system.
ps->setDefaultParticleTemplate(ptemplate);
// now we have to create an emitter; this will be a ModularEmitter, for
which
// we define a RandomRateCounter as counter, a SectorPlacer as placer, and
// a RadialShooter as shooter.
osgParticle::ModularEmitter *emitter = new osgParticle::ModularEmitter;
emitter->setParticleSystem(ps);
// setup the counter
osgParticle::RandomRateCounter *counter = new
osgParticle::RandomRateCounter;
counter->setRateRange(60, 60);
emitter->setCounter(counter);
// setup the placer; it will be a circle of radius 5 (the particles will
// be placed inside this circle).
osgParticle::SectorPlacer *placer = new osgParticle::SectorPlacer;
placer->setCenter(8, 0, 10);
placer->setRadiusRange(2.5, 5);
placer->setPhiRange(0, 2 * osg::PI); // 360° angle to make a circle
emitter->setPlacer(placer);
// now let's setup the shooter; we use a RadialShooter but we set the
// initial speed to zero, because we want the particles to fall down
// only under the effect of the gravity force. Since we se the speed
// to zero, there is no need to setup the shooting angles.
osgParticle::RadialShooter *shooter = new osgParticle::RadialShooter;
shooter->setInitialSpeedRange(0, 0);
emitter->setShooter(shooter);
// add the emitter to the scene graph
root->addChild(emitter);
// WELL, we got our particle system and a nice emitter. Now we want to
// simulate the effect of the earth gravity, so first of all we have to
// create a Program. It is a particle processor just like the Emitter
// class, but it allows to modify particle properties *after* they have
// been created.
// The ModularProgram class can be thought as a sequence of operators,
// each one performing some actions on the particles. So, the trick is:
// create the ModularProgram object, create one or more Operator objects,
// add those operators to the ModularProgram, and finally add the
// ModularProgram object to the scene graph.
// NOTE: since the Program objects perform actions after the particles
// have been emitted by one or more Emitter objects, all instances of
// Program (and its descendants) should be placed *after* the instances
// of Emitter objects in the scene graph.
osgParticle::ModularProgram *program = new osgParticle::ModularProgram;
program->setParticleSystem(ps);
// create an operator that simulates the gravity acceleration.
osgParticle::AccelOperator *op1 = new osgParticle::AccelOperator;
op1->setToGravity();
program->addOperator(op1);
// now create a custom operator, we have defined it before (see
// class VortexOperator).
VortexOperator *op2 = new VortexOperator;
op2->setCenter(osg::Vec3(8, 0, 0));
program->addOperator(op2);
// let's add a fluid operator to simulate air friction.
osgParticle::FluidFrictionOperator *op3 = new
osgParticle::FluidFrictionOperator;
op3->setFluidToAir();
program->addOperator(op3);
// add the program to the scene graph
root->addChild(program);
// create a Geode to contain our particle system.
osg::Geode *geode = new osg::Geode;
geode->addDrawable(ps);
// add the geode to the scene graph.
root->addChild(geode);
return ps;
}
//////////////////////////////////////////////////////////////////////////////
// MAIN SCENE GRAPH BUILDING FUNCTION
//////////////////////////////////////////////////////////////////////////////
void build_world(osg::Group *root)
{
// In this function we are going to create two particle systems;
// the first one will be very simple, based mostly on default properties;
// the second one will be a little bit more complex, showing how to
// create custom operators.
// To avoid inserting too much code in a single function, we have
// splitted the work into two functions which accept a Group node as
// parameter, and return a pointer to the particle system they created.
osgParticle::ParticleSystem *ps1 = create_simple_particle_system(root);
osgParticle::ParticleSystem *ps2 = create_complex_particle_system(root);
// Now that the particle systems and all other related objects have been
// created, we have to add an "updater" node to the scene graph. This node
// will react to cull traversal by updating the specified particles system.
osgParticle::ParticleSystemUpdater *psu = new
osgParticle::ParticleSystemUpdater;
psu->addParticleSystem(ps1);
psu->addParticleSystem(ps2);
// add the updater node to the scene graph
root->addChild(psu);
}
void build_witness(osg::Group *root, osgViewer::Viewer *viewer)
{
// Box figuration
osg::Box *pBox = new osg::Box(osg::Vec3(0.0f, 0.0f, 0.0f), 3.0f, 3.0f,
3.0f);
//osg::TessellationHints *pHints = new osg::TessellationHints();
//pHints->setDetailRatio(0.5f);
osg::ref_ptr<osg::ShapeDrawable> pDrawable = new
osg::ShapeDrawable(pBox /*, pHints */);
pDrawable->setColor(osg::Vec4(1.0f, 0.5f, 0.5f, 1.0f));
osg::ref_ptr<osg::Geode> pGeode = new osg::Geode();
pGeode->addDrawable(pDrawable.get());
osg::ref_ptr<osg::MatrixTransform> pBoxMT = new osg::MatrixTransform();
pBoxMT->addChild(pGeode.get());
osg::Matrix m;
m.makeIdentity(); m.makeTranslate(osg::Vec3(-5.0f, 0.0f, 0.0f));
pBoxMT->setMatrix(m);
// add the updater node to the scene graph
root->addChild(pBoxMT.get());
}
//////////////////////////////////////////////////////////////////////////////
// main()
//////////////////////////////////////////////////////////////////////////////
int main(int, char **)
{
// construct the viewer.
osgViewer::Viewer viewer;
osg::Group *root = new osg::Group;
build_world(root);
build_witness(root, &viewer);
// add a viewport to the viewer and attach the scene graph.
viewer.setSceneData(root);
// MODIFY here to see the lighting effect ON/OFF both on witness box
and on ParticleSystems
bool lightOn = true;
viewer.getLight()->setDiffuse(true ? osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)
: osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
return viewer.run();
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org