Adding static friction for easier "catching" of particles on paddle hands.

This commit is contained in:
Andrew Meadows 2014-01-20 17:34:24 -08:00
parent 516a590e4f
commit 966cd76e2c

View file

@ -71,7 +71,7 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE); glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
float radius = particle->getRadius() * (float)(TREE_SCALE); float radius = particle->getRadius() * (float)(TREE_SCALE);
const float ELASTICITY = 0.4f; const float ELASTICITY = 0.4f;
const float DAMPING = 0.0f; const float DAMPING = 0.05f;
const float COLLISION_FREQUENCY = 0.5f; const float COLLISION_FREQUENCY = 0.5f;
CollisionInfo collisionInfo; CollisionInfo collisionInfo;
VoxelDetail* voxelDetails = NULL; VoxelDetail* voxelDetails = NULL;
@ -135,6 +135,10 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA)
} }
} }
// MIN_VALID_SPEED is obtained by computing speed gained at one gravity after the shortest expected frame
const float MIN_EXPECTED_FRAME_PERIOD = 0.0167f; // 1/60th of a second
const float HALTING_SPEED = 9.8 * MIN_EXPECTED_FRAME_PERIOD / (float)(TREE_SCALE);
void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
// particles that are in hand, don't collide with avatars // particles that are in hand, don't collide with avatars
@ -145,7 +149,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE); glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
float radius = particle->getRadius() * (float)(TREE_SCALE); float radius = particle->getRadius() * (float)(TREE_SCALE);
const float ELASTICITY = 0.9f; const float ELASTICITY = 0.9f;
const float DAMPING = 0.0f; const float DAMPING = 0.1f;
const float COLLISION_FREQUENCY = 0.5f; const float COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration; glm::vec3 penetration;
@ -164,17 +168,20 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle. // NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
// TODO: make this less hacky when we have more per-collision details // TODO: make this less hacky when we have more per-collision details
float elasticity = ELASTICITY; float elasticity = ELASTICITY;
float SLOW_PADDLE_SPEED = 5.0e-5f; float attenuationFactor = glm::length(collisionInfo._addedVelocity) / HALTING_SPEED;
float attenuationFactor = glm::length(collisionInfo._addedVelocity) / SLOW_PADDLE_SPEED; float damping = DAMPING;
if (attenuationFactor < 1.f) { if (attenuationFactor < 1.f) {
collisionInfo._addedVelocity *= attenuationFactor; collisionInfo._addedVelocity *= attenuationFactor;
elasticity *= attenuationFactor; elasticity *= attenuationFactor;
// NOTE: the math below keeps the damping piecewise continuous,
// while ramping it up to 1.0 when attenuationFactor = 0
damping = DAMPING + (1.f - attenuationFactor) * (1.f - DAMPING);
} }
// HACK END // HACK END
collisionInfo._penetration /= (float)(TREE_SCALE); collisionInfo._penetration /= (float)(TREE_SCALE);
updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY); updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
applyHardCollision(particle, elasticity, DAMPING, collisionInfo); applyHardCollision(particle, elasticity, damping, collisionInfo);
} }
} }
} }
@ -193,24 +200,26 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle. // NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
// TODO: make this less hacky when we have more per-collision details // TODO: make this less hacky when we have more per-collision details
float elasticity = ELASTICITY; float elasticity = ELASTICITY;
float SLOW_PADDLE_SPEED = 5.0e-5f; float attenuationFactor = glm::length(collisionInfo._addedVelocity) / HALTING_SPEED;
float attenuationFactor = glm::length(collisionInfo._addedVelocity) / SLOW_PADDLE_SPEED; float damping = DAMPING;
if (attenuationFactor < 1.f) { if (attenuationFactor < 1.f) {
collisionInfo._addedVelocity *= attenuationFactor; collisionInfo._addedVelocity *= attenuationFactor;
elasticity *= attenuationFactor; elasticity *= attenuationFactor;
// NOTE: the math below keeps the damping piecewise continuous,
// while ramping it up to 1.0 when attenuationFactor = 0
damping = DAMPING + (1.f - attenuationFactor) * (1.f - DAMPING);
} }
// HACK END // HACK END
collisionInfo._penetration /= (float)(TREE_SCALE); collisionInfo._penetration /= (float)(TREE_SCALE);
updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY); updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
applyHardCollision(particle, ELASTICITY, DAMPING, collisionInfo); applyHardCollision(particle, ELASTICITY, damping, collisionInfo);
} }
} }
} }
} }
} }
// TODO: convert applyHardCollision() to take a CollisionInfo& instead of penetration + addedVelocity // TODO: convert applyHardCollision() to take a CollisionInfo& instead of penetration + addedVelocity
void ParticleCollisionSystem::applyHardCollision(Particle* particle, float elasticity, float damping, const CollisionInfo& collisionInfo) { void ParticleCollisionSystem::applyHardCollision(Particle* particle, float elasticity, float damping, const CollisionInfo& collisionInfo) {
// //
@ -224,19 +233,19 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, float elast
glm::vec3 velocity = particle->getVelocity(); glm::vec3 velocity = particle->getVelocity();
const float EPSILON = 0.0f; const float EPSILON = 0.0f;
float velocityDotPenetration = glm::dot(velocity, collisionInfo._penetration); glm::vec3 relativeVelocity = collisionInfo._addedVelocity - velocity;
if (velocityDotPenetration > EPSILON) { float velocityDotPenetration = glm::dot(relativeVelocity, collisionInfo._penetration);
if (velocityDotPenetration < EPSILON) {
// particle is moving into collision surface
position -= collisionInfo._penetration; position -= collisionInfo._penetration;
// cancel out the velocity component in the direction of penetration
glm::vec3 direction = glm::normalize(collisionInfo._penetration);
velocity += collisionInfo._addedVelocity - (glm::dot(velocity, direction) * (1.0f + elasticity)) * direction;
velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f);
// TODO: move this halt logic into Particle::update() method if (glm::length(relativeVelocity) < HALTING_SPEED) {
static float HALTING_SPEED = 0.2f / (float)(TREE_SCALE); // static friction kicks in and particle moves with colliding object
if (glm::length(velocity) < HALTING_SPEED) { velocity = collisionInfo._addedVelocity;
// If moving really slowly after a collision, and not applying forces, stop altogether } else {
velocity *= 0.f; glm::vec3 direction = glm::normalize(collisionInfo._penetration);
velocity += glm::dot(relativeVelocity, direction) * (1.0f + elasticity) * direction; // dynamic reflection
velocity += glm::clamp(damping, 0.0f, 1.0f) * (relativeVelocity - glm::dot(relativeVelocity, direction) * direction); // dynamic friction
} }
} }
const bool wantDebug = false; const bool wantDebug = false;