Adding Particle::_mass and correct elastic collisions between particles

This commit is contained in:
Andrew Meadows 2014-01-10 11:37:01 -08:00
parent 6f21592ebd
commit 71e5de8420
3 changed files with 47 additions and 29 deletions

View file

@ -54,6 +54,7 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
_position = position;
_radius = radius;
_mass = 1.0f;
memcpy(_color, color, sizeof(_color));
_velocity = velocity;
_damping = damping;
@ -63,6 +64,11 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
_shouldDie = false;
}
void Particle::setMass(float value) {
if (value > 0.0f) {
_mass = value;
}
}
bool Particle::appendParticleData(OctreePacketData* packetData) const {

View file

@ -67,6 +67,7 @@ public:
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
float getRadius() const { return _radius; }
float getMass() const { return _mass; }
const glm::vec3& getVelocity() const { return _velocity; }
const glm::vec3& getGravity() const { return _gravity; }
bool getInHand() const { return _inHand; }
@ -96,6 +97,7 @@ public:
_color[BLUE_INDEX] = value.blue;
}
void setRadius(float value) { _radius = value; }
void setMass(float value);
void setGravity(const glm::vec3& value) { _gravity = value; }
void setInHand(bool inHand) { _inHand = inHand; }
void setDamping(float value) { _damping = value; }
@ -146,6 +148,7 @@ protected:
glm::vec3 _position;
rgbColor _color;
float _radius;
float _mass;
glm::vec3 _velocity;
uint32_t _id;
static uint32_t _nextID;

View file

@ -87,41 +87,50 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
}
}
void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
glm::vec3 center = particle->getPosition() * static_cast<float>(TREE_SCALE);
float radius = particle->getRadius() * static_cast<float>(TREE_SCALE);
const float ELASTICITY = 1.4f;
void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) {
glm::vec3 center = particleA->getPosition() * (float)TREE_SCALE;
float radius = particleA->getRadius() * (float)TREE_SCALE;
const float ELASTICITY = 0.4f;
const float DAMPING = 0.0f;
const float COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration;
Particle* penetratedParticle;
if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) {
Particle* particleB;
if (_particles->findSpherePenetration(center, radius, penetration, (void**)&particleB)) {
// NOTE: 'penetration' is the depth that 'particleA' overlaps 'particleB'.
// That is, it points from A into B.
// let the particles run their collision scripts if they have them
particle->collisionWithParticle(penetratedParticle);
penetratedParticle->collisionWithParticle(particle);
// Even if the particles overlap... when the particles are already moving appart
// we don't want to count this as a collision.
glm::vec3 relativeVelocity = particleA->getVelocity() - particleB->getVelocity();
if (glm::dot(relativeVelocity, penetration) > 0.0f) {
particleA->collisionWithParticle(particleB);
particleB->collisionWithParticle(particleA);
penetration /= static_cast<float>(TREE_SCALE);
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
// apply a hard collision to both particles of half the penetration each
float particleShare, penetratedParticleShare;
if (particle->getInHand() && penetratedParticle->getInHand()) {
particleShare = 0.5f;
penetratedParticleShare = -0.5f;
} else if (particle->getInHand()) {
particleShare = 0.f;
penetratedParticleShare = -1.f;
} else if (penetratedParticle->getInHand()) {
particleShare = -1.f;
penetratedParticleShare = 0.f;
} else {
particleShare = 0.5f;
penetratedParticleShare = -0.5f;
glm::vec3 axis = glm::normalize(penetration);
glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis;
// particles that are in hand are assigned an ureasonably large mass for collisions
// which effectively makes them immovable but allows the other ball to reflect correctly.
const float MAX_MASS = 1.0e6f;
float massA = (particleA->getInHand()) ? MAX_MASS : particleA->getMass();
float massB = (particleB->getInHand()) ? MAX_MASS : particleB->getMass();
float totalMass = massA + massB;
particleA->setVelocity(particleA->getVelocity() - axialVelocity * (2.0f * massB / totalMass));
ParticleEditHandle particleEditHandle(_packetSender, _particles, particleA->getID());
particleEditHandle.updateParticle(particleA->getPosition(), particleA->getRadius(), particleA->getXColor(), particleA->getVelocity(),
particleA->getGravity(), particleA->getDamping(), particleA->getInHand(), particleA->getScript());
particleB->setVelocity(particleB->getVelocity() + axialVelocity * (2.0f * massA / totalMass));
ParticleEditHandle penetratedparticleEditHandle(_packetSender, _particles, particleB->getID());
penetratedparticleEditHandle.updateParticle(particleB->getPosition(), particleB->getRadius(), particleB->getXColor(), particleB->getVelocity(),
particleB->getGravity(), particleB->getDamping(), particleB->getInHand(), particleB->getScript());
penetration /= (float)TREE_SCALE;
updateCollisionSound(particleA, penetration, COLLISION_FREQUENCY);
}
applyHardCollision(particle, penetration * particleShare, ELASTICITY, DAMPING);
applyHardCollision(penetratedParticle, penetration * penetratedParticleShare, ELASTICITY, DAMPING);
}
}