|
|
|
@ -31,12 +31,47 @@
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/// @todo Do this in updateCallback so that animations are accounted for.
|
|
|
|
|
class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor
|
|
|
|
|
class InitWorldSpaceParticlesCallback : public osg::NodeCallback
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|
|
|
|
{
|
|
|
|
|
osgParticle::ParticleSystem* partsys = static_cast<osgParticle::ParticleSystem*>(node);
|
|
|
|
|
|
|
|
|
|
// HACK: Ignore the InverseWorldMatrix transform the particle system is attached to
|
|
|
|
|
if (partsys->getNumParents() && partsys->getParent(0)->getNumParents())
|
|
|
|
|
transformInitialParticles(partsys, partsys->getParent(0)->getParent(0));
|
|
|
|
|
|
|
|
|
|
node->removeUpdateCallback(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node)
|
|
|
|
|
{
|
|
|
|
|
osg::NodePathList nodepaths = node->getParentalNodePaths();
|
|
|
|
|
if (nodepaths.empty())
|
|
|
|
|
return;
|
|
|
|
|
osg::Matrixf worldMat = osg::computeLocalToWorld(nodepaths[0]);
|
|
|
|
|
worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node
|
|
|
|
|
for (int i=0; i<partsys->numParticles(); ++i)
|
|
|
|
|
{
|
|
|
|
|
partsys->getParticle(i)->transformPositionVelocity(worldMat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// transform initial bounds to worldspace
|
|
|
|
|
osg::BoundingSphere sphere(partsys->getInitialBound());
|
|
|
|
|
SceneUtil::transformBoundingSphere(worldMat, sphere);
|
|
|
|
|
osg::BoundingBox box;
|
|
|
|
|
box.expandBy(sphere);
|
|
|
|
|
partsys->setInitialBound(box);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class InitParticlesVisitor : public osg::NodeVisitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
/// @param mask The node mask to set on ParticleSystem nodes.
|
|
|
|
|
InitWorldSpaceParticlesVisitor(unsigned int mask)
|
|
|
|
|
InitParticlesVisitor(unsigned int mask)
|
|
|
|
|
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
|
|
|
|
, mMask(mask)
|
|
|
|
|
{
|
|
|
|
@ -56,33 +91,12 @@ namespace
|
|
|
|
|
{
|
|
|
|
|
if (isWorldSpaceParticleSystem(partsys))
|
|
|
|
|
{
|
|
|
|
|
// HACK: Ignore the InverseWorldMatrix transform the particle system is attached to
|
|
|
|
|
if (partsys->getNumParents() && partsys->getParent(0)->getNumParents())
|
|
|
|
|
transformInitialParticles(partsys, partsys->getParent(0)->getParent(0));
|
|
|
|
|
partsys->addUpdateCallback(new InitWorldSpaceParticlesCallback);
|
|
|
|
|
}
|
|
|
|
|
partsys->setNodeMask(mMask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node)
|
|
|
|
|
{
|
|
|
|
|
osg::NodePathList nodepaths = node->getParentalNodePaths();
|
|
|
|
|
if (nodepaths.empty())
|
|
|
|
|
return;
|
|
|
|
|
osg::Matrixf worldMat = osg::computeLocalToWorld(nodepaths[0]);
|
|
|
|
|
worldMat.orthoNormalize(worldMat); // scale is already applied on the particle node
|
|
|
|
|
for (int i=0; i<partsys->numParticles(); ++i)
|
|
|
|
|
{
|
|
|
|
|
partsys->getParticle(i)->transformPositionVelocity(worldMat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// transform initial bounds to worldspace
|
|
|
|
|
osg::BoundingSphere sphere(partsys->getInitialBound());
|
|
|
|
|
SceneUtil::transformBoundingSphere(worldMat, sphere);
|
|
|
|
|
osg::BoundingBox box;
|
|
|
|
|
box.expandBy(sphere);
|
|
|
|
|
partsys->setInitialBound(box);
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
unsigned int mMask;
|
|
|
|
|
};
|
|
|
|
@ -489,7 +503,7 @@ namespace Resource
|
|
|
|
|
// we can skip any scene graphs without update callbacks since we know that particle emitters will have an update callback set
|
|
|
|
|
if (node->getNumChildrenRequiringUpdateTraversal() > 0)
|
|
|
|
|
{
|
|
|
|
|
InitWorldSpaceParticlesVisitor visitor (mParticleSystemMask);
|
|
|
|
|
InitParticlesVisitor visitor (mParticleSystemMask);
|
|
|
|
|
node->accept(visitor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|