/// <summary> /// Detecta la colisión entre caja y plano /// </summary> /// <param name="box">Caja</param> /// <param name="plane">Plano</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 BoxAndHalfSpace(CollisionBox box, CollisionPlane plane, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Comprobar la intersección if (!IntersectionTests.BoxAndHalfSpace(box, plane)) { return(false); } // Hay intersección, ahora hay que encontrar los puntos de intersección. // Podemos hacerlo únicamente chequeando los vértices. // Si la caja está descansando sobre el plano o un eje, se reportarán cuatro o dos puntos de contacto. uint contactsUsed = 0; for (int i = 0; i < 8; i++) { // Calcular la positición de cada vértice Vector3 vertexPos = box.GetCorner(i); // Calcular la distancia al plano float vertexDistance = Vector3.Dot(vertexPos, plane.Normal); // Comparar las distancias if (vertexDistance <= plane.D) { // Crear la información del contacto. // El punto de contacto está a medio camino entre el vértice y el plano. // Se obtiene multiplicando la dirección por la mitad de la distancia de separación, y añadiendo la posición del vértice. Contact contact = data.CurrentContact; contact.ContactPoint = vertexPos; contact.ContactNormal = plane.Normal; contact.Penetration = plane.D - vertexDistance; // Establecer los datos del contacto RigidBody one = box.Body; RigidBody two = null; contact.SetBodyData(ref one, ref two, data.Friction, data.Restitution); // Añadir contacto data.AddContact(); contactsUsed++; if (contactsUsed == data.ContactsLeft) { return(true); } } } return(true); }
/// <summary> /// Detecta la colisión entre caja y triángulo /// </summary> /// <param name="box">Caja</param> /// <param name="tri">Triángulo</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 BoxAndTriangle(CollisionBox box, Triangle tri, ref CollisionData data) { bool intersectionExists = false; if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } // Hay intersección, ahora hay que encontrar los puntos de intersección. // Podemos hacerlo únicamente chequeando los vértices. // Si la caja está descansando sobre el plano o un eje, se reportarán cuatro o dos puntos de contacto. for (int i = 0; i < 8; i++) { // Calcular la positición de cada vértice Vector3 vertexPos = box.GetCorner(i); // Calcular la distancia al plano float distanceToPlane = tri.Plane.Distance(vertexPos); if (distanceToPlane <= 0f) { // Si la distancia es negativa está tras el plano. Si es 0, está en el plano // Intersección entre línea y triángulo Vector3 direction = Vector3.Normalize(box.Position - vertexPos); Ray r = new Ray(vertexPos, direction); if (IntersectionTests.TriAndRay(tri, r)) { intersectionExists = true; // Crear la información del contacto. // El punto de contacto está a medio camino entre el vértice y el plano. // Se obtiene multiplicando la dirección por la mitad de la distancia de separación, y añadiendo la posición del vértice. Contact contact = data.CurrentContact; contact.ContactPoint = vertexPos; contact.ContactNormal = tri.Plane.Normal; contact.Penetration = -distanceToPlane; // Establecer los datos del contacto RigidBody one = box; RigidBody two = null; contact.SetBodyData(ref one, ref two, data.Friction, data.Restitution); // Añadir contacto data.AddContact(); if (data.ContactsLeft <= 0) { return(true); } } } } return(intersectionExists); }
/// <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> /// Obtiene si hay intersección entre el rayo y la lista de triángulos /// </summary> /// <param name="triangleList">Lista de triángulos</param> /// <param name="ray">Rayo</param> /// <param name="triangle">Devuelve el triángulo de intersección si existe</param> /// <param name="intersectionPoint">Devuelve el punto de intersección con el triángulo</param> /// <param name="distanceToPoint">Devuelve la distancia desde el origen del ray al punto de intersección</param> /// <param name="findNearest">Indica si se debe testear la intersección hasta encontrar el más cercano</param> /// <returns>Devuelve verdadero si hay intersección o falso en el resto de los casos</returns> public static bool TriangleListAndRay(Triangle[] triangleList, Ray ray, out Triangle?triangle, out Vector3?intersectionPoint, out float?distanceToPoint, bool findNearest) { triangle = null; intersectionPoint = null; distanceToPoint = null; // Indica si ha habido intersección bool intersectionOccur = false; // Variables para almacenar la interscción más cercana Triangle?closestTriangle = null; Vector3? closestIntersectionPoint = null; float? closestDistanceToPoint = null; // Recorremos todos los triángulos de la lista realizando el test de intersección foreach (Triangle currentTriangle in triangleList) { // Variables para almacener la intersección actual Vector3?currentIntersectionPoint = null; float? currentDistanceToPoint = null; if (IntersectionTests.TriAndRay(currentTriangle, ray, out currentIntersectionPoint, out currentDistanceToPoint)) { bool update = false; if (closestDistanceToPoint.HasValue) { // Comprobar si la distancia obtenida en la intersección es más cercana a la obtenida anteriormente if (closestDistanceToPoint.Value > currentDistanceToPoint.Value) { // Actualizar la intersección más cercana update = true; } } else { // No hay intersección todavía, se debe actualizar la intersección más cercana con la obtenida update = true; } if (update) { // Indicar que ha habido una intersección intersectionOccur = true; // Actualizar la información de intersección más cercana closestTriangle = currentTriangle; closestIntersectionPoint = currentIntersectionPoint; closestDistanceToPoint = currentDistanceToPoint; if (!findNearest) { // Salimos en la primera intersección break; } } } } if (intersectionOccur) { // Si ha habido intersección se establece el resultado de la intersección más cercana triangle = closestTriangle; intersectionPoint = closestIntersectionPoint; distanceToPoint = closestDistanceToPoint; return(true); } return(false); }
/// <summary> /// Detecta la colisión entre una caja y una lista de triángulos /// </summary> /// <param name="box">Caja</param> /// <param name="triangleList">Lista de triángulos</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 BoxAndTriangleList(CollisionBox box, Triangle[] triangleList, ref CollisionData data) { if (data.ContactsLeft <= 0) { // Si no hay más contactos disponibles se sale de la función. return(false); } bool intersection = false; if (data.ContactsLeft > 0) { int firstContact = data.ContactCount; foreach (Triangle triangle in triangleList) { // Comprobar la intersección con el triángulo if (IntersectionTests.BoxAndTri(box, triangle)) { if (data.ContactsLeft > 0) { if (CollisionDetector.BoxAndTriangle(box, triangle, ref data)) { intersection = true; } } else { break; } } } //int contactCount = data.ContactCount - firstContact; //if (intersection && contactCount > 1) //{ // //Agrupar los contactos // Vector3 contactPoint = Vector3.Zero; // Vector3 contactNormal = Vector3.Zero; // float penetration = 0f; // for (int i = firstContact; i < data.ContactCount; i++) // { // contactPoint += data.ContactArray[i].ContactPoint; // contactNormal += data.ContactArray[i].ContactNormal; // penetration += data.ContactArray[i].Penetration; // } // contactPoint /= contactCount; // contactNormal /= contactCount; // penetration /= contactCount; // Contact newContact = new Contact(); // data.ContactArray[firstContact].ContactPoint = contactPoint; // data.ContactArray[firstContact].ContactNormal = Vector3.Normalize(contactNormal); // data.ContactArray[firstContact].Penetration = penetration; // data.SetContactIndex(firstContact + 1); //} } return(intersection); }