/// <summary> /// Detecta la colisión entre una caja y una esfera /// </summary> /// <param name="box">Caja</param> /// <param name="sphere">Esfera</param> /// <param name="data">Datos de colisión a llenar</param> /// <returns>Devuelve verdadero si existe colisión, falso en el resto de los casos</returns> private static bool BoxAndSphere(CollisionBox box, CollisionSphere sphere, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Obtener el punto de la caja más cercano al centro de la esfera Vector3 closestPoint = CollisionBox.ClosestPointInBox(box, sphere.Position); // Obtener la distancia entre los puntos float distance = Vector3.Distance(sphere.Position, closestPoint); if (distance <= sphere.Radius) { Vector3 normal = Vector3.Normalize(box.Position - closestPoint); Contact contact = data.CurrentContact; contact.ContactNormal = normal; contact.ContactPoint = closestPoint; contact.Penetration = sphere.Radius - distance; RigidBody one = box; RigidBody two = sphere; contact.SetBodyData(ref one, ref two, data.Friction, data.Restitution); data.AddContact(); return(true); } return(false); }
/// <summary> /// Detecta la colisión entre una esfera y una lista de triángulos /// </summary> /// <param name="sphere">Esfera</param> /// <param name="triangleList">Lista de triángulos</param> /// <param name="data">Datos de la colisión</param> /// <returns>Devuelve verdadero si hay colisión, o falso en el resto de los casos</returns> private static bool SphereAndTriangleList(CollisionSphere sphere, Triangle[] triangleList, ref CollisionData data) { bool contact = false; if (data.ContactsLeft > 0) { if (triangleList != null && triangleList.Length > 0) { foreach (Triangle triangle in triangleList) { if (data.ContactsLeft > 0) { // Comprobar la intersección if (CollisionDetector.SphereAndTriangle(sphere, triangle, ref data)) { contact = true; } } else { break; } } } } return(contact); }
/// <summary> /// Detecta la colisión entre dos esferas /// </summary> /// <param name="one">Esfera uno</param> /// <param name="two">Esfera dos</param> /// <param name="data">Datos de la colisión</param> /// <returns>Devuelve verdadero si hay colisión, o falso en el resto de los casos</returns> public static bool SphereAndSphere(CollisionSphere one, CollisionSphere two, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Almacenar las posiciones de las esferas Vector3 positionOne = one.Position; Vector3 positionTwo = two.Position; // Encontrar el vector entre los objetos Vector3 midline = positionOne - positionTwo; float size = midline.Length(); if (size <= 0.0f || size >= one.Radius + two.Radius) { return(false); } // Obtener la normal de forma manual Vector3 normal = midline * (1.0f / size); Contact contact = data.CurrentContact; contact.ContactNormal = normal; contact.ContactPoint = positionOne + midline * 0.5f; contact.Penetration = (one.Radius + two.Radius - size); contact.SetBodyData(ref one.Body, ref two.Body, data.Friction, data.Restitution); data.AddContact(); return(true); }
/// <summary> /// Detecta la colisión entre una esfera y un triángulo /// </summary> /// <param name="sphere">Esfera</param> /// <param name="tri">Triángulo</param> /// <param name="data">Rellena los datos de colisión</param> /// <returns>Devuelve verdadero si hay colisión o falso en el resto de los casos</returns> private static bool SphereAndTriangle(CollisionSphere sphere, Triangle tri, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Obtener el punto del triángulo más cercano al centro de la esfera Vector3 closestPoint = Triangle.ClosestPointInTriangle(tri, sphere.Position); // Obtener la distancia del punto obtenido al centro de la esfera float distance = Vector3.Distance(closestPoint, sphere.Position); if (distance <= sphere.Radius) { // Crear el contacto. Tiene una normal en la dirección del plano. Contact contact = data.CurrentContact; contact.ContactNormal = tri.Normal; contact.Penetration = sphere.Radius - distance; contact.ContactPoint = closestPoint; RigidBody one = sphere; RigidBody two = null; contact.SetBodyData(ref one, ref two, data.Friction, data.Restitution); data.AddContact(); return(true); } else { return(false); } }
/// <summary> /// Detecta la intersección entre dos esferas /// </summary> /// <param name="one">Esfera</param> /// <param name="two">Esfera</param> /// <returns>Devuelve verdadero si hay intersección</returns> public static bool SphereAndSphere(CollisionSphere one, CollisionSphere two) { // Vector entre ambas esferas Vector3 midline = one.Position - two.Position; // Si el vector es más largo que la suma de los radios, no hay intersección return(midline.LengthSquared() < (one.Radius + two.Radius) * (one.Radius + two.Radius)); }
public static bool SphereAndHalfSpace(CollisionSphere sphere, CollisionPlane plane) { // Find the distance from the origin float ballDistance = Vector3.Dot(plane.Normal, sphere.Position) - sphere.Radius; // Check for the intersection return(ballDistance <= plane.D); }
public static bool SphereAndSphere(CollisionSphere one, CollisionSphere two) { // Find the vector between the objects Vector3 midline = one.Position - two.Position; // See if it is large enough. return(midline.LengthSquared() < (one.Radius + two.Radius) * (one.Radius + two.Radius)); }
/// <summary> /// Detecta la intersección entre una esfera y un triángulo /// </summary> /// <param name="sphere">Esfera</param> /// <param name="triangle">Triángulo</param> /// <param name="halfSpace">Indica si toma el triángulo como un HalfSpace, para tener en cuenta la dirección de la normal</param> /// <returns>Devuelve verdadero si hay intersección</returns> public static bool SphereAndTri(CollisionSphere sphere, Triangle triangle) { // Obtener el punto más cercano al triángulo desde el centro Vector3 point = Triangle.ClosestPointInTriangle(triangle, sphere.Position); float distance = Vector3.Distance(point, sphere.Position); if (distance > sphere.Radius) { return(false); } else { return(true); } }
/// <summary> /// Detecta la colisión entre una esfera y un plano /// </summary> /// <param name="sphere">Esfera</param> /// <param name="plane">Plano</param> /// <param name="data">Rellena los datos de colisión</param> /// <returns>Devuelve verdadero si hay colisión o falso en el resto de los casos</returns> public static bool SphereAndTruePlane(CollisionSphere sphere, CollisionPlane plane, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Almacenar la posición de la esfera Vector3 position = sphere.Position; // Encontrar la distancia al plano float centreDistance = Vector3.Dot(plane.Normal, position) - plane.D; if (centreDistance * centreDistance > sphere.Radius * sphere.Radius) { return(false); } // Chequear la cara del plano en la que estamos para calcular normal y penetración Vector3 normal = plane.Normal; float penetration = -centreDistance; if (centreDistance < 0) { normal *= -1; penetration = -penetration; } penetration += sphere.Radius; // Crear el contacto. Tiene una normal en la dirección del plano. Contact contact = data.CurrentContact; contact.ContactNormal = normal; contact.Penetration = penetration; contact.ContactPoint = position - plane.Normal * centreDistance; RigidBody two = null; contact.SetBodyData(ref sphere.Body, ref two, data.Friction, data.Restitution); data.AddContact(); return(true); }
/// <summary> /// Detecta la intersección entre una esfera y un plano /// </summary> /// <param name="sphere">Esfera</param> /// <param name="normal">Normal del plano</param> /// <param name="d">Distancia</param> /// <returns>Devuelve verdadero si hay intersección</returns> public static int SphereAndPlane(CollisionSphere sphere, Vector3 normal, float d) { // Buscar la distancia al origen float distance = Vector3.Dot(normal, sphere.Position) + d; // Si la distancia es menor hay intersección if (distance > sphere.Radius) { // La esfera está sobre el plano return(1); } else if (distance < -sphere.Radius) { // La esfera está bajo el plano return(-1); } else { // La esfera intersecta con el plano return(0); } }
/// <summary> /// Detecta la colisión entre una esfera y una lista de triángulos /// </summary> /// <param name="sphere">Esfera</param> /// <param name="triangleSoup">Lista de triángulos</param> /// <param name="data">Datos de la colisión</param> /// <returns>Devuelve verdadero si hay colisión, o falso en el resto de los casos</returns> public static bool SphereAndTriangleSoup(CollisionSphere sphere, CollisionTriangleSoup triangleSoup, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } foreach (Triangle triangle in triangleSoup.Triangles) { // Comprobar la intersección if (IntersectionTests.SphereAndTri(sphere, triangle, true)) { // Informar la colisión if (CollisionDetector.SphereAndHalfSpace(sphere, new CollisionPlane(triangle.Plane), ref data)) { return(true); } } } return(false); }
/// <summary> /// Detecta la colisión entre una esfera y un plano /// </summary> /// <param name="sphere">Esfera</param> /// <param name="plane">Plano</param> /// <param name="data">Rellena los datos de colisión</param> /// <returns>Devuelve verdadero si hay colisión o falso en el resto de los casos</returns> private static bool SphereAndHalfSpace(CollisionSphere sphere, CollisionPlane plane, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Distancia del centro al plano float centerToPlane = Math.Abs(Vector3.Dot(plane.Normal, sphere.Position) + plane.D); // Obtener la penetración de la esfera en el plano. float penetration = centerToPlane - sphere.Radius; if (penetration >= 0) { return(false); } // Crear el contacto. Tiene una normal en la dirección del plano. Contact contact = data.CurrentContact; contact.ContactNormal = plane.Normal; contact.Penetration = -penetration; contact.ContactPoint = sphere.Position - plane.Normal * centerToPlane; // No hay cuerpo para el plano. Se considera escenario. RigidBody one = sphere; RigidBody two = null; contact.SetBodyData(ref one, ref two, data.Friction, data.Restitution); // Añadir el contacto data.AddContact(); return(true); }
/// <summary> /// Detecta la colisión entre una esfera y un plano /// </summary> /// <param name="sphere">Esfera</param> /// <param name="plane">Plano</param> /// <param name="data">Rellena los datos de colisión</param> /// <returns>Devuelve verdadero si hay colisión o falso en el resto de los casos</returns> public static bool SphereAndHalfSpace(CollisionSphere sphere, CollisionPlane plane, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Almacenar la posición de la esfera Vector3 position = sphere.Position; // Obtener la distancia al plano. float ballDistance = Vector3.Dot(plane.Normal, position) - sphere.Radius - plane.D; if (ballDistance >= 0) { return(false); } // Crear el contacto. Tiene una normal en la dirección del plano. Contact contact = data.CurrentContact; contact.ContactNormal = plane.Normal; contact.Penetration = -ballDistance; contact.ContactPoint = position - plane.Normal * (ballDistance + sphere.Radius); // No hay cuerpo para el plano. Se considera escenario. RigidBody two = null; contact.SetBodyData(ref sphere.Body, ref two, data.Friction, data.Restitution); // Añadir el contacto data.AddContact(); return(true); }
/// <summary> /// Detecta la intersección entre una esfera y un plano /// </summary> /// <param name="sphere">Esfera</param> /// <param name="plane">Plano</param> /// <returns>Devuelve verdadero si hay intersección</returns> public static bool SphereAndPlane(CollisionSphere sphere, Plane plane) { return(SphereAndPlane(sphere, plane.Normal, plane.D) == 0); }
/// <summary> /// Detecta la colisión entre una caja y una esfera /// </summary> /// <param name="box">Caja</param> /// <param name="sphere">Esfera</param> /// <param name="data">Datos de colisión a llenar</param> /// <returns>Devuelve verdadero si existe colisión, falso en el resto de los casos</returns> public static bool BoxAndSphere(CollisionBox box, CollisionSphere sphere, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Transformar el cetro de la esfera Vector3 centre = sphere.Position; Vector3 relCentre = Vector3.Transform(centre, Matrix.Invert(box.Transform)); // Comprobar si se puede excluir el contacto if (Math.Abs(relCentre.X) - sphere.Radius > box.HalfSize.X || Math.Abs(relCentre.Y) - sphere.Radius > box.HalfSize.Y || Math.Abs(relCentre.Z) - sphere.Radius > box.HalfSize.Z) { return(false); } Vector3 closestPt = Vector3.Zero; float dist = relCentre.X; if (dist > box.HalfSize.X) { dist = box.HalfSize.X; } if (dist < -box.HalfSize.X) { dist = -box.HalfSize.X; } closestPt.X = dist; dist = relCentre.Y; if (dist > box.HalfSize.Y) { dist = box.HalfSize.Y; } if (dist < -box.HalfSize.Y) { dist = -box.HalfSize.Y; } closestPt.Y = dist; dist = relCentre.Z; if (dist > box.HalfSize.Z) { dist = box.HalfSize.Z; } if (dist < -box.HalfSize.Z) { dist = -box.HalfSize.Z; } closestPt.Z = dist; // Comprobar si estamos en contacto. dist = (closestPt - relCentre).LengthSquared(); if (dist > sphere.Radius * sphere.Radius) { return(false); } Vector3 closestPtWorld = Vector3.Transform(closestPt, box.Transform); //HACKBYME: Añadimos la velocidad de la esfera para calcular la normal Vector3 relativeVelocity = sphere.Body.Velocity + box.Body.Velocity; Vector3 normal = Vector3.Normalize(closestPtWorld - centre + relativeVelocity); Contact contact = data.CurrentContact; contact.ContactNormal = normal; contact.ContactPoint = closestPtWorld; contact.Penetration = sphere.Radius - (float)Math.Sqrt(dist); contact.SetBodyData(ref box.Body, ref sphere.Body, data.Friction, data.Restitution); data.AddContact(); return(true); }
/// <summary> /// Detecta la colisión entre una esfera y una lista de triángulos /// </summary> /// <param name="sphere">Esfera</param> /// <param name="triangleSoup">Lista de triángulos</param> /// <param name="data">Datos de la colisión</param> /// <returns>Devuelve verdadero si hay colisión, o falso en el resto de los casos</returns> private static bool SphereAndTriangleSoup(CollisionSphere sphere, CollisionTriangleSoup triangleSoup, ref CollisionData data) { return(SphereAndTriangleList(sphere, triangleSoup.Triangles, ref data)); }
public static bool SphereAndTri(CollisionSphere sphere, Triangle triangle, bool halfSpace) { bool axisTest = true; if (!halfSpace) { // Find the distance from the origin float ballDistance = Math.Abs(Vector3.Dot(triangle.Plane.Normal, sphere.Position)) - sphere.Radius; // Check for the intersection if (ballDistance > triangle.Plane.D) { axisTest = false; } } if (axisTest) { // Obtener los ejes del triángulo Vector3 edge0 = Vector3.Subtract(triangle.Point2, triangle.Point1); Vector3 edge1 = Vector3.Subtract(triangle.Point3, triangle.Point2); Vector3 edge2 = Vector3.Subtract(triangle.Point1, triangle.Point3); // Proyectar desde el punto 1 Vector3 toPoint1 = sphere.Position - triangle.Point1; float distanceTo1 = toPoint1.Length(); toPoint1.Normalize(); float f1a = Math.Abs(Vector3.Dot(edge0, toPoint1)); float f1b = Math.Abs(Vector3.Dot(edge2, toPoint1)); if (distanceTo1 > f1a + sphere.Radius) { return(false); } if (distanceTo1 > f1a + sphere.Radius) { return(false); } // Proyectar desde el punto 2 Vector3 toPoint2 = sphere.Position - triangle.Point2; float distanceTo2 = toPoint2.Length(); toPoint2.Normalize(); float f2a = Math.Abs(Vector3.Dot(edge0, toPoint2)); float f2b = Math.Abs(Vector3.Dot(edge1, toPoint2)); if (distanceTo2 > f2a + sphere.Radius) { return(false); } if (distanceTo2 > f2a + sphere.Radius) { return(false); } // Proyectar desde el punto 3 Vector3 toPoint3 = sphere.Position - triangle.Point3; float distanceTo3 = toPoint3.Length(); toPoint3.Normalize(); float f3a = Math.Abs(Vector3.Dot(edge1, toPoint3)); float f3b = Math.Abs(Vector3.Dot(edge2, toPoint3)); if (distanceTo3 > f3a + sphere.Radius) { return(false); } if (distanceTo3 > f3a + sphere.Radius) { return(false); } return(true); } return(false); }