public static bool SpherePlaneCollisionOccured(PSI_Collider_Sphere sphereCol, PSI_Collider_Plane planeCol, out Vector3 point) { // Determine the signed distance to from the sphere to its projected point on the plane. float distToProjectedPoint = Vector3.Dot(planeCol.pNormal, (sphereCol.pPosition - planeCol.pPosition)); // Determine the spheres projected point on the plane. point = sphereCol.pPosition - distToProjectedPoint * planeCol.pNormal; // Generate 4 triangles between the corners of the plane and the projected point. var planeVerts = planeCol.GetVertices(); var triangles = new Vector3[4, 3]; for (int i = 0; i < 4; i++) { triangles[i, 0] = point; triangles[i, 1] = planeVerts[i]; triangles[i, 2] = planeVerts[(i == 3) ? 0 : i + 1]; } // Sum the area of the traingles. float totalTriArea = 0.0f; for (int i = 0; i < 4; i++) { float a = Vector3.Distance(triangles[i, 0], triangles[i, 1]); float b = Vector3.Distance(triangles[i, 1], triangles[i, 2]); float c = Vector3.Distance(triangles[i, 2], triangles[i, 0]); float s = (a + b + c) / 2; totalTriArea += Mathf.Sqrt(s * (s - a) * (s - b) * (s - c)); } // Determine if a collision occured by checking if the sphere is overlapping with the plane and the projected point // is within the extents of the plane by checking the sum area of the triangles is equal to the size of the plane. bool isColliding = Mathf.Abs(totalTriArea - planeCol.pArea) < 0.01f && Mathf.Abs(distToProjectedPoint) <= sphereCol.pRadius; if (isColliding) { // Resolve any overlap between the sphere and the plane. var collisionAxis = CorrectCollisionAxisDirection(planeCol.pPosition, sphereCol.pPosition, point - sphereCol.pPosition); var overlap = collisionAxis.magnitude - sphereCol.pRadius; ResolveCollisionOverlaps(sphereCol, planeCol, collisionAxis, overlap); // Calculate and apply the collision impulse to the sphere. ApplyImpulses(sphereCol, planeCol, collisionAxis, point); // Apply friction to the sphere. ApplyFriction(sphereCol, planeCol, point); return(true); } return(false); }
private static void ApplyFriction(PSI_Collider col, PSI_Collider_Plane planeCol, Vector3 collisionPoint) { // Calculating and applying friction to a body moving along a plane. if (!col.pRigidbody) { return; } var incline = Vector3.Angle(Vector3.up, planeCol.pNormal); var normalForce = col.pRigidbody.Mass * 9.81f * Mathf.Cos(incline); var coeffFriction = col.pRigidbody.CoeffOfFrict; var friction = coeffFriction * normalForce; col.pRigidbody.AddFrictionAtPoint(friction * -col.pRigidbody.Velocity.normalized, collisionPoint); }
//------------------------------------Private Functions------------------------------------- private void CheckForCollision(PSI_Collider col1, PSI_Collider col2) { bool collisionOccurred = false; PSI_Collision collision = new PSI_Collision(); collision.col1 = col1; collision.col2 = col2; // Sphere on sphere. if (col1.pType == ColliderType.Sphere && col2.pType == ColliderType.Sphere) { collisionOccurred = PSI_PhysicsUtils.SphereSphereCollisionCheck((PSI_Collider_Sphere)col1, (PSI_Collider_Sphere)col2, out collision.point); } // Sphere on plane. if ((col1.pType == ColliderType.Sphere && col2.pType == ColliderType.Plane) || (col1.pType == ColliderType.Plane && col2.pType == ColliderType.Sphere)) { PSI_Collider_Sphere sphere = (PSI_Collider_Sphere)((col1.pType == ColliderType.Sphere) ? col1 : col2); PSI_Collider_Plane plane = (PSI_Collider_Plane)((col1.pType == ColliderType.Sphere) ? col2 : col1); if (PSI_PhysicsUtils.SpherePlaneCollisionOccured(sphere, plane, out collision.point)) { collisionOccurred = true; } } // Sphere on box. if ((col1.pType == ColliderType.Sphere && col2.pType == ColliderType.Box) || (col1.pType == ColliderType.Box && col2.pType == ColliderType.Sphere)) { PSI_Collider_Sphere sphere = (PSI_Collider_Sphere)((col1.pType == ColliderType.Sphere) ? col1 : col2); PSI_Collider_Box box = (PSI_Collider_Box)((col1.pType == ColliderType.Sphere) ? col2 : col1); if (PSI_PhysicsUtils.SphereBoxCollisionOccured(sphere, box, out collision.point)) { collisionOccurred = true; } } // Box on box. if ((col1.pType == ColliderType.Box && col2.pType == ColliderType.Box)) { if (PSI_PhysicsUtils.BoxBoxCollisionOccured((PSI_Collider_Box)col1, (PSI_Collider_Box)col2, out collision.point)) { collisionOccurred = true; } } // Box on plane. if ((col1.pType == ColliderType.Box && col2.pType == ColliderType.Plane) || (col1.pType == ColliderType.Plane && col2.pType == ColliderType.Box)) { PSI_Collider_Box box = (PSI_Collider_Box)((col1.pType == ColliderType.Box) ? col1 : col2); PSI_Collider_Plane plane = (PSI_Collider_Plane)((col1.pType == ColliderType.Box) ? col2 : col1); if (PSI_PhysicsUtils.BoxPlaneCollisionOccured(box, plane, out collision.point)) { collisionOccurred = true; } } if (collisionOccurred) { mCollisionData.Add(collision); } }
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); }