//--- Non Standard Singleton Methods std::shared_ptr<Collision> Collider::IsColliding(Collider* const a_pOther) { float dist = glm::distance(GetCenter(), a_pOther->GetCenter()); if (dist > (GetRadius() + a_pOther->GetRadius())) { return nullptr; } if (type != a_pOther->type) { Collider* box = type == ColliderType::OBB ? this : a_pOther; Collider* sphere = type == ColliderType::Sphere ? this : a_pOther; vector3 axes[] = { box->obb.r, box->obb.s, box->obb.t }; vector3 closestPt = box->obb.c; vector3 disp = sphere->GetCenter() - box->obb.c; for (int i = 0; i < 3; i++) { float dist = glm::dot(disp, glm::normalize(axes[i])); float extent = glm::length(axes[i]) / 2.0f; if (dist > extent) dist = extent; if (dist < -extent) dist = -extent; closestPt += dist * glm::normalize(axes[i]); } //MeshManagerSingleton::GetInstance()->AddSphereToQueue(glm::translate(closestPt) * glm::scale(vector3(0.1f)), REYELLOW, SOLID); vector3 toSphereCenter = closestPt - sphere->GetCenter(); bool colliding = glm::dot(toSphereCenter, toSphereCenter) <= sphere->GetRadius() * sphere->GetRadius(); if (colliding) { std::shared_ptr<Collision> collision(new Collision()); collision->colliding = true; vector3 penetration = vector3(0); if(glm::length2(toSphereCenter) > 0) penetration = (sphere->GetRadius() - glm::distance(closestPt, sphere->GetCenter())) * glm::normalize(toSphereCenter); collision->penetrationVector = type == ColliderType::OBB ? penetration : -penetration; vector3 toSphereEdge = vector3(0); if (glm::length2(penetration) > 0) toSphereEdge = glm::normalize(penetration) * sphere->GetRadius(); vector3 sphereEdgePt = sphere->GetCenter() + toSphereEdge; vector3 obbEdgePt = closestPt; collision->intersectPoint1 = type == ColliderType::OBB ? obbEdgePt : sphereEdgePt; collision->intersectPoint2 = type == ColliderType::OBB ? sphereEdgePt : obbEdgePt; return collision; } return nullptr; } //If they are both circles, we have already checked their radii else if (type == ColliderType::Sphere) { std::shared_ptr<Collision> collision(new Collision()); collision->colliding = true; return collision; } else { vector3 r1 = obb.r; vector3 s1 = obb.s; vector3 t1 = obb.t; OBB obb2 = a_pOther->obb; vector3 r2 = obb2.r; vector3 s2 = obb2.s; vector3 t2 = obb2.t; vector3 axes[] = { //Normals of OBB1 glm::cross(r1, s1), glm::cross(r1, t1), glm::cross(s1, t1), //Normals of OBB2 glm::cross(r2, s2), glm::cross(r2, t2), glm::cross(s2, t2), //Normals between OBB1 & 2 glm::cross(r1, r2), glm::cross(r1, s2), glm::cross(r1, t2), glm::cross(s1, r2), glm::cross(s1, s2), glm::cross(s1, t2), glm::cross(t1, r2), glm::cross(t1, s2), glm::cross(t1, t2), }; for (int i = 0; i < 15; i++) { if (glm::length(axes[i]) == 0) continue; Projection proj1 = Projection(obb.GetWorldVerts(), axes[i]); Projection proj2 = Projection(a_pOther->obb.GetWorldVerts(), axes[i]); lastCollision = (obb.c + a_pOther->obb.c) / 2.0f; if (!proj1.Overlaps(proj2)) { return nullptr; } } std::shared_ptr<Collision> collision(new Collision()); //TODO: SAT penetration vector collision->colliding = true; return collision; } }