Hi Jannik,
I have rearranged the if statement to try and make it a bit more readable,
I've also unified the two similar if statements in the
ParticleProcessor.cpp and PartileSystemUpdater.cpp. Files attached, and
diff below (I had to revert my git diff.tool setting to get this:-) Could
you test this on your system to see if it works OK.
As a general note, it seems to me that if a ParticleSystem in a previous
frame is still being rendered then osgParticle shouldn't be updating them.
I have just checked and there isn't a
ParticleSystem::setDataVariance(osg::Object::DYNAMIC) which is technically
a bug as it doesn't double buffer it's data, it does have a Mutex which
will be avoiding the most obvious race condition but design wise it's a bit
dubious. I'm not the original author of this code, and it's pretty old so
not really a great example of how you'd code something in the OSG if you
were to write it today, so I'm not 100% comfortable or happy with changing
things around.
Let me know what you think of the revisions.
Robert.
$ git diff
diff --git a/src/osgParticle/ParticleProcessor.cpp
b/src/osgParticle/ParticleProcessor.cpp
index c8ba61b..d0e7e53 100644
--- a/src/osgParticle/ParticleProcessor.cpp
+++ b/src/osgParticle/ParticleProcessor.cpp
@@ -99,10 +99,12 @@ void
osgParticle::ParticleProcessor::traverse(osg::NodeVisitor& nv)
_currentTime += t - _t0;
// process only if the particle system is not
frozen/culled
+ // We need to allow at least 2 frames difference,
because the particle system's lastFrameNumber
+ // is updated in the draw thread which may not
have completed yet.
if (alive &&
_enabled &&
!_ps->isFrozen() &&
- ((_ps->getLastFrameNumber()+1) >=
(nv.getFrameStamp()->getFrameNumber()) || !_ps->getFreezeOnCull()))
+ (!_ps->getFreezeOnCull() ||
((nv.getFrameStamp()->getFrameNumber()-_ps->getLastFrameNumber()) <= 2)) )
{
// initialize matrix flags
_need_ltw_matrix = true;
diff --git a/src/osgParticle/ParticleSystemUpdater.cpp
b/src/osgParticle/ParticleSystemUpdater.cpp
index e2aeef7..662df3e 100644
--- a/src/osgParticle/ParticleSystemUpdater.cpp
+++ b/src/osgParticle/ParticleSystemUpdater.cpp
@@ -41,7 +41,10 @@ void
osgParticle::ParticleSystemUpdater::traverse(osg::NodeVisitor& nv)
ParticleSystem::ScopedWriteLock
lock(*(ps->getReadWriteMutex()));
- if (!ps->isFrozen() && (ps->getLastFrameNumber()
>= (nv.getFrameStamp()->getFrameNumber() - 1) || !ps->getFreezeOnCull()))
+ // We need to allow at least 2 frames difference,
because the particle system's lastFrameNumber
+ // is updated in the draw thread which may not
have completed yet.
+ if (!ps->isFrozen() &&
+ (!_ps->getFreezeOnCull() ||
((nv.getFrameStamp()->getFrameNumber()-_ps->getLastFrameNumber()) <= 2)) )
{
ps->update(t - _t0, nv);
}
#include <osgParticle/ParticleSystemUpdater>
#include <osg/CopyOp>
#include <osg/Geode>
using namespace osg;
osgParticle::ParticleSystemUpdater::ParticleSystemUpdater()
: osg::Node(), _t0(-1), _frameNumber(0)
{
setCullingActive(false);
}
osgParticle::ParticleSystemUpdater::ParticleSystemUpdater(const ParticleSystemUpdater& copy, const osg::CopyOp& copyop)
: osg::Node(copy, copyop), _t0(copy._t0), _frameNumber(0)
{
ParticleSystem_Vector::const_iterator i;
for (i=copy._psv.begin(); i!=copy._psv.end(); ++i) {
_psv.push_back(static_cast<ParticleSystem* >(copyop(i->get())));
}
}
void osgParticle::ParticleSystemUpdater::traverse(osg::NodeVisitor& nv)
{
osgUtil::CullVisitor* cv = nv.asCullVisitor();
if (cv)
{
if (nv.getFrameStamp())
{
if( _frameNumber < nv.getFrameStamp()->getFrameNumber())
{
_frameNumber = nv.getFrameStamp()->getFrameNumber();
double t = nv.getFrameStamp()->getSimulationTime();
if (_t0 != -1.0)
{
ParticleSystem_Vector::iterator i;
for (i=_psv.begin(); i!=_psv.end(); ++i)
{
ParticleSystem* ps = i->get();
ParticleSystem::ScopedWriteLock lock(*(ps->getReadWriteMutex()));
// We need to allow at least 2 frames difference, because the particle system's lastFrameNumber
// is updated in the draw thread which may not have completed yet.
if (!ps->isFrozen() &&
(!_ps->getFreezeOnCull() || ((nv.getFrameStamp()->getFrameNumber()-_ps->getLastFrameNumber()) <= 2)) )
{
ps->update(t - _t0, nv);
}
}
}
_t0 = t;
}
}
else
{
OSG_WARN << "osgParticle::ParticleSystemUpdater::traverse(NodeVisitor&) requires a valid FrameStamp to function, particles not updated.\n";
}
}
Node::traverse(nv);
}
osg::BoundingSphere osgParticle::ParticleSystemUpdater::computeBound() const
{
return osg::BoundingSphere();
}
bool osgParticle::ParticleSystemUpdater::addParticleSystem(ParticleSystem* ps)
{
_psv.push_back(ps);
return true;
}
bool osgParticle::ParticleSystemUpdater::removeParticleSystem(ParticleSystem* ps)
{
unsigned int i = getParticleSystemIndex( ps );
if( i >= _psv.size() ) return false;
removeParticleSystem( i );
return true;
}
bool osgParticle::ParticleSystemUpdater::removeParticleSystem(unsigned int pos, unsigned int numParticleSystemsToRemove)
{
if( (pos < _psv.size()) && (numParticleSystemsToRemove > 0) )
{
unsigned int endOfRemoveRange = pos + numParticleSystemsToRemove;
if( endOfRemoveRange > _psv.size() )
{
OSG_DEBUG<<"Warning: ParticleSystem::removeParticleSystem(i,numParticleSystemsToRemove) has been passed an excessive number"<<std::endl;
OSG_DEBUG<<" of ParticleSystems to remove, trimming just to end of ParticleSystem list."<<std::endl;
endOfRemoveRange = _psv.size();
}
_psv.erase(_psv.begin()+pos, _psv.begin()+endOfRemoveRange);
return true;
}
return false;
}
bool osgParticle::ParticleSystemUpdater::replaceParticleSystem( ParticleSystem* origPS, ParticleSystem* newPS )
{
if( (newPS == NULL) || (origPS == newPS) ) return false;
unsigned int pos = getParticleSystemIndex( origPS );
if( pos < _psv.size() )
{
return setParticleSystem( pos, newPS );
}
return false;
}
bool osgParticle::ParticleSystemUpdater::setParticleSystem( unsigned int i, ParticleSystem* ps )
{
if( (i < _psv.size()) && ps )
{
_psv[i] = ps;
return true;
}
return false;
}
#include <osgParticle/ParticleSystem>
#include <vector>
#include <osg/Drawable>
#include <osg/CopyOp>
#include <osg/State>
#include <osg/Matrix>
#include <osg/GL>
#include <osg/StateSet>
#include <osg/Texture2D>
#include <osg/BlendFunc>
#include <osg/TexEnv>
#include <osg/Material>
#include <osg/PointSprite>
#include <osg/Program>
#include <osg/Notify>
#include <osg/io_utils>
#include <osgDB/FileUtils>
#include <osgDB/ReadFile>
#include <osgUtil/CullVisitor>
#define USE_LOCAL_SHADERS
static double distance(const osg::Vec3& coord, const osg::Matrix& matrix)
{
// copied from CullVisitor.cpp
return -(coord[0]*matrix(0,2)+coord[1]*matrix(1,2)+coord[2]*matrix(2,2)+matrix(3,2));
}
osgParticle::ParticleSystem::ParticleSystem()
: osg::Drawable(),
_def_bbox(osg::Vec3(-10, -10, -10), osg::Vec3(10, 10, 10)),
_alignment(BILLBOARD),
_align_X_axis(1, 0, 0),
_align_Y_axis(0, 1, 0),
_particleScaleReferenceFrame(WORLD_COORDINATES),
_useVertexArray(false),
_useShaders(false),
_dirty_uniforms(false),
_doublepass(false),
_frozen(false),
_bmin(0, 0, 0),
_bmax(0, 0, 0),
_reset_bounds_flag(false),
_bounds_computed(false),
_def_ptemp(Particle()),
_last_frame(0),
_dirty_dt(true),
_freeze_on_cull(false),
_t0(0.0),
_dt(0.0),
_detail(1),
_sortMode(NO_SORT),
_visibilityDistance(-1.0),
_draw_count(0)
{
// we don't support display lists because particle systems
// are dynamic, and they always changes between frames
setSupportsDisplayList(false);
}
osgParticle::ParticleSystem::ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop)
: osg::Drawable(copy, copyop),
_def_bbox(copy._def_bbox),
_alignment(copy._alignment),
_align_X_axis(copy._align_X_axis),
_align_Y_axis(copy._align_Y_axis),
_particleScaleReferenceFrame(copy._particleScaleReferenceFrame),
_useVertexArray(copy._useVertexArray),
_useShaders(copy._useShaders),
_dirty_uniforms(copy._dirty_uniforms),
_doublepass(copy._doublepass),
_frozen(copy._frozen),
_bmin(copy._bmin),
_bmax(copy._bmax),
_reset_bounds_flag(copy._reset_bounds_flag),
_bounds_computed(copy._bounds_computed),
_def_ptemp(copy._def_ptemp),
_last_frame(copy._last_frame),
_dirty_dt(copy._dirty_dt),
_freeze_on_cull(copy._freeze_on_cull),
_t0(copy._t0),
_dt(copy._dt),
_detail(copy._detail),
_sortMode(copy._sortMode),
_visibilityDistance(copy._visibilityDistance),
_draw_count(0)
{
}
osgParticle::ParticleSystem::~ParticleSystem()
{
}
void osgParticle::ParticleSystem::update(double dt, osg::NodeVisitor& nv)
{
// reset bounds
_reset_bounds_flag = true;
if (_useShaders)
{
// Update shader uniforms
// This slightly reduces the consumption of traversing the particle vector, because we
// don't compute tile and angle attributes that are useleff for shaders.
// At present, our lcoal shader implementation will ignore these particle props:
// _cur_tile, _s_coord, _t_coord, _prev_pos, _prev_angle and _angle
osg::StateSet* stateset = getOrCreateStateSet();
if (_dirty_uniforms)
{
osg::Uniform* u_vd = stateset->getUniform("visibilityDistance");
if (u_vd) u_vd->set((float)_visibilityDistance);
_dirty_uniforms = false;
}
}
for(unsigned int i=0; i<_particles.size(); ++i)
{
Particle& particle = _particles[i];
if (particle.isAlive())
{
if (particle.update(dt, _useShaders))
{
update_bounds(particle.getPosition(), particle.getCurrentSize());
}
else
{
reuseParticle(i);
}
}
}
if (_sortMode != NO_SORT)
{
// sort particles
osgUtil::CullVisitor* cv = nv.asCullVisitor();
if (cv)
{
osg::Matrixd modelview = *(cv->getModelViewMatrix());
double scale = (_sortMode==SORT_FRONT_TO_BACK ? -1.0 : 1.0);
double deadDistance = DBL_MAX;
for (unsigned int i=0; i<_particles.size(); ++i)
{
Particle& particle = _particles[i];
if (particle.isAlive())
particle.setDepth(distance(particle.getPosition(), modelview) * scale);
else
particle.setDepth(deadDistance);
}
std::sort<Particle_vector::iterator>(_particles.begin(), _particles.end());
// Repopulate the death stack as it will have been invalidated by the sort.
unsigned int numDead = _deadparts.size();
if (numDead>0)
{
// clear the death stack
_deadparts = Death_stack();
// copy the tail of the _particles vector as this will contain all the dead Particle thanks to the depth sort against DBL_MAX
Particle* first_dead_ptr = &_particles[_particles.size()-numDead];
Particle* last_dead_ptr = &_particles[_particles.size()-1];
for(Particle* dead_ptr = first_dead_ptr; dead_ptr<=last_dead_ptr; ++dead_ptr)
{
_deadparts.push(dead_ptr);
}
}
}
}
// force recomputing of bounding box on next frame
dirtyBound();
}
void osgParticle::ParticleSystem::drawImplementation(osg::RenderInfo& renderInfo) const
{
osg::State& state = *renderInfo.getState();
ScopedReadLock lock(_readWriteMutex);
// update the frame count, so other objects can detect when
// this particle system is culled
_last_frame = state.getFrameStamp()->getFrameNumber();
// update the dirty flag of delta time, so next time a new request for delta time
// will automatically cause recomputing
_dirty_dt = true;
// get the current modelview matrix
osg::Matrix modelview = state.getModelViewMatrix();
// set up depth mask for first rendering pass
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
glPushAttrib(GL_DEPTH_BUFFER_BIT);
#endif
glDepthMask(GL_FALSE);
// render, first pass
if (_useVertexArray)
render_vertex_array(renderInfo);
else
single_pass_render(renderInfo, modelview);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
// restore depth mask settings
glPopAttrib();
#endif
// render, second pass
if (_doublepass) {
// set up color mask for second rendering pass
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
glPushAttrib(GL_COLOR_BUFFER_BIT);
#endif
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// render the particles onto the depth buffer
if (_useVertexArray)
render_vertex_array(renderInfo);
else
single_pass_render(renderInfo, modelview);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
// restore color mask settings
glPopAttrib();
#endif
}
#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
OSG_NOTICE<<"Warning: ParticleSystem::drawImplementation(..) not fully implemented."<<std::endl;
#endif
}
void osgParticle::ParticleSystem::setDefaultAttributes(const std::string& texturefile, bool emissive_particles, bool lighting, int texture_unit)
{
osg::StateSet *stateset = new osg::StateSet;
stateset->setMode(GL_LIGHTING, lighting? osg::StateAttribute::ON: osg::StateAttribute::OFF);
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::Material *material = new osg::Material;
material->setSpecular(osg::Material::FRONT, osg::Vec4(0, 0, 0, 1));
material->setEmission(osg::Material::FRONT, osg::Vec4(0, 0, 0, 1));
material->setColorMode(lighting? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF);
stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
if (!texturefile.empty()) {
osg::Texture2D *texture = new osg::Texture2D;
texture->setImage(osgDB::readRefImageFile(texturefile));
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::MIRROR);
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::MIRROR);
stateset->setTextureAttributeAndModes(texture_unit, texture, osg::StateAttribute::ON);
osg::TexEnv *texenv = new osg::TexEnv;
texenv->setMode(osg::TexEnv::MODULATE);
stateset->setTextureAttribute(texture_unit, texenv);
}
osg::BlendFunc *blend = new osg::BlendFunc;
if (emissive_particles) {
blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
} else {
blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
}
stateset->setAttributeAndModes(blend, osg::StateAttribute::ON);
setStateSet(stateset);
setUseVertexArray(false);
setUseShaders(false);
}
void osgParticle::ParticleSystem::setDefaultAttributesUsingShaders(const std::string& texturefile, bool emissive_particles, int texture_unit)
{
osg::StateSet *stateset = new osg::StateSet;
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::PointSprite *sprite = new osg::PointSprite;
stateset->setTextureAttributeAndModes(texture_unit, sprite, osg::StateAttribute::ON);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
stateset->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON);
#else
OSG_NOTICE<<"Warning: ParticleSystem::setDefaultAttributesUsingShaders(..) not fully implemented."<<std::endl;
#endif
if (!texturefile.empty())
{
osg::Texture2D *texture = new osg::Texture2D;
texture->setImage(osgDB::readRefImageFile(texturefile));
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::MIRROR);
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::MIRROR);
stateset->setTextureAttributeAndModes(texture_unit, texture, osg::StateAttribute::ON);
}
osg::BlendFunc *blend = new osg::BlendFunc;
if (emissive_particles)
{
blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
}
else
{
blend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
}
stateset->setAttributeAndModes(blend, osg::StateAttribute::ON);
osg::Program *program = new osg::Program;
#ifdef USE_LOCAL_SHADERS
char vertexShaderSource[] =
"uniform float visibilityDistance;\n"
"varying vec3 basic_prop;\n"
"\n"
"void main(void)\n"
"{\n"
" basic_prop = gl_MultiTexCoord0.xyz;\n"
" \n"
" vec4 ecPos = gl_ModelViewMatrix * gl_Vertex;\n"
" float ecDepth = -ecPos.z;\n"
" \n"
" if (visibilityDistance > 0.0)\n"
" {\n"
" if (ecDepth <= 0.0 || ecDepth >= visibilityDistance)\n"
" basic_prop.x = -1.0;\n"
" }\n"
" \n"
" gl_Position = ftransform();\n"
" gl_ClipVertex = ecPos;\n"
" \n"
" vec4 color = gl_Color;\n"
" color.a *= basic_prop.z;\n"
" gl_FrontColor = color;\n"
" gl_BackColor = gl_FrontColor;\n"
"}\n";
char fragmentShaderSource[] =
"uniform sampler2D baseTexture;\n"
"varying vec3 basic_prop;\n"
"\n"
"void main(void)\n"
"{\n"
" if (basic_prop.x < 0.0) discard;\n"
" gl_FragColor = gl_Color * texture2D(baseTexture, gl_TexCoord[0].xy);\n"
"}\n";
program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
#else
program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/particle.vert")));
program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/particle.frag")));
#endif
stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
stateset->addUniform(new osg::Uniform("visibilityDistance", (float)_visibilityDistance));
stateset->addUniform(new osg::Uniform("baseTexture", texture_unit));
setStateSet(stateset);
setUseVertexArray(true);
setUseShaders(true);
}
void osgParticle::ParticleSystem::single_pass_render(osg::RenderInfo& renderInfo, const osg::Matrix& modelview) const
{
_draw_count = 0;
if (_particles.size() <= 0) return;
osg::GLBeginEndAdapter* gl = &(renderInfo.getState()->getGLBeginEndAdapter());
float scale = sqrtf(static_cast<float>(_detail));
osg::Vec3 xAxis = _align_X_axis;
osg::Vec3 yAxis = _align_Y_axis;
osg::Vec3 scaled_aligned_xAxis = _align_X_axis;
osg::Vec3 scaled_aligned_yAxis = _align_Y_axis;
float xScale = 1.0f;
float yScale = 1.0f;
if (_alignment==BILLBOARD)
{
xAxis = osg::Matrix::transform3x3(modelview,_align_X_axis);
yAxis = osg::Matrix::transform3x3(modelview,_align_Y_axis);
float lengthX2 = xAxis.length2();
float lengthY2 = yAxis.length2();
if (_particleScaleReferenceFrame==LOCAL_COORDINATES)
{
xScale = 1.0f/sqrtf(lengthX2);
yScale = 1.0f/sqrtf(lengthY2);
}
else
{
xScale = 1.0f/lengthX2;
yScale = 1.0f/lengthY2;
}
scaled_aligned_xAxis *= xScale;
scaled_aligned_yAxis *= yScale;
xAxis *= xScale;
yAxis *= yScale;
}
bool requiresEndRender = false;
const Particle* startParticle = &_particles[0];
if (startParticle->getShape() != Particle::USER)
{
startParticle->beginRender(gl);
requiresEndRender = true;
}
else
{
// Enable writing depth mask when drawing user-defined particles
glDepthMask(GL_TRUE);
}
for(unsigned int i=0; i<_particles.size(); i+=_detail)
{
const Particle* currentParticle = &_particles[i];
bool insideDistance = true;
if (_sortMode != NO_SORT && _visibilityDistance>0.0)
insideDistance = (currentParticle->getDepth()>=0.0 && currentParticle->getDepth()<=_visibilityDistance);
if (currentParticle->isAlive() && insideDistance)
{
if (currentParticle->getShape() != startParticle->getShape())
{
startParticle->endRender(gl);
startParticle = currentParticle;
if (currentParticle->getShape() != Particle::USER)
{
currentParticle->beginRender(gl);
requiresEndRender = true;
glDepthMask(GL_FALSE);
}
else
glDepthMask(GL_TRUE);
}
++_draw_count;
if (currentParticle->getShape() == Particle::USER)
{
if (requiresEndRender)
{
startParticle->endRender(gl);
requiresEndRender = false;
}
currentParticle->render(renderInfo, currentParticle->getPosition(), currentParticle->getAngle());
continue;
}
const osg::Vec3& angle = currentParticle->getAngle();
bool requiresRotation = (angle.x()!=0.0f || angle.y()!=0.0f || angle.z()!=0.0f);
if (requiresRotation)
{
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));
if (_alignment==BILLBOARD)
{
xAxis = osg::Matrix::transform3x3(R,scaled_aligned_xAxis);
xAxis = osg::Matrix::transform3x3(modelview,xAxis);
yAxis = osg::Matrix::transform3x3(R,scaled_aligned_yAxis);
yAxis = osg::Matrix::transform3x3(modelview,yAxis);
currentParticle->render(gl,currentParticle->getPosition(), xAxis, yAxis, scale);
}
else
{
xAxis = osg::Matrix::transform3x3(R, scaled_aligned_xAxis);
yAxis = osg::Matrix::transform3x3(R, scaled_aligned_yAxis);
currentParticle->render(gl,currentParticle->getPosition(), xAxis, yAxis, scale);
}
}
else
{
currentParticle->render(gl,currentParticle->getPosition(), xAxis, yAxis, scale);
}
}
}
if (requiresEndRender)
startParticle->endRender(gl);
}
void osgParticle::ParticleSystem::render_vertex_array(osg::RenderInfo& renderInfo) const
{
if (_particles.size() <= 0) return;
// Compute the pointer and offsets
Particle_vector::const_iterator itr = _particles.begin();
float* ptr = (float*)(&(*itr));
GLsizei stride = 0;
if (_particles.size() > 1)
{
float* ptr1 = (float*)(&(*(itr+1)));
stride = ptr1 - ptr;
}
GLsizei posOffset = (float*)(&(itr->_position)) - ptr; // Position
GLsizei colorOffset = (float*)(&(itr->_current_color)) - ptr; // Color
GLsizei velOffset = (float*)(&(itr->_velocity)) - ptr; // Velocity
GLsizei propOffset = (float*)(&(itr->_alive)) - ptr; // Alive, size & alpha
// Draw particles as arrays
osg::State& state = *renderInfo.getState();
state.lazyDisablingOfVertexAttributes();
state.setColorPointer(4, GL_FLOAT, stride * sizeof(float), ptr + colorOffset);
state.setVertexPointer(3, GL_FLOAT, stride * sizeof(float), ptr + posOffset);
if (_useShaders)
{
state.setNormalPointer(GL_FLOAT, stride * sizeof(float), ptr + velOffset);
state.setTexCoordPointer(0, 3, GL_FLOAT, stride * sizeof(float), ptr + propOffset);
}
state.applyDisablingOfVertexAttributes();
glDrawArrays(GL_POINTS, 0, _particles.size());
}
osg::BoundingBox osgParticle::ParticleSystem::computeBoundingBox() const
{
if (!_bounds_computed)
{
return _def_bbox;
} else
{
return osg::BoundingBox(_bmin,_bmax);
}
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org