void PUParticleSystem3D::emitParticles( ParticlePool &pool, PUEmitter* emitter, unsigned requested, float elapsedTime ) { Vec3 scale = getDerivedScale(); Mat4 rotMat; Mat4::createRotation(getDerivedOrientation(), &rotMat); float timePoint = 0.0f; float timeInc = elapsedTime / requested; for (unsigned short i = 0; i < requested; ++i) { PUParticle3D *particle = static_cast<PUParticle3D *>(pool.createData()); if (!particle) return; particle->initForEmission(); emitter->initParticleForEmission(particle); particle->direction = (rotMat * Vec3(particle->direction.x, particle->direction.y, particle->direction.z)); particle->originalDirection = (rotMat * Vec3(particle->originalDirection.x, particle->originalDirection.y, particle->originalDirection.z)); for (auto& it : _affectors) { if (it->isEnabled()) { (static_cast<PUAffector*>(it))->initParticleForEmission(particle); } } initParticleForEmission(particle); particle->position.add(particle->direction.x * scale.x * _particleSystemScaleVelocity * timePoint , particle->direction.y * scale.y * _particleSystemScaleVelocity * timePoint , particle->direction.z * scale.z * _particleSystemScaleVelocity * timePoint); // Increment time fragment timePoint += timeInc; } }
// Get transform in world space. const Matrix4& Node::Transform::getFullWorldTransform(const Node* parent) const { if (mCachedTransformOutOfDate) { mCachedTransform.makeTransform(getDerivedTranslate(parent), getDerivedScale(parent), getDerivedRotate(parent)); mCachedTransformOutOfDate = false; } return mCachedTransform; }
void PUParticleSystem3D::processMotion( PUParticle3D* particle, float timeElapsed, bool firstParticle ) { if (particle->isFreezed()) return; /** Because everything is calculated in worldspace we recalculate it back to the techniques' origin (the result is still worldspace) just by adding a relative offset of the particle system, technique, emitter or visual particle. Change in V1.4: The additional PEF_EMITTED check fixes the problem with scenenodese moving forward at extremely fast speeds The bug is due to how PU code processes keep_local, and the calculation shouldn't be applied to newly emitted particles. */ if (!particle->hasEventFlags(PUParticle3D::PEF_EMITTED)) { if (!particle->parentEmitter->makeParticleLocal(particle)) { if (!makeParticleLocal(particle)) { _parentParticleSystem->makeParticleLocal(particle); } } } /** Adjust position of the particle if the parent has rotated (only in case of particle system with 'keep local'). PU 1.4: Added check that technique may not be local, otherwise particles are rotated twice as fast. */ if (_parentParticleSystem->isKeepLocal() && !_keepLocal) { /** Ignore some rendersystems, because they are rotated by Ogre itself. Entities for example are always rotated (even if not local), based on the node orientation. A Billboard not. */ if (_render && !static_cast<PURender *>(_render)->autoRotate) { _parentParticleSystem->rotationOffset(particle->position); } } // Added for 1.3 if (particle->hasEventFlags(PUParticle3D::PEF_EMITTED)) return; // Adjust the velocity to the allowed maximum. if (_maxVelocitySet && particle->calculateVelocity() > _maxVelocity) { particle->direction *= (_maxVelocity / particle->direction.length()); } Vec3 scale = getDerivedScale(); // Update the position with the direction. particle->position.add(particle->direction.x * scale.x * _particleSystemScaleVelocity * timeElapsed , particle->direction.y * scale.y * _particleSystemScaleVelocity * timeElapsed , particle->direction.z * scale.z * _particleSystemScaleVelocity * timeElapsed); }
Point3r SceneNode::getDerivedScale()const { Point3r result( m_scale ); auto parent = getParent(); if ( parent ) { result *= parent->getDerivedScale(); } return result; }
void PUParticleSystem3D::prepared() { if (!_prepared){ //if (_emitter && _emitter->isEnabled()) //{ // auto emitter = static_cast<PUEmitter*>(_emitter); // emitter->prepare(); //} if (_render) static_cast<PURender *>(_render)->prepare(); for (auto it : _behaviourTemplates) { it->prepare(); } for (auto it : _emitters) { //if (it->isEnabled()) (static_cast<PUEmitter*>(it))->prepare(); } for (auto it : _affectors) { //if (it->isEnabled()) (static_cast<PUAffector*>(it))->prepare(); } if (!_poolPrepared){ for (auto it : _emitters) { //if (it->isEnabled()) PUEmitter *emitter = static_cast<PUEmitter*>(it); if (emitter->getEmitsType() == PUParticle3D::PT_EMITTER){ PUEmitter *emitted = static_cast<PUEmitter*>(emitter->getEmitsEntityPtr()); for (unsigned int i = 0; i < _emittedEmitterQuota; ++i){ auto p = new (std::nothrow) PUParticle3D(); p->particleType = PUParticle3D::PT_EMITTER; p->particleEntityPtr = emitted->clone(); p->particleEntityPtr->retain(); p->copyBehaviours(_behaviourTemplates); _emittedEmitterParticlePool[emitted->getName()].addData(p); } } else if (emitter->getEmitsType() == PUParticle3D::PT_TECHNIQUE){ PUParticleSystem3D *emitted = static_cast<PUParticleSystem3D*>(emitter->getEmitsEntityPtr()); for (unsigned int i = 0; i < _emittedSystemQuota; ++i){ PUParticleSystem3D *clonePS = emitted->clone(); auto p = new (std::nothrow) PUParticle3D(); p->particleType = PUParticle3D::PT_TECHNIQUE; p->particleEntityPtr = clonePS; p->particleEntityPtr->retain(); p->copyBehaviours(_behaviourTemplates); _emittedSystemParticlePool[emitted->getName()].addData(p); clonePS->prepared(); } //emitted->stopParticle(); } } for (unsigned int i = 0; i < _particleQuota; ++i){ auto p = new (std::nothrow) PUParticle3D(); p->copyBehaviours(_behaviourTemplates); _particlePool.addData(p); } _poolPrepared = true; } _prepared = true; _timeElapsedSinceStart = 0.0f; if (_parentParticleSystem){ _particleSystemScaleVelocity = _parentParticleSystem->getParticleSystemScaleVelocity(); } } notifyRescaled(getDerivedScale()); }
void PUParticleSystem3D::processParticle( ParticlePool &pool, bool &firstActiveParticle, bool &firstParticle, float elapsedTime ) { Vec3 scale = getDerivedScale(); PUParticle3D *particle = static_cast<PUParticle3D *>(pool.getFirst()); //Mat4 ltow = getNodeToWorldTransform(); //Vec3 scl; //Quaternion rot; //ltow.decompose(&scl, &rot, nullptr); while (particle){ if (!isExpired(particle, elapsedTime)){ particle->process(elapsedTime); //if (_emitter && _emitter->isEnabled()) // _emitter->updateEmitter(particle, elapsedTime); for (auto it : _emitters) { if (it->isEnabled() && !it->isMarkedForEmission()){ (static_cast<PUEmitter*>(it))->updateEmitter(particle, elapsedTime); } } for (auto& it : _affectors) { if (it->isEnabled()){ (static_cast<PUAffector*>(it))->process(particle, elapsedTime, firstActiveParticle); } } if (_render) static_cast<PURender *>(_render)->updateRender(particle, elapsedTime, firstActiveParticle); if (_isEnabled && particle->particleType != PUParticle3D::PT_VISUAL){ if (particle->particleType == PUParticle3D::PT_EMITTER){ auto emitter = static_cast<PUEmitter *>(particle->particleEntityPtr); emitter->setLocalPosition(particle->position); executeEmitParticles(emitter, emitter->calculateRequestedParticles(elapsedTime), elapsedTime); }else if (particle->particleType == PUParticle3D::PT_TECHNIQUE){ auto system = static_cast<PUParticleSystem3D *>(particle->particleEntityPtr); system->setPosition3D(particle->position); system->setRotationQuat(particle->orientation); //system->setScaleX(scl.x);system->setScaleY(scl.y);system->setScaleZ(scl.z); system->forceUpdate(elapsedTime); } } firstActiveParticle = false; // Keep latest position particle->latestPosition = particle->position; //if (_maxVelocitySet && particle->calculateVelocity() > _maxVelocity) //{ // particle->direction *= (_maxVelocity / particle->direction.length()); //} //// Update the position with the direction. //particle->position += (particle->direction * _particleSystemScaleVelocity * elapsedTime); //particle->positionInWorld = particle->position; //particle->orientationInWorld = particle->orientation; //particle->widthInWorld = particle->width; //particle->heightInWorld = particle->height; //particle->depthInWorld = particle->depth; //bool keepLocal = _keepLocal; //PUParticleSystem3D *parent = dynamic_cast<PUParticleSystem3D *>(getParent()); //if (parent) keepLocal = keepLocal || parent->isKeepLocal(); //if (keepLocal){ // ltow.transformPoint(particle->positionInWorld, &particle->positionInWorld); // Vec3 ori; // ltow.transformVector(Vec3(particle->orientation.x, particle->orientation.y, particle->orientation.z), &ori); // particle->orientationInWorld.x = ori.x; particle->orientationInWorld.y = ori.y; particle->orientationInWorld.z = ori.z; // particle->widthInWorld = scl.x * particle->width; // particle->heightInWorld = scl.y * particle->height; // particle->depthInWorld = scl.z * particle->depth; //} processMotion(particle, elapsedTime, scale, firstActiveParticle); } else{ initParticleForExpiration(particle, elapsedTime); pool.lockLatestData(); } for (auto it : _observers){ if (it->isEnabled()){ it->updateObserver(particle, elapsedTime, firstParticle); } } if (particle->hasEventFlags(PUParticle3D::PEF_EXPIRED)) { particle->setEventFlags(0); particle->addEventFlags(PUParticle3D::PEF_EXPIRED); } else { particle->setEventFlags(0); } particle->timeToLive -= elapsedTime; firstParticle = false; particle = static_cast<PUParticle3D *>(pool.getNext()); } }