public static bool BoxPlaneCollisionOccured(PSI_Collider_Box boxCol, PSI_Collider_Plane planeCol, out Vector3 point) { // Projecting the box vertices onto the plane. If a the vertex that is closest // to the plane intersects it then the box and plane are colliding. var boxVerts = boxCol.GetVertices(); float overlap = float.PositiveInfinity; bool collisionOccured = false; point = Vector3.zero; for (int i = 0; i < boxVerts.Length; i++) { float distanceToPlane; if (!planeCol.PosIsWithinPlaneBounds(boxVerts[i], out distanceToPlane)) { continue; } if (distanceToPlane <= 0f && Mathf.Abs(distanceToPlane) < boxCol.pSize.magnitude) { collisionOccured = true; if (distanceToPlane < overlap) { overlap = distanceToPlane; } } } if (collisionOccured) { // Resolve any overlap between the box and the plane. ResolveCollisionOverlaps(boxCol, planeCol, -planeCol.pNormal.normalized, overlap); // Getting the collision point by averaging the closest box verts to the plane. boxVerts = boxCol.GetVertices(); int touchingVertexCount = 0; for (int i = 0; i < boxVerts.Length; i++) { float distanceToPlane; if (!planeCol.PosIsWithinPlaneBounds(boxVerts[i], out distanceToPlane)) { continue; } if (distanceToPlane <= 0.01f) { point += boxVerts[i]; touchingVertexCount++; } } point /= (float)touchingVertexCount; // Calculate and apply the collision impulse to the box. ApplyImpulses(boxCol, planeCol, -planeCol.pNormal.normalized, point); // Apply friction to the box. ApplyFriction(boxCol, planeCol, point); return(true); } return(false); }
public static bool BoxBoxCollisionOccured(PSI_Collider_Box col1, PSI_Collider_Box col2, out Vector3 point) { point = Vector3.zero; // Determine the axis to check during SAT. var col1Axes = col1.GetAxes(); var col2Axes = col2.GetAxes(); var axesToCheck = new Vector3[] { col1Axes[0], col1Axes[1], col1Axes[2], col2Axes[0], col2Axes[1], col2Axes[2], Vector3.Cross(col1Axes[0], col2Axes[0]), Vector3.Cross(col1Axes[0], col2Axes[1]), Vector3.Cross(col1Axes[0], col2Axes[2]), Vector3.Cross(col1Axes[1], col2Axes[0]), Vector3.Cross(col1Axes[1], col2Axes[1]), Vector3.Cross(col1Axes[1], col2Axes[2]), Vector3.Cross(col1Axes[2], col2Axes[0]), Vector3.Cross(col1Axes[2], col2Axes[1]), Vector3.Cross(col1Axes[2], col2Axes[2]) }; // Determine the verts to check during SAT. var col1Verts = col1.GetVertices(); var col2Verts = col2.GetVertices(); // Determine if the boxes are colliding using SAT. Vector3 minOverlapAxis = Vector3.zero; float minOverlap = 0f; bool isColliding = CheckForOverlapUsingSAT(axesToCheck, col2Verts, col1Verts, out minOverlapAxis, out minOverlap) || CheckForOverlapUsingSAT(axesToCheck, col1Verts, col2Verts, out minOverlapAxis, out minOverlap); if (isColliding) { // Estimate the collision point by converting the box faces to planes and projecting the vertices of the other // box onto them. The projection points with the smallest distance are averaged to give the collision point. var facePlanes = new PSI_Plane[][] { col1.GetFacePlanes(), col2.GetFacePlanes() }; var verts = new Vector3[][] { col1Verts, col2Verts }; var contactPoints = new List <Vector3>(); float contactPointDist = float.PositiveInfinity; for (int i = 0; i < 2; i++) { foreach (var plane in facePlanes[i]) { foreach (var vert in verts[1 - i]) { float projectionDist = float.PositiveInfinity; if (plane.PointProjectsOntoPlane(vert, out projectionDist)) { projectionDist = Mathf.Abs(projectionDist); if (Mathf.Abs(projectionDist - contactPointDist) < float.Epsilon) { contactPoints.Add(vert); } else if (projectionDist < contactPointDist) { contactPoints.Clear(); contactPoints.Add(vert); contactPointDist = projectionDist; } } } } } point = Vector3.zero; foreach (var contactPoint in contactPoints) { point += contactPoint; } point /= contactPoints.Count; // Resolve any overlap between the boxes. var collisionAxis = CorrectCollisionAxisDirection(col2.pPosition, col1.pPosition, minOverlapAxis); ResolveCollisionOverlaps(col1, col2, collisionAxis, minOverlap); // Calculate and apply the collision impulse to the boxes. ApplyImpulses(col1, col2, collisionAxis, point); return(true); } return(false); }