void FTLParticleChain::simulateStep() { std::vector<std::pair<Particle*, CollisionConstraint> > collisionConstraints; auto i = mParticles.begin()+1; Ogre::Vector3 oldPos(i->position); i->velocity += i->force * mTimestep * mParticleMassInv; i->position += i->velocity * mTimestep; Ogre::Vector3 correctionVec = computeFTLCorrectionVector(i); CollisionConstraint cc; if (checkPenetration(i->position, cc.closestSurfacePoint, cc.normal)) { collisionConstraints.push_back(std::make_pair(&(*i), cc)); i->position += computeCollisionCorrection(i->position, cc); } for (; i != mParticles.end()-1; ++i) { // recompute FTL correction, considering the previously added collision response i->position += computeFTLCorrectionVector(i); //correctionVec; auto succ = i + 1; Ogre::Vector3 nextOldPos(succ->position); succ->velocity += succ->force * mTimestep * mParticleMassInv; succ->position += succ->velocity * mTimestep; // this seems give the most stable results: // 1. compute FTL correction vector without considering collision, use this for damping // 2. add collision response // 3. recompute FTL correction and add it (see first line after for loop statement) Ogre::Vector3 nextCorrectionVec = computeFTLCorrectionVector(succ); if (checkPenetration(succ->position, cc.closestSurfacePoint, cc.normal)) { collisionConstraints.push_back(std::make_pair(&(*succ), cc)); succ->position += computeCollisionCorrection(succ->position, cc); } i->velocity = (i->position - oldPos - nextCorrectionVec * mFTLDamping - correctionVec * mPBDPointDamping) / mTimestep; correctionVec = nextCorrectionVec; oldPos = nextOldPos; } // perform update for last particle i->position += correctionVec; i->velocity = (i->position - oldPos - correctionVec * (mPBDPointDamping + mFTLDamping)) / mTimestep; // finally project collision constraints once more and simulate friction by damping the velocity for (auto ic = collisionConstraints.begin(); ic != collisionConstraints.end(); ++ic) { Particle &particle = *ic->first; particle.position += computeCollisionCorrection(particle.position, ic->second); particle.velocity -= mTimestep * mParticleMassInv * computeFrictionDamping(ic->second.normal, particle.velocity); } }
/** * Updates the sprite to apply gravitational effects to it. * The sprite will accellerate downwards unless it lands on another baseable spriteObject. */ void massObject::updateSprite() { spriteObject::updateSprite(); //move sprite first wasGrounded = grounded; if (!isOnGround() && !bStasis) { vy += GRAVITY; if (vy > TERMINALVEL) vy = TERMINALVEL; checkPenetration(); } grounded = false; //is re-checked in collidingWith() later in the tick }
// this implementation follows closely the method proposed here: http://www.matthiasmueller.info/publications/posBasedDyn.pdf void PBDParticleChain::simulateStep() { std::vector<Particle> futureParticles = mParticles; for (auto i = futureParticles.begin() + 1; i != futureParticles.end(); ++i) { i->velocity += i->force * mParticleMassInv * mTimestep; i->velocity -= i->velocity * mPointDamping * mParticleMassInv * mTimestep; // point damping i->position += i->velocity * mTimestep; } // generate collision constraints std::vector<std::pair<int, CollisionConstraint> > collisionConstraints; int particleIndex = 1; for (auto i = futureParticles.begin() + 1; i != futureParticles.end(); ++i) { CollisionConstraint cc; if (checkPenetration(i->position, cc.closestSurfacePoint, cc.normal)) collisionConstraints.push_back(std::make_pair(particleIndex, cc)); particleIndex++; } // hack: use force component of Particle class to store correction vector for damping later for (auto i = futureParticles.begin(); i != futureParticles.end(); ++i) i->force = Ogre::Vector3(0, 0, 0); // collision constraints // maybe it is necessary to put this inside the iterative solver, but so far it seems to work this way for (auto ic = collisionConstraints.begin(); ic != collisionConstraints.end(); ++ic) { Particle &particle = futureParticles[ic->first]; Ogre::Vector3 collisionCorrection = computeCollisionCorrection(particle.position, ic->second); particle.position += collisionCorrection; particle.force += collisionCorrection; } int numIterations = mIterationCount; //std::min<int>(mIterationCount + collisionConstraints.size(), 10); for (int iteration = 0; iteration < numIterations; iteration++) { auto i = futureParticles.begin() + 1; Ogre::Vector3 correction = computeFTLCorrectionVector(i) * mOverRelaxation; i->force += correction; i->position += correction; for (i = futureParticles.begin() + 2; i != futureParticles.end(); ++i) { correction = computeFTLCorrectionVector(i) * 0.5f * mOverRelaxation; (i-1)->position -= correction; i->position += correction; (i-1)->force -= correction; i->force += correction; } // chain stiffness for (i = futureParticles.begin() + 1; i != futureParticles.end() - 1; ++i) { Ogre::Vector3 target = projectPointOnLine(i->position, (i-1)->position, (i+1)->position); Ogre::Vector3 correction = (target - i->position) * mChainStiffness; i->position += correction; i->force += correction; } } auto ifu = futureParticles.begin() + 1; for (auto i = mParticles.begin() + 1; i != mParticles.end(); ++i) { i->velocity = (ifu->position - i->position - ifu->force * mPBDPointDamping) / mTimestep; i->position = ifu->position; ++ifu; } // finally project collision constraints once more and simulate friction by damping the velocity for (auto ic = collisionConstraints.begin(); ic != collisionConstraints.end(); ++ic) { Particle &particle = mParticles[ic->first]; particle.position += computeCollisionCorrection(particle.position, ic->second); particle.velocity -= mTimestep * mParticleMassInv * computeFrictionDamping(ic->second.normal, particle.velocity); } }