/// <summary> /// Detecta la colisión entre una caja y una colección de triángulos /// </summary> /// <param name="box">Caja</param> /// <param name="triangleSoup">Colección 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> public static bool BoxAndTriangleSoup(CollisionBox box, CollisionTriangleSoup triangleSoup, 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; int contacts = 0; foreach (Triangle triangle in triangleSoup.Triangles) { // Comprobar la intersección if (IntersectionTests.BoxAndTri(box, triangle)) { // 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); Plane plane = triangle.Plane; // Calcular la distancia al plano float distanceToPlane = Vector3.Dot(vertexPos, plane.Normal) + plane.D; // Si la distancia es negativa está tras el plano. Si es 0, está en el plano if (distanceToPlane <= 0f) { // Intersección entre línea y triángulo Vector3 direction = vertexPos - box.Position; if (IntersectionTests.TriAndRay(triangle, new Ray(box.Position, direction))) { intersection = true; contacts++; // 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 = -distanceToPlane; // 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(); if (data.ContactsLeft <= 0) { return(true); } if (contacts > 4) { return(true); } } } } } } return(intersection); }
/// <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); }