public static bool ClosestPointOnSurface(Collider collider, Vector3 to, float radius, out Vector3 closestPointOnSurface)
        {
            if (collider is BoxCollider)
            {
                closestPointOnSurface = SuperCollider.ClosestPointOnSurface((BoxCollider)collider, to);
                return(true);
            }
            else if (collider is SphereCollider)
            {
                closestPointOnSurface = SuperCollider.ClosestPointOnSurface((SphereCollider)collider, to);
                return(true);
            }
            else if (collider is CapsuleCollider)
            {
                closestPointOnSurface = SuperCollider.ClosestPointOnSurface((CapsuleCollider)collider, to);
                return(true);
            }
            else if (collider is MeshCollider)
            {
                BSPTree bsp = collider.GetComponent <BSPTree>();

                if (bsp != null)
                {
                    closestPointOnSurface = bsp.ClosestPointOn(to, radius);
                    return(true);
                }

                BruteForceMesh bfm = collider.GetComponent <BruteForceMesh>();

                if (bfm != null)
                {
                    closestPointOnSurface = bfm.ClosestPointOn(to);
                    return(true);
                }
            }
            else if (collider is TerrainCollider)
            {
                closestPointOnSurface = SuperCollider.ClosestPointOnSurface((TerrainCollider)collider, to, radius, false);
                return(true);
            }

            Debug.LogError(string.Format("{0} does not have an implementation for ClosestPointOnSurface; GameObject.Name='{1}'", collider.GetType(), collider.gameObject.name));
            closestPointOnSurface = Vector3.zero;
            return(false);
        }
        /// <summary>
        /// Check if any of the CollisionSpheres are colliding with any walkable objects in the world.
        /// If they are, apply a proper pushback and retrieve the collision data
        /// </summary>
        void RecursivePushback(int depth, int maxDepth)
        {
            PushIgnoredColliders();

            bool contact = false;

            foreach (var sphere in spheres)
            {
                foreach (Collider col in Physics.OverlapSphere((SpherePosition(sphere)), radius, Walkable, triggerInteraction))
                {
                    Vector3 position = SpherePosition(sphere);
                    Vector3 contactPoint;
                    bool    contactPointSuccess = SuperCollider.ClosestPointOnSurface(col, position, radius, out contactPoint);

                    if (!contactPointSuccess)
                    {
                        return;
                    }

                    if (debugPushbackMesssages)
                    {
                        DebugDraw.DrawMarker(contactPoint, 2.0f, Color.cyan, 0.0f, false);
                    }

                    Vector3 v = contactPoint - position;
                    if (v != Vector3.zero)
                    {
                        // Cache the collider's layer so that we can cast against it
                        int layer = col.gameObject.layer;

                        col.gameObject.layer = TemporaryLayerIndex;

                        // Check which side of the normal we are on
                        bool facingNormal = Physics.SphereCast(new Ray(position, v.normalized), TinyTolerance, v.magnitude + TinyTolerance, 1 << TemporaryLayerIndex);

                        col.gameObject.layer = layer;

                        // Orient and scale our vector based on which side of the normal we are situated
                        if (facingNormal)
                        {
                            if (Vector3.Distance(position, contactPoint) < radius)
                            {
                                v = v.normalized * (radius - v.magnitude) * -1;
                            }
                            else
                            {
                                // A previously resolved collision has had a side effect that moved us outside this collider
                                continue;
                            }
                        }
                        else
                        {
                            v = v.normalized * (radius + v.magnitude);
                        }

                        contact = true;

                        transform.position += v;

                        col.gameObject.layer = TemporaryLayerIndex;

                        // Retrieve the surface normal of the collided point
                        RaycastHit normalHit;

                        Physics.SphereCast(new Ray(position + v, contactPoint - (position + v)), TinyTolerance, out normalHit, 1 << TemporaryLayerIndex);

                        col.gameObject.layer = layer;

                        SuperCollisionType superColType = col.gameObject.GetComponent <SuperCollisionType>();

                        if (superColType == null)
                        {
                            superColType = defaultCollisionType;
                        }

                        // Our collision affected the collider; add it to the collision data
                        var collision = new SuperCollision()
                        {
                            collisionSphere    = sphere,
                            superCollisionType = superColType,
                            gameObject         = col.gameObject,
                            point  = contactPoint,
                            normal = normalHit.normal
                        };

                        collisionData.Add(collision);
                    }
                }
            }

            PopIgnoredColliders();

            if (depth < maxDepth && contact)
            {
                RecursivePushback(depth + 1, maxDepth);
            }
        }