diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 9cda7d755..fbb4f2889 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -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(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; inumParticles(); ++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; inumParticles(); ++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); } }