/// <summary>
        /// Llena la información de colisión entre dos cajas, una vez se conoce que hay contacto del tipo vértice - cara
        /// </summary>
        /// <param name="one">Caja uno</param>
        /// <param name="two">Caja dos</param>
        /// <param name="toCentre">Distancia entre centros</param>
        /// <param name="data">Información de colisión</param>
        /// <param name="best">Eje de penetración menor</param>
        /// <param name="pen">Pentración menor</param>
        private static void FillPointFaceBoxBox(CollisionBox one, CollisionBox two, Vector3 toCentre, uint best, float pen, ref CollisionData data)
        {
            // Sabemos cual es el eje de la colisión, pero tenemos que conocer con qué cara tenemos que trabjar
            Vector3 normal = one.GetAxis((TransformAxis)best);

            if (Vector3.Dot(one.GetAxis((TransformAxis)best), toCentre) > 0f)
            {
                normal = normal * -1.0f;
            }

            // Obtenemos el vértice
            Vector3 vertex = two.HalfSize;

            if (Vector3.Dot(two.XAxis, normal) < 0f)
            {
                vertex.X = -vertex.X;
            }
            if (Vector3.Dot(two.YAxis, normal) < 0f)
            {
                vertex.Y = -vertex.Y;
            }
            if (Vector3.Dot(two.ZAxis, normal) < 0f)
            {
                vertex.Z = -vertex.Z;
            }

            Contact contact = data.CurrentContact;

            contact.ContactNormal = normal;
            contact.Penetration   = pen;
            contact.ContactPoint  = Vector3.Transform(vertex, two.Transform);
            RigidBody rbOne = one;
            RigidBody rbTwo = two;

            contact.SetBodyData(ref rbOne, ref rbTwo, data.Friction, data.Restitution);
        }
 /// <summary>
 /// Ejecuta el test de intersección entre el OBB y el Triángulo
 /// </summary>
 /// <param name="box">OBB</param>
 /// <param name="tri">Triángulo</param>
 /// <param name="edge">Lado</param>
 /// <param name="axis">Eje a testear (0, 1 ó 2)</param>
 /// <returns>Devuelve verdadero si la intersección no ha sido descartada</returns>
 private static bool OverlapOnAxis(CollisionBox box, Triangle tri, Vector3 edge, int axis)
 {
     if (axis == 0)
     {
         // a.X ^ b.X = (1,0,0) ^ edge
         // axis = Vector3(0, -edge.Z, edge.Y);
         float dPoint1 = tri.Point1.Z * edge.Y - tri.Point1.Y * edge.Z;
         float dPoint2 = tri.Point2.Z * edge.Y - tri.Point2.Y * edge.Z;
         float dPoint3 = tri.Point3.Z * edge.Y - tri.Point3.Y * edge.Z;
         float dhalf   = Math.Abs(box.HalfSize.Y * edge.Z) + Math.Abs(box.HalfSize.Z * edge.Y);
         if (Math.Min(dPoint1, Math.Min(dPoint2, dPoint3)) >= dhalf ||
             Math.Max(dPoint1, Math.Max(dPoint2, dPoint3)) <= -dhalf)
         {
             return(true);
         }
         else
         {
             return(false);
         }
     }
     else if (axis == 1)
     {
         // a.Y ^ b.X = (0,1,0) ^ edge
         // axis = Vector3(edge.Z, 0, -edge.X);
         float dPoint1 = tri.Point1.X * edge.Z - tri.Point1.Z * edge.X;
         float dPoint2 = tri.Point2.X * edge.Z - tri.Point2.Z * edge.X;
         float dPoint3 = tri.Point3.X * edge.Z - tri.Point3.Z * edge.X;
         float dhalf   = Math.Abs(box.HalfSize.X * edge.Z) + Math.Abs(box.HalfSize.Z * edge.X);
         if (Math.Min(dPoint1, Math.Min(dPoint2, dPoint3)) >= dhalf ||
             Math.Max(dPoint1, Math.Max(dPoint2, dPoint3)) <= -dhalf)
         {
             return(true);
         }
         else
         {
             return(false);
         }
     }
     else if (axis == 2)
     {
         // a.Y ^ b.X = (0,0,1) ^ edge
         // axis = Vector3(-edge.Y, edge.X, 0);
         float dPoint1 = tri.Point1.Y * edge.X - tri.Point1.X * edge.Y;
         float dPoint2 = tri.Point2.Y * edge.X - tri.Point2.X * edge.Y;
         float dPoint3 = tri.Point3.Y * edge.X - tri.Point3.X * edge.Y;
         float dhalf   = Math.Abs(box.HalfSize.Y * edge.X) + Math.Abs(box.HalfSize.X * edge.Y);
         if (Math.Min(dPoint1, Math.Min(dPoint2, dPoint3)) >= dhalf ||
             Math.Max(dPoint1, Math.Max(dPoint2, dPoint3)) <= -dhalf)
         {
             return(true);
         }
         else
         {
             return(false);
         }
     }
     else
     {
         throw new Exception();
     }
 }
        /// <summary>
        /// Detecta la intersección entre una caja y un triángulo
        /// </summary>
        /// <param name="box">Caja</param>
        /// <param name="tri">Triángulo</param>
        /// <returns>Devuelve verdadero si hay intersección</returns>
        public static bool BoxAndTri(CollisionBox box, Triangle tri)
        {
            //Transformar la caja a coordenadas locales para poder usar un AABB-Triangle
            Quaternion orientation = box.Orientation;
            Quaternion orientationInv;

            Quaternion.Conjugate(ref orientation, out orientationInv);

            //Llevar el triángulo a las coordenadas de la caja
            Matrix   minv        = Matrix.CreateFromQuaternion(orientationInv);
            Vector3  localPoint1 = Vector3.TransformNormal(tri.Point1 - box.Position, minv);
            Vector3  localPoint2 = Vector3.TransformNormal(tri.Point2 - box.Position, minv);
            Vector3  localPoint3 = Vector3.TransformNormal(tri.Point3 - box.Position, minv);
            Triangle localTri    = new Triangle(localPoint1, localPoint2, localPoint3);

            BoundingBox localTriBounds          = PhysicsMathHelper.GenerateFromTriangle(localTri);
            Vector3     localTriBoundhalfExtent = localTriBounds.GetHalfSizes();
            Vector3     localTriBoundCenter     = localTriBounds.GetCenter();

            float localTriBoundCenterX = Math.Abs(localTriBoundCenter.X);
            float localTriBoundCenterY = Math.Abs(localTriBoundCenter.Y);
            float localTriBoundCenterZ = Math.Abs(localTriBoundCenter.Z);

            if (localTriBoundhalfExtent.X + box.HalfSize.X <= localTriBoundCenterX ||
                localTriBoundhalfExtent.Y + box.HalfSize.Y <= localTriBoundCenterY ||
                localTriBoundhalfExtent.Z + box.HalfSize.Z <= localTriBoundCenterZ)
            {
                //El cuerpo está fuera de la caja
                return(false);
            }

            if (localTriBoundhalfExtent.X + localTriBoundCenterX <= box.HalfSize.X &&
                localTriBoundhalfExtent.Y + localTriBoundCenterY <= box.HalfSize.Y &&
                localTriBoundhalfExtent.Z + localTriBoundCenterZ <= box.HalfSize.Z)
            {
                //El cuerpo está dentro de la caja
                return(true);
            }

            Vector3 point1 = localTri.Point1;
            Vector3 point2 = localTri.Point2;
            Vector3 point3 = localTri.Point3;

            //Obtener eje 1, entre el punto 1 y el 2 del triángulo
            Vector3 edge1;

            Vector3.Subtract(ref point2, ref point1, out edge1);

            //Obtener eje 2, entre el punto 1 y el 3 del triángulo
            Vector3 edge2;

            Vector3.Subtract(ref point3, ref point1, out edge2);

            //Obtener el eje perpendicular entre los dos ejes
            Vector3 crossEdge;

            Vector3.Cross(ref edge1, ref edge2, out crossEdge);

            //Obtener la distancia del triángulo al eje
            float triangleDist = Vector3.Dot(localTri.Point1, crossEdge);

            if (Math.Abs(crossEdge.X * box.HalfSize.X) +
                Math.Abs(crossEdge.Y * box.HalfSize.Y) +
                Math.Abs(crossEdge.Z * box.HalfSize.Z) <= Math.Abs(triangleDist))
            {
                return(false);
            }

            // No hay resultados en los tests con el AABB del triángulo, hay que probar los 9 casos, 3 por eje
            // Al usar la transformación local de la caja, cada plano calculado es paralelo a cada eje de la caja
            // Como son paralelos, el producto es siempre 0 y se puede omitir

            //Obtener eje 3, entre el punto 2 y el 3 del triángulo
            Vector3 edge3;

            Vector3.Subtract(ref point2, ref point3, out edge3);

            if (OverlapOnAxis(box, localTri, edge1, 0))
            {
                return(false);
            }
            if (OverlapOnAxis(box, localTri, edge2, 0))
            {
                return(false);
            }
            if (OverlapOnAxis(box, localTri, edge3, 0))
            {
                return(false);
            }

            if (OverlapOnAxis(box, localTri, edge1, 1))
            {
                return(false);
            }
            if (OverlapOnAxis(box, localTri, edge2, 1))
            {
                return(false);
            }
            if (OverlapOnAxis(box, localTri, edge3, 1))
            {
                return(false);
            }

            if (OverlapOnAxis(box, localTri, edge1, 2))
            {
                return(false);
            }
            if (OverlapOnAxis(box, localTri, edge2, 2))
            {
                return(false);
            }
            if (OverlapOnAxis(box, localTri, edge3, 2))
            {
                return(false);
            }

#if DEBUG
            if (m_DEBUGUSE)
            {
                m_DEBUGTRI[m_DEBUGTRICOUNT++]   = tri;
                m_DEBUGAABB[m_DEBUGAABBCOUNT++] = PhysicsMathHelper.GenerateFromTriangle(tri);
            }
#endif

            return(true);
        }
 /// <summary>
 /// Detecta la intersección entre una caja y un plano
 /// </summary>
 /// <param name="box">Caja</param>
 /// <param name="plane">Plano</param>
 /// <returns>Devuelve verdadero si hay intersección</returns>
 public static bool BoxAndPlane(CollisionBox box, Plane plane)
 {
     return(BoxAndPlane(box, plane.Normal, plane.D));
 }
        /// <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 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 cajas
        /// </summary>
        /// <param name="one">Caja uno</param>
        /// <param name="two">Caja dos</param>
        /// <param name="data">Datos de colisión</param>
        /// <returns>Devuelve verdadero si hay colisión, o falso en el resto de los casos</returns>
        public static bool BoxAndBox(CollisionBox one, CollisionBox two, ref CollisionData data)
        {
            if (data.ContactsLeft <= 0)
            {
                // Si no hay más contactos disponibles se sale de la función.
                return(false);
            }

            // Encontrar el vector entre los dos centros
            Vector3 toCentre = two.Position - one.Position;

            // Se asume que no hay contacto
            float pen  = float.MaxValue;
            uint  best = uint.MaxValue;

            // Chequear cada eje, almacenando penetración y el mejor eje
            if (!TryAxis(one, two, one.XAxis, toCentre, 0, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, one.YAxis, toCentre, 1, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, one.ZAxis, toCentre, 2, ref pen, ref best))
            {
                return(false);
            }

            if (!TryAxis(one, two, two.XAxis, toCentre, 3, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, two.YAxis, toCentre, 4, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, two.ZAxis, toCentre, 5, ref pen, ref best))
            {
                return(false);
            }

            // Almacenar el mejor eje hasta ahora, en el caso de estar en una colisión de ejes paralelos más adelante.
            uint bestSingleAxis = best;

            if (!TryAxis(one, two, Vector3.Cross(one.XAxis, two.XAxis), toCentre, 6, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.XAxis, two.YAxis), toCentre, 7, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.XAxis, two.ZAxis), toCentre, 8, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.YAxis, two.XAxis), toCentre, 9, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.YAxis, two.YAxis), toCentre, 10, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.YAxis, two.ZAxis), toCentre, 11, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.ZAxis, two.XAxis), toCentre, 12, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.ZAxis, two.YAxis), toCentre, 13, ref pen, ref best))
            {
                return(false);
            }
            if (!TryAxis(one, two, Vector3.Cross(one.ZAxis, two.ZAxis), toCentre, 14, ref pen, ref best))
            {
                return(false);
            }

            // Asegurarse de que tenemos un resultado.
            if (best != uint.MaxValue)
            {
                // Tenemos colisión, y tenemos el eje de colisión con menor penetración
                if (best < 3)
                {
                    // Hay un vértice la caja dos en una cara de la caja uno.
                    FillPointFaceBoxBox(one, two, toCentre, best, pen, ref data);

                    data.AddContact();

                    return(true);
                }
                else if (best < 6)
                {
                    // Hay un vértice de la caja uno en una cara de la caja dos.
                    FillPointFaceBoxBox(two, one, toCentre * -1.0f, best - 3, pen, ref data);

                    data.AddContact();

                    return(true);
                }
                else
                {
                    // Contacto canto a canto. Obtener el eje común.
                    best -= 6;
                    uint    oneAxisIndex = best / 3;
                    uint    twoAxisIndex = best % 3;
                    Vector3 oneAxis      = one.GetAxis((TransformAxis)oneAxisIndex);
                    Vector3 twoAxis      = two.GetAxis((TransformAxis)twoAxisIndex);
                    Vector3 axis         = Vector3.Cross(oneAxis, twoAxis);
                    axis.Normalize();

                    // El eje debería apuntar desde la caja uno a la dos.
                    if (Vector3.Dot(axis, toCentre) > 0f)
                    {
                        axis = axis * -1.0f;
                    }

                    // Tenemos los ejes, pero no los cantos.

                    // Cada eje tiene 4 cantos paralelos a él, tenemos que encontrar los 4 de cada caja.
                    // Buscaremos el punto en el centro del canto. Sabemos que su componente en el eje de colisión es 0 y
                    // determinamos cual de los extremos en cada uno de los otros ejes es el más cercano.
                    Vector3 vOne        = one.HalfSize;
                    Vector3 vTwo        = two.HalfSize;
                    float[] ptOnOneEdge = new float[] { vOne.X, vOne.Y, vOne.Z };
                    float[] ptOnTwoEdge = new float[] { vTwo.X, vTwo.Y, vTwo.Z };
                    for (uint i = 0; i < 3; i++)
                    {
                        if (i == oneAxisIndex)
                        {
                            ptOnOneEdge[i] = 0;
                        }
                        else if (Vector3.Dot(one.GetAxis((TransformAxis)i), axis) > 0f)
                        {
                            ptOnOneEdge[i] = -ptOnOneEdge[i];
                        }

                        if (i == twoAxisIndex)
                        {
                            ptOnTwoEdge[i] = 0;
                        }
                        else if (Vector3.Dot(two.GetAxis((TransformAxis)i), axis) < 0f)
                        {
                            ptOnTwoEdge[i] = -ptOnTwoEdge[i];
                        }
                    }

                    vOne.X = ptOnOneEdge[0];
                    vOne.Y = ptOnOneEdge[1];
                    vOne.Z = ptOnOneEdge[2];

                    vTwo.X = ptOnTwoEdge[0];
                    vTwo.Y = ptOnTwoEdge[1];
                    vTwo.Z = ptOnTwoEdge[2];

                    // Pasar a coordenadas del mundo
                    vOne = Vector3.Transform(vOne, one.Transform);
                    vTwo = Vector3.Transform(vTwo, two.Transform);

                    // Tenemos un punto y una dirección para los cantos que colisionan.
                    // Necesitamos encontrar el punto de mayor cercanía de los dos segmentos.
                    float[] vOneAxis = new float[] { one.HalfSize.X, one.HalfSize.Y, one.HalfSize.Z };
                    float[] vTwoAxis = new float[] { two.HalfSize.X, two.HalfSize.Y, two.HalfSize.Z };
                    Vector3 vertex   = ContactPoint(
                        vOne, oneAxis, vOneAxis[oneAxisIndex],
                        vTwo, twoAxis, vTwoAxis[twoAxisIndex],
                        bestSingleAxis > 2);

                    // Llenar el contacto.
                    Contact contact = data.CurrentContact;
                    contact.Penetration   = pen;
                    contact.ContactNormal = axis;
                    contact.ContactPoint  = vertex;
                    contact.SetBodyData(ref one.Body, ref two.Body, data.Friction, data.Restitution);

                    data.AddContact();

                    return(true);
                }
            }

            return(false);
        }
        public static bool BoxAndTri(CollisionBox box, Triangle tri)
        {
            // Pasar el triángulo a coordenadas de la caja
            Triangle trnTri = new Triangle(
                Vector3.Subtract(tri.Point1, box.Position),
                Vector3.Subtract(tri.Point2, box.Position),
                Vector3.Subtract(tri.Point3, box.Position));

            // Obtener los ejes del triángulo
            Vector3 edge0 = Vector3.Subtract(trnTri.Point2, trnTri.Point1);
            Vector3 edge1 = Vector3.Subtract(trnTri.Point3, trnTri.Point2);
            Vector3 edge2 = Vector3.Subtract(trnTri.Point1, trnTri.Point3);

            // Comprobar si la caja está sobre el triángulo
            float fex = Math.Abs(edge0.X);
            float fey = Math.Abs(edge0.Y);
            float fez = Math.Abs(edge0.Z);

            if (!AXISTEST_X01(trnTri.Point1, trnTri.Point3, box.HalfSize, edge0.Z, edge0.Y, fez, fey))
            {
                return(false);
            }
            if (!AXISTEST_Y02(trnTri.Point1, trnTri.Point3, box.HalfSize, edge0.Z, edge0.X, fez, fex))
            {
                return(false);
            }
            if (!AXISTEST_Z12(trnTri.Point2, trnTri.Point3, box.HalfSize, edge0.Y, edge0.X, fey, fex))
            {
                return(false);
            }

            fex = Math.Abs(edge1.X);
            fey = Math.Abs(edge1.Y);
            fez = Math.Abs(edge1.Z);

            if (!AXISTEST_X01(trnTri.Point1, trnTri.Point3, box.HalfSize, edge1.Z, edge1.Y, fez, fey))
            {
                return(false);
            }
            if (!AXISTEST_Y02(trnTri.Point1, trnTri.Point3, box.HalfSize, edge1.Z, edge1.X, fez, fex))
            {
                return(false);
            }
            if (!AXISTEST_Z0(trnTri.Point1, trnTri.Point2, box.HalfSize, edge1.Y, edge1.X, fey, fex))
            {
                return(false);
            }

            fex = Math.Abs(edge2.X);
            fey = Math.Abs(edge2.Y);
            fez = Math.Abs(edge2.Z);

            if (!AXISTEST_X2(trnTri.Point1, trnTri.Point2, box.HalfSize, edge2.Z, edge2.Y, fez, fey))
            {
                return(false);
            }
            if (!AXISTEST_Y1(trnTri.Point1, trnTri.Point2, box.HalfSize, edge2.Z, edge2.X, fez, fex))
            {
                return(false);
            }
            if (!AXISTEST_Z12(trnTri.Point2, trnTri.Point3, box.HalfSize, edge2.Y, edge2.X, fey, fex))
            {
                return(false);
            }

            // Hay intersección
            return(true);
        }
        /// <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);
        }