void ShapeColliderTests::capsuleMissesCapsule() { // non-overlapping capsules float radiusA = 2.f; float halfHeightA = 3.f; float radiusB = 3.f; float halfHeightB = 4.f; float totalRadius = radiusA + radiusB; float totalHalfLength = totalRadius + halfHeightA + halfHeightB; CapsuleShape capsuleA(radiusA, halfHeightA); CapsuleShape capsuleB(radiusA, halfHeightA); CollisionList collisions(16); // side by side capsuleB.setPosition((1.01f * totalRadius) * xAxis); if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } // end to end capsuleB.setPosition((1.01f * totalHalfLength) * xAxis); if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } // rotate B and move it to the side glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); capsuleB.setPosition((1.01f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (collisions.size() > 0) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; } }
void ShapeColliderTests::capsuleTouchesCapsule() { // overlapping capsules float radiusA = 2.f; float halfHeightA = 3.f; float radiusB = 3.f; float halfHeightB = 4.f; float totalRadius = radiusA + radiusB; float totalHalfLength = totalRadius + halfHeightA + halfHeightB; CapsuleShape capsuleA(radiusA, halfHeightA); CapsuleShape capsuleB(radiusB, halfHeightB); CollisionList collisions(16); int numCollisions = 0; { // side by side capsuleB.setPosition((0.99f * totalRadius) * xAxis); if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } } { // end to end capsuleB.setPosition((0.99f * totalHalfLength) * yAxis); if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } } { // rotate B and move it to the side glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); capsuleB.setPosition((0.99f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } } { // again, but this time check collision details float overlap = 0.1f; glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); glm::vec3 positionB = ((totalRadius + capsuleB.getHalfHeight()) - overlap) * xAxis; capsuleB.setPosition(positionB); // capsuleA vs capsuleB if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } CollisionInfo* collision = collisions.getCollision(numCollisions - 1); glm::vec3 expectedPenetration = overlap * xAxis; float inaccuracy = glm::length(collision->_penetration - expectedPenetration); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration << " actual = " << collision->_penetration << std::endl; } glm::vec3 expectedContactPoint = capsuleA.getPosition() + radiusA * xAxis; inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint << " actual = " << collision->_contactPoint << std::endl; } // capsuleB vs capsuleA if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } collision = collisions.getCollision(numCollisions - 1); expectedPenetration = - overlap * xAxis; inaccuracy = glm::length(collision->_penetration - expectedPenetration); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration << " actual = " << collision->_penetration << std::endl; } expectedContactPoint = capsuleB.getPosition() - (radiusB + halfHeightB) * xAxis; inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint << " actual = " << collision->_contactPoint << std::endl; } } { // collide cylinder wall against cylinder wall float overlap = 0.137f; float shift = 0.317f * halfHeightA; glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); glm::vec3 positionB = (totalRadius - overlap) * zAxis + shift * yAxis; capsuleB.setPosition(positionB); // capsuleA vs capsuleB if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should touch" << std::endl; } else { ++numCollisions; } CollisionInfo* collision = collisions.getCollision(numCollisions - 1); glm::vec3 expectedPenetration = overlap * zAxis; float inaccuracy = glm::length(collision->_penetration - expectedPenetration); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration << " actual = " << collision->_penetration << std::endl; } glm::vec3 expectedContactPoint = capsuleA.getPosition() + radiusA * zAxis + shift * yAxis; inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint << " actual = " << collision->_contactPoint << std::endl; } } }
void VerletShapeTests::capsuleMissesCapsule() { // non-overlapping capsules float radiusA = 2.0f; float halfHeightA = 3.0f; float radiusB = 3.0f; float halfHeightB = 4.0f; float totalRadius = radiusA + radiusB; float totalHalfLength = totalRadius + halfHeightA + halfHeightB; // create points for the shapes VerletPoint points[4]; for (int i = 0; i < 4; ++i) { points[i]._position = glm::vec3(0.0f); } // give the points to the shapes VerletCapsuleShape capsuleA(radiusA, points+0, points+1); VerletCapsuleShape capsuleB(radiusB, points+2, points+3); capsuleA.setHalfHeight(halfHeightA); capsuleA.setHalfHeight(halfHeightB); CollisionList collisions(16); // side by side capsuleB.setTranslation((1.01f * totalRadius) * xAxis); if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } // end to end capsuleB.setTranslation((1.01f * totalHalfLength) * xAxis); if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } // rotate B and move it to the side glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); capsuleB.setRotation(rotation); capsuleB.setTranslation((1.01f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: capsule and capsule should NOT touch" << std::endl; } if (collisions.size() > 0) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; } }