diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index edca3a1fc0..346760b115 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -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 { diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index 9c92d0ec48..5e80234660 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -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; diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index 1e1f3955fe..0389dddb66 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -87,41 +87,50 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) { } } -void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) { - glm::vec3 center = particle->getPosition() * static_cast(TREE_SCALE); - float radius = particle->getRadius() * static_cast(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(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); } }