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);
    }
Exemple #3
0
    //------------------------------------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);
    }