Merged changed to osgParticle from Marco Jez, the changes are (quoted from

email from Marco)

"Most relevant news:
1) particle systems now have the "freezeOnCull" property set to false by
default. Since it is an optimization, and using it may cause some unwanted
behaviors if not handled properly, it makes more sense to turn it off by
default.
2) new "LINE" shape mode which uses GL_LINES to draw line segments that
point to the direction of motion.
3) particles can now have a rotation angle and angular velocity.
4) new AngularAccelOperator applies angular acceleration to particles.
5) particle processors such as emitters and programs can have a "start",
"end" and "reset" time coordinate. For example, an emitter may be instructed
to start emitting particles only after a certain time, stop after another
amount of time and then start again.

Update (2) is from Gideon May.
Updates (3) to (5) are from Douglas A. Pouk."
This commit is contained in:
Robert Osfield
2003-09-02 20:39:41 +00:00
parent 763ee70f2f
commit 4761442005
19 changed files with 607 additions and 84 deletions

View File

@@ -27,7 +27,7 @@ osgParticle::FluidFrictionOperator::FluidFrictionOperator(const FluidFrictionOpe
{
}
void osgParticle::FluidFrictionOperator::operate(Particle *P, double)
void osgParticle::FluidFrictionOperator::operate(Particle *P, double dt)
{
float r = (ovr_rad_ > 0)? ovr_rad_ : P->getRadius();
osg::Vec3 v = P->getVelocity();
@@ -42,7 +42,7 @@ void osgParticle::FluidFrictionOperator::operate(Particle *P, double)
}
// correct unwanted velocity increments
osg::Vec3 dv = Fr * (P->getMassInv() * 0.01);
osg::Vec3 dv = Fr * P->getMassInv() * dt;
float dvl = dv.length();
if (dvl > vm) {
dv *= vm / dvl;

View File

@@ -17,7 +17,7 @@ osgParticle::ModularEmitter::ModularEmitter(const ModularEmitter &copy, const os
{
}
void osgParticle::ModularEmitter::emit(double dt)
void osgParticle::ModularEmitter::emit(double dt)
{
int n = counter_->numParticlesToCreate(dt);
for (int i=0; i<n; ++i) {

View File

@@ -36,6 +36,9 @@ osgParticle::Particle::Particle()
prev_pos_(0, 0, 0),
position_(0, 0, 0),
velocity_(0, 0, 0),
prev_angle_(0, 0, 0),
angle_(0, 0, 0),
angular_vel_(0, 0, 0),
t0_(0),
current_size_(0),
current_alpha_(0)
@@ -75,6 +78,17 @@ bool osgParticle::Particle::update(double dt)
prev_pos_ = position_;
position_ += velocity_ * dt;
// update angle
prev_angle_ = angle_;
angle_ += angular_vel_ * dt;
if (angle_.x() > osg::PI*2) angle_.x() -= osg::PI*2;
if (angle_.x() < -osg::PI*2) angle_.x() += osg::PI*2;
if (angle_.y() > osg::PI*2) angle_.y() -= osg::PI*2;
if (angle_.y() < -osg::PI*2) angle_.y() += osg::PI*2;
if (angle_.z() > osg::PI*2) angle_.z() -= osg::PI*2;
if (angle_.z() < -osg::PI*2) angle_.z() += osg::PI*2;
return true;
}
@@ -85,67 +99,90 @@ void osgParticle::Particle::render(const osg::Vec3 &xpos, const osg::Vec3 &px, c
current_color_.z(),
current_color_.w() * current_alpha_);
osg::Matrix R;
R.makeRotate(
angle_.x(), osg::Vec3(1, 0, 0),
angle_.y(), osg::Vec3(0, 1, 0),
angle_.z(), osg::Vec3(0, 0, 1));
osg::Vec3 p1(px * current_size_ * scale);
osg::Vec3 p2(py * current_size_ * scale);
switch (shape_)
{
case POINT:
glVertex3f(xpos.x(), xpos.y(), xpos.z());
glVertex3f(xpos.x(), xpos.y(), xpos.z());
break;
case QUAD:
glTexCoord2f(0, 0);
glVertex3fv((xpos-p1-p2).ptr());
glVertex3fv((xpos-(p1+p2)*R).ptr());
glTexCoord2f(1, 0);
glVertex3fv((xpos+p1-p2).ptr());
glVertex3fv((xpos+(p1-p2)*R).ptr());
glTexCoord2f(1, 1);
glVertex3fv((xpos+p1+p2).ptr());
glVertex3fv((xpos+(p1+p2)*R).ptr());
glTexCoord2f(0, 1);
glVertex3fv((xpos-p1+p2).ptr());
glVertex3fv((xpos-(p1-p2)*R).ptr());
break;
case QUAD_TRIANGLESTRIP:
// we must glBegin() and glEnd() here, because each particle is a single strip
glPushMatrix();
glTranslatef(xpos.x(), xpos.y(), xpos.z());
glMultMatrixf(R.ptr());
// we must glBegin() and glEnd() here, because each particle is a single strip
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(1, 1);
glVertex3fv((xpos+p1+p2).ptr());
glVertex3fv((p1+p2).ptr());
glTexCoord2f(0, 1);
glVertex3fv((xpos-p1+p2).ptr());
glVertex3fv((-p1+p2).ptr());
glTexCoord2f(1, 0);
glVertex3fv((xpos+p1-p2).ptr());
glVertex3fv((p1-p2).ptr());
glTexCoord2f(0, 0);
glVertex3fv((xpos-p1-p2).ptr());
glVertex3fv((-p1-p2).ptr());
glEnd();
glPopMatrix();
break;
case HEXAGON:
glPushMatrix();
glTranslatef(xpos.x(), xpos.y(), xpos.z());
glMultMatrixf(R.ptr());
// we must glBegin() and glEnd() here, because each particle is a single fan
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0.5f, 0.5f);
glVertex3fv(xpos.ptr());
glVertex3f(0,0,0);
glTexCoord2f(hex_texcoord_x1, hex_texcoord_y1);
glVertex3fv((xpos+p1*cosPI3+p2*sinPI3).ptr());
//glVertex3f(xpos.x() + cs * cosPI3, xpos.y() + cs * sinPI3, xpos.z());
glVertex3fv((p1*cosPI3+p2*sinPI3).ptr());
glTexCoord2f(hex_texcoord_x2, hex_texcoord_y1);
glVertex3fv((xpos-p1*cosPI3+p2*sinPI3).ptr());
//glVertex3f(xpos.x() - cs * cosPI3, xpos.y() + cs * sinPI3, xpos.z());
glVertex3fv((-p1*cosPI3+p2*sinPI3).ptr());
glTexCoord2f(0, 0.5f);
glVertex3fv((xpos-p1).ptr());
//glVertex3f(xpos.x() - cs, xpos.y(), xpos.z());
glVertex3fv((-p1).ptr());
glTexCoord2f(hex_texcoord_x2, hex_texcoord_y2);
glVertex3fv((xpos-p1*cosPI3-p2*sinPI3).ptr());
//glVertex3f(xpos.x() - cs * cosPI3, xpos.y() - cs * sinPI3, xpos.z());
glVertex3fv((-p1*cosPI3-p2*sinPI3).ptr());
glTexCoord2f(hex_texcoord_x1, hex_texcoord_y2);
glVertex3fv((xpos+p1*cosPI3-p2*sinPI3).ptr());
//glVertex3f(xpos.x() + cs * cosPI3, xpos.y() - cs * sinPI3, xpos.z());
glVertex3fv((p1*cosPI3-p2*sinPI3).ptr());
glTexCoord2f(1, 0.5f);
glVertex3fv((xpos+p1).ptr());
//glVertex3f(xpos.x() + cs, xpos.y(), xpos.z());
glVertex3fv((p1).ptr());
glTexCoord2f(hex_texcoord_x1, hex_texcoord_y1);
glVertex3fv((xpos+p1*cosPI3+p2*sinPI3).ptr());
//glVertex3f(xpos.x() + cs * cosPI3, xpos.y() + cs * sinPI3, xpos.z());
glVertex3fv((p1*cosPI3+p2*sinPI3).ptr());
glEnd();
glPopMatrix();
break;
case LINE:
{
// Get the normalized direction of the particle, to be used in the
// calculation of one of the linesegment endpoints.
float vl = velocity_.length();
if (vl != 0) {
osg::Vec3 v = velocity_ * current_size_ * scale / vl;
glTexCoord1f(0);
glVertex3f(xpos.x(), xpos.y(), xpos.z());
glTexCoord1f(1);
glVertex3f(xpos.x() + v.x(), xpos.y() + v.y(), xpos.z() + v.z());
}
}
break;
default:

View File

@@ -19,7 +19,12 @@ osgParticle::ParticleProcessor::ParticleProcessor()
ps_(0),
need_ltw_matrix_(false),
need_wtl_matrix_(false),
current_nodevisitor_(0)
current_nodevisitor_(0),
endless_(true),
lifeTime_(0.0),
startTime_(0.0),
currentTime_(0.0),
resetTime_(0.0)
{
setCullingActive(false);
}
@@ -32,65 +37,84 @@ osgParticle::ParticleProcessor::ParticleProcessor(const ParticleProcessor &copy,
ps_(static_cast<ParticleSystem *>(copyop(copy.ps_.get()))),
need_ltw_matrix_(copy.need_ltw_matrix_),
need_wtl_matrix_(copy.need_wtl_matrix_),
current_nodevisitor_(0)
current_nodevisitor_(0),
endless_(copy.endless_),
lifeTime_(copy.lifeTime_),
startTime_(copy.startTime_),
currentTime_(copy.currentTime_),
resetTime_(copy.resetTime_)
{
}
void osgParticle::ParticleProcessor::traverse(osg::NodeVisitor &nv)
{
// continue only if enabled
if (enabled_ )
{
// typecast the NodeVisitor to CullVisitor
osgUtil::CullVisitor *cv = dynamic_cast<osgUtil::CullVisitor *>(&nv);
// typecast the NodeVisitor to CullVisitor
osgUtil::CullVisitor *cv = dynamic_cast<osgUtil::CullVisitor *>(&nv);
// continue only if the visitor actually is a cull visitor
if (cv) {
// continue only if the visitor actually is a cull visitor
if (cv) {
// continue only if the particle system is valid
if (ps_.valid())
{
// continue only if the particle system is valid
if (ps_.valid())
if (nv.getFrameStamp())
{
if (nv.getFrameStamp())
{
// retrieve the current time
double t = nv.getFrameStamp()->getReferenceTime();
// retrieve the current time
double t = nv.getFrameStamp()->getReferenceTime();
// reset this processor if we've reached the reset point
if ((currentTime_ >= resetTime_) && (resetTime_ > 0)) {
currentTime_ = 0;
t0_ = -1;
}
// skip if we haven't initialized t0_ yet
if (t0_ != -1) {
// skip if we haven't initialized t0_ yet
if (t0_ != -1) {
// check whether the particle system is frozen/culled
if (!ps_->isFrozen() && (ps_->getLastFrameNumber() >= (nv.getFrameStamp()->getFrameNumber() - 1) || !ps_->getFreezeOnCull())) {
// check whether the processor is alive
bool alive = false;
if (currentTime_ >= startTime_) {
if (endless_ || (currentTime_ < (startTime_ + lifeTime_)))
alive = true;
}
// initialize matrix flags
need_ltw_matrix_ = true;
need_wtl_matrix_ = true;
current_nodevisitor_ = &nv;
// update current time
currentTime_ += t - t0_;
// do some process (unimplemented in this base class)
process(t - t0_);
}
// process only if the particle system is not frozen/culled
if (alive &&
enabled_ &&
!ps_->isFrozen() &&
(ps_->getLastFrameNumber() >= (nv.getFrameStamp()->getFrameNumber() - 1) || !ps_->getFreezeOnCull())) {
// initialize matrix flags
need_ltw_matrix_ = true;
need_wtl_matrix_ = true;
current_nodevisitor_ = &nv;
// do some process (unimplemented in this base class)
process(t - t0_);
}
// update t0_
t0_ = t;
}
else
{
osg::notify(osg::WARN) << "osgParticle::ParticleProcessor::traverse(NodeVisitor&) requires a valid FrameStamp to function, particles not updated.\n";
}
} else
{
osg::notify(osg::WARN) << "ParticleProcessor \"" << getName() << "\": invalid particle system\n";
// update t0_
t0_ = t;
}
else
{
osg::notify(osg::WARN) << "osgParticle::ParticleProcessor::traverse(NodeVisitor&) requires a valid FrameStamp to function, particles not updated.\n";
}
} else
{
osg::notify(osg::WARN) << "ParticleProcessor \"" << getName() << "\": invalid particle system\n";
}
}
// call the inherited method
Node::traverse(nv);
}

View File

@@ -30,7 +30,7 @@ osgParticle::ParticleSystem::ParticleSystem()
bounds_computed_(false),
def_ptemp_(Particle()),
last_frame_(0),
freeze_on_cull_(true),
freeze_on_cull_(false),
detail_(1),
draw_count_(0)
{

View File

@@ -68,11 +68,11 @@ DataInputStream::DataInputStream(std::istream* istream){
DataInputStream::~DataInputStream(){}
bool DataInputStream::readBool(){
bool b;
_istream->read((char*)&b, BOOLSIZE);
char c;
_istream->read(&c, CHARSIZE);
if (_istream->rdstate() & _istream->failbit)
throw Exception("DataInputStream::readBool(): Failed to read boolean value.");
return b;
return c;
}
char DataInputStream::readChar(){

View File

@@ -58,8 +58,10 @@ DataOutputStream::DataOutputStream(std::ostream * ostream){
DataOutputStream::~DataOutputStream(){}
void DataOutputStream::writeBool(bool b){
_ostream->write((char*)&b, BOOLSIZE);
void DataOutputStream::writeBool(bool b)
{
char c = b;
_ostream->write(&c, CHARSIZE);
}
void DataOutputStream::writeChar(char c){

View File

@@ -3,6 +3,7 @@ include $(TOPDIR)/Make/makedefs
CXXFILES =\
IO_AccelOperator.cpp\
IO_AngularAccelOperator.cpp\
IO_CenteredPlacer.cpp\
IO_Emitter.cpp\
IO_FluidFrictionOperator.cpp\

View File

@@ -0,0 +1,48 @@
#include <osgParticle/AngularAccelOperator>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osg/Vec3>
#include <iostream>
bool AngularAccelOperator_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool AngularAccelOperator_writeLocalData(const osg::Object &obj, osgDB::Output &fw);
osgDB::RegisterDotOsgWrapperProxy AngularAccelOperator_Proxy
(
new osgParticle::AngularAccelOperator,
"AngularAccelOperator",
"Object Operator AngularAccelOperator",
AngularAccelOperator_readLocalData,
AngularAccelOperator_writeLocalData
);
bool AngularAccelOperator_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
osgParticle::AngularAccelOperator &aop = static_cast<osgParticle::AngularAccelOperator &>(obj);
bool itAdvanced = false;
osg::Vec3 a;
if (fr[0].matchWord("angularAcceleration")) {
if (fr[1].getFloat(a.x()) && fr[2].getFloat(a.y()) && fr[3].getFloat(a.z())) {
aop.setAngularAcceleration(a);
fr += 4;
itAdvanced = true;
}
}
return itAdvanced;
}
bool AngularAccelOperator_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
const osgParticle::AngularAccelOperator &aop = static_cast<const osgParticle::AngularAccelOperator &>(obj);
osg::Vec3 a = aop.getAngularAcceleration();
fw.indent() << "angularAcceleration " << a.x() << " " << a.y() << " " << a.z() << std::endl;
return true;
}

View File

@@ -32,6 +32,8 @@ bool read_particle(osgDB::Input &fr, osgParticle::Particle &P)
P.setShape(osgParticle::Particle::POINT);
} else if (std::string(ptstr) == "QUAD_TRIANGLESTRIP") {
P.setShape(osgParticle::Particle::QUAD_TRIANGLESTRIP);
} else if (std::string(ptstr) == "LINE") {
P.setShape(osgParticle::Particle::LINE);
} else {
osg::notify(osg::WARN) << "Particle reader warning: invalid shape: " << ptstr << std::endl;
}
@@ -87,6 +89,22 @@ bool read_particle(osgDB::Input &fr, osgParticle::Particle &P)
fr += 4;
itAdvanced = true;
}
}
if (fr[0].matchWord("angle")) {
osg::Vec3 v;
if (fr[1].getFloat(v.x()) && fr[2].getFloat(v.y()) && fr[3].getFloat(v.z())) {
P.setAngle(v);
fr += 4;
itAdvanced = true;
}
}
if (fr[0].matchWord("angularVelocity")) {
osg::Vec3 v;
if (fr[1].getFloat(v.x()) && fr[2].getFloat(v.y()) && fr[3].getFloat(v.z())) {
P.setAngularVelocity(v);
fr += 4;
itAdvanced = true;
}
}
if (fr[0].matchWord("radius")) {
float f;
@@ -152,8 +170,9 @@ void write_particle(const osgParticle::Particle &P, osgDB::Output &fw)
case osgParticle::Particle::POINT: fw << "POINT" << std::endl; break;
case osgParticle::Particle::HEXAGON: fw << "HEXAGON" << std::endl; break;
case osgParticle::Particle::QUAD_TRIANGLESTRIP: fw << "QUAD_TRIANGLESTRIP" << std::endl; break;
case osgParticle::Particle::QUAD:
default: fw << "QUAD" << std::endl; break;
case osgParticle::Particle::QUAD: fw << "QUAD" << std::endl; break;
case osgParticle::Particle::LINE:
default: fw << "LINE" << std::endl; break;
}
fw.indent() << "lifeTime " << P.getLifeTime() << std::endl;
@@ -177,8 +196,16 @@ void write_particle(const osgParticle::Particle &P, osgDB::Output &fw)
fw.indent() << "velocity ";
fw << v.x() << " " << v.y() << " " << v.z() << std::endl;
fw.indent() << "mass " << P.getMass() << std::endl;
v = P.getAngle();
fw.indent() << "angle ";
fw << v.x() << " " << v.y() << " " << v.z() << std::endl;
v = P.getAngularVelocity();
fw.indent() << "angularVelocity ";
fw << v.x() << " " << v.y() << " " << v.z() << std::endl;
fw.indent() << "radius " << P.getRadius() << std::endl;
fw.indent() << "mass " << P.getMass() << std::endl;
// interpolators

View File

@@ -63,6 +63,54 @@ bool ParticleProcessor_readLocalData(osg::Object &obj, osgDB::Input &fr)
}
}
if (fr[0].matchWord("endless")) {
if (fr[1].matchWord("TRUE")) {
myobj.setEndless(true);
fr += 2;
itAdvanced = true;
} else if (fr[1].matchWord("FALSE")) {
myobj.setEndless(false);
fr += 2;
itAdvanced = true;
}
}
if (fr[0].matchWord("lifeTime")) {
float lt;
if (fr[1].getFloat(lt)) {
myobj.setLifeTime(lt);
fr += 2;
itAdvanced = true;
}
}
if (fr[0].matchWord("startTime")) {
float st;
if (fr[1].getFloat(st)) {
myobj.setStartTime(st);
fr += 2;
itAdvanced = true;
}
}
if (fr[0].matchWord("currentTime")) {
float ct;
if (fr[1].getFloat(ct)) {
myobj.setCurrentTime(ct);
fr += 2;
itAdvanced = true;
}
}
if (fr[0].matchWord("resetTime")) {
float ct;
if (fr[1].getFloat(ct)) {
myobj.setResetTime(ct);
fr += 2;
itAdvanced = true;
}
}
return itAdvanced;
}
@@ -89,5 +137,16 @@ bool ParticleProcessor_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
fw << "RELATIVE_TO_PARENTS" << std::endl;
}
fw.indent() << "endless ";
if (myobj.isEndless())
fw << "TRUE" << std::endl;
else
fw << "FALSE" << std::endl;
fw.indent() << "lifeTime " << myobj.getLifeTime() << std::endl;
fw.indent() << "startTime " << myobj.getStartTime() << std::endl;
fw.indent() << "currentTime " << myobj.getCurrentTime() << std::endl;
fw.indent() << "resetTime " << myobj.getResetTime() << std::endl;
return true;
}

View File

@@ -49,6 +49,17 @@ bool RadialShooter_readLocalData(osg::Object &obj, osgDB::Input &fr)
}
}
if (fr[0].matchWord("initialRotationalSpeedRange")) {
osg::Vec3 r1;
osg::Vec3 r2;
if (fr[1].getFloat(r1.x()) && fr[2].getFloat(r1.y()) && fr[3].getFloat(r1.z()) && \
fr[4].getFloat(r2.x()) && fr[5].getFloat(r2.y()) && fr[6].getFloat(r2.z())) {
myobj.setInitialRotationalSpeedRange(r1,r2);
fr += 7;
itAdvanced = true;
}
}
return itAdvanced;
}
@@ -63,6 +74,13 @@ bool RadialShooter_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
fw.indent() << "phiRange " << r.minimum << " " << r.maximum << std::endl;
r = myobj.getInitialSpeedRange();
fw.indent() << "initialSpeedRange " << r.minimum << " " << r.maximum << std::endl;
osgParticle::rangev3 rv = myobj.getInitialRotationalSpeedRange();
osg::Vec3 v1 = rv.minimum;
osg::Vec3 v2 = rv.maximum;
fw.indent() << "initialRotationalSpeedRange ";
fw << v1.x() << " " << v1.y() << " " << v1.z() << " ";
fw << v2.x() << " " << v2.y() << " " << v2.z() << std::endl;
return true;
}