From bbd476d564c376232a40cfa7fb21ffde2c05df69 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Sep 2014 14:55:05 -0700 Subject: [PATCH 1/2] handled multiple collisions correctly, and don't collide if fully enclosed --- .../entities/src/EntityCollisionSystem.cpp | 150 +++++++++--------- libraries/entities/src/EntityTreeElement.cpp | 4 +- 2 files changed, 78 insertions(+), 76 deletions(-) diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 609b91f3a1..53966c28bd 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -120,95 +120,95 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { bool shapeCollisions = _entities->findShapeCollisions(&entityA->getCollisionShapeInMeters(), collisions, Octree::NoLock, &shapeCollisionsAccurate); + if (shapeCollisions) { for(int i = 0; i < collisions.size(); i++) { + CollisionInfo* collision = collisions[i]; penetration = collision->_penetration; entityB = static_cast(collision->_extraData); - // TODO: how to handle multiple collisions? - break; - } - } - - if (shapeCollisions) { - // NOTE: 'penetration' is the depth that 'entityA' overlaps 'entityB'. It points from A into B. - glm::vec3 penetrationInTreeUnits = penetration / (float)(TREE_SCALE); + // NOTE: 'penetration' is the depth that 'entityA' overlaps 'entityB'. It points from A into B. + glm::vec3 penetrationInTreeUnits = penetration / (float)(TREE_SCALE); - // Even if the Entities overlap... when the Entities are already moving appart - // we don't want to count this as a collision. - glm::vec3 relativeVelocity = entityA->getVelocity() - entityB->getVelocity(); - - bool wantToMoveA = entityA->getCollisionsWillMove(); - bool wantToMoveB = entityB->getCollisionsWillMove(); - bool movingTowardEachOther = glm::dot(relativeVelocity, penetrationInTreeUnits) > 0.0f; - - // only do collisions if the entities are moving toward each other and one or the other - // of the entities are movable from collisions - bool doCollisions = movingTowardEachOther && (wantToMoveA || wantToMoveB); - - if (doCollisions) { - quint64 now = usecTimestampNow(); - - CollisionInfo collision; - collision._penetration = penetration; - // for now the contactPoint is the average between the the two paricle centers - collision._contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); - emitGlobalEntityCollisionWithEntity(entityA, entityB, collision); - - glm::vec3 axis = glm::normalize(penetration); - glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis; - - float massA = entityA->getMass(); - float massB = entityB->getMass(); - float totalMass = massA + massB; - float massRatioA = (2.0f * massB / totalMass); - float massRatioB = (2.0f * massA / totalMass); - - // in the event that one of our entities is non-moving, then fix up these ratios - if (wantToMoveA && !wantToMoveB) { - massRatioA = 2.0f; - massRatioB = 0.0f; - } - - if (!wantToMoveA && wantToMoveB) { - massRatioA = 0.0f; - massRatioB = 2.0f; - } + // Even if the Entities overlap... when the Entities are already moving appart + // we don't want to count this as a collision. + glm::vec3 relativeVelocity = entityA->getVelocity() - entityB->getVelocity(); - // unless the entity is configured to not be moved by collision, calculate it's new position - // and velocity and apply it - if (wantToMoveA) { - // handle Entity A - glm::vec3 newVelocityA = entityA->getVelocity() - axialVelocity * massRatioA; - glm::vec3 newPositionA = entityA->getPosition() - 0.5f * penetrationInTreeUnits; + bool fullyEnclosedCollision = glm::length(penetrationInTreeUnits) > entityA->getLargestDimension(); - EntityItemProperties propertiesA = entityA->getProperties(); - EntityItemID idA(entityA->getID()); - propertiesA.setVelocity(newVelocityA * (float)TREE_SCALE); - propertiesA.setPosition(newPositionA * (float)TREE_SCALE); - propertiesA.setLastEdited(now); + bool wantToMoveA = entityA->getCollisionsWillMove(); + bool wantToMoveB = entityB->getCollisionsWillMove(); + bool movingTowardEachOther = glm::dot(relativeVelocity, penetrationInTreeUnits) > 0.0f; + + // only do collisions if the entities are moving toward each other and one or the other + // of the entities are movable from collisions + bool doCollisions = !fullyEnclosedCollision && movingTowardEachOther && (wantToMoveA || wantToMoveB); + + if (doCollisions) { + + quint64 now = usecTimestampNow(); - _entities->updateEntity(idA, propertiesA); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA); - } + CollisionInfo collision; + collision._penetration = penetration; + // for now the contactPoint is the average between the the two paricle centers + collision._contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); + emitGlobalEntityCollisionWithEntity(entityA, entityB, collision); - // unless the entity is configured to not be moved by collision, calculate it's new position - // and velocity and apply it - if (wantToMoveB) { - glm::vec3 newVelocityB = entityB->getVelocity() + axialVelocity * massRatioB; - glm::vec3 newPositionB = entityB->getPosition() + 0.5f * penetrationInTreeUnits; + glm::vec3 axis = glm::normalize(penetration); + glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis; - EntityItemProperties propertiesB = entityB->getProperties(); + float massA = entityA->getMass(); + float massB = entityB->getMass(); + float totalMass = massA + massB; + float massRatioA = (2.0f * massB / totalMass); + float massRatioB = (2.0f * massA / totalMass); - EntityItemID idB(entityB->getID()); - propertiesB.setVelocity(newVelocityB * (float)TREE_SCALE); - propertiesB.setPosition(newPositionB * (float)TREE_SCALE); - propertiesB.setLastEdited(now); + // in the event that one of our entities is non-moving, then fix up these ratios + if (wantToMoveA && !wantToMoveB) { + massRatioA = 2.0f; + massRatioB = 0.0f; + } - _entities->updateEntity(idB, propertiesB); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB); - } + if (!wantToMoveA && wantToMoveB) { + massRatioA = 0.0f; + massRatioB = 2.0f; + } + + // unless the entity is configured to not be moved by collision, calculate it's new position + // and velocity and apply it + if (wantToMoveA) { + // handle Entity A + glm::vec3 newVelocityA = entityA->getVelocity() - axialVelocity * massRatioA; + glm::vec3 newPositionA = entityA->getPosition() - 0.5f * penetrationInTreeUnits; + + EntityItemProperties propertiesA = entityA->getProperties(); + EntityItemID idA(entityA->getID()); + propertiesA.setVelocity(newVelocityA * (float)TREE_SCALE); + propertiesA.setPosition(newPositionA * (float)TREE_SCALE); + propertiesA.setLastEdited(now); + + _entities->updateEntity(idA, propertiesA); + _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA); + } + + // unless the entity is configured to not be moved by collision, calculate it's new position + // and velocity and apply it + if (wantToMoveB) { + glm::vec3 newVelocityB = entityB->getVelocity() + axialVelocity * massRatioB; + glm::vec3 newPositionB = entityB->getPosition() + 0.5f * penetrationInTreeUnits; + + EntityItemProperties propertiesB = entityB->getProperties(); + + EntityItemID idB(entityB->getID()); + propertiesB.setVelocity(newVelocityB * (float)TREE_SCALE); + propertiesB.setPosition(newPositionB * (float)TREE_SCALE); + propertiesB.setLastEdited(now); + + _entities->updateEntity(idB, propertiesB); + _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB); + } + } } } } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 5df98d43a8..da7d5db226 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -558,7 +558,9 @@ bool EntityTreeElement::findShapeCollisions(const Shape* shape, CollisionList& c // entities that are set for ignore for collisions then don't consider them for collision const Shape* otherCollisionShape = &entity->getCollisionShapeInMeters(); - if (shape != otherCollisionShape && !entity->getIgnoreForCollisions()) { + + bool ignoreForCollisions = entity->getIgnoreForCollisions(); + if (shape != otherCollisionShape && !ignoreForCollisions) { if (ShapeCollider::collideShapes(shape, otherCollisionShape, collisions)) { CollisionInfo* lastCollision = collisions.getLastCollision(); lastCollision->_extraData = entity; From 7bea4b3123e149b1c0174f74c372d2124503f76e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Sep 2014 15:12:59 -0700 Subject: [PATCH 2/2] also honor ignore collisions for voxels and avatars --- libraries/entities/src/EntityCollisionSystem.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 53966c28bd..4ec9912b01 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -78,6 +78,11 @@ void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* enti } void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) { + + if (entity->getIgnoreForCollisions() || !entity->getCollisionsWillMove()) { + return; // bail early if this entity is to be ignored or wont move + } + glm::vec3 center = entity->getPosition() * (float)(TREE_SCALE); float radius = entity->getRadius() * (float)(TREE_SCALE); const float ELASTICITY = 0.4f; @@ -220,6 +225,10 @@ void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) { return; } + if (entity->getIgnoreForCollisions() || !entity->getCollisionsWillMove()) { + return; // bail early if this entity is to be ignored or wont move + } + glm::vec3 center = entity->getPosition() * (float)(TREE_SCALE); float radius = entity->getRadius() * (float)(TREE_SCALE); const float ELASTICITY = 0.9f;