Source: shape/bounding-sphere.js

Object.assign(pc, function () {
    var tmpVecA = new pc.Vec3();
    var tmpVecB = new pc.Vec3();
    var tmpVecC = new pc.Vec3();
    var tmpVecD = new pc.Vec3();

    /**
     * @constructor
     * @name pc.BoundingSphere
     * @classdesc A bounding sphere is a volume for facilitating fast intersection testing.
     * @description Creates a new bounding sphere.
     * @example
     * // Create a new bounding sphere centered on the origin with a radius of 0.5
     * var sphere = new pc.BoundingSphere();
     * @param {pc.Vec3} [center] The world space coordinate marking the center of the sphere. The constructor takes a reference of this parameter.
     * @param {Number} [radius] The radius of the bounding sphere. Defaults to 0.5.
     */
    function BoundingSphere(center, radius) {
        this.center = center || new pc.Vec3(0, 0, 0);
        this.radius = radius === undefined ? 0.5 : radius;
    }

    Object.assign(BoundingSphere.prototype, {
        containsPoint: function (point) {
            var lenSq = tmpVecA.sub2(point, this.center).lengthSq();
            var r = this.radius;
            return lenSq < r * r;
        },

        compute: function (vertices) {
            var i;
            var numVerts = vertices.length / 3;

            var vertex = tmpVecA;
            var avgVertex = tmpVecB;
            var sum = tmpVecC;

            // FIRST PASS:
            // Find the "average vertex", which is the sphere's center...

            for (i = 0; i < numVerts; i++) {
                vertex.set(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
                sum.addSelf(vertex);

                // apply a part-result to avoid float-overflows
                if (i % 100 === 0) {
                    sum.scale(1 / numVerts);
                    avgVertex.add(sum);
                    sum.set(0, 0, 0);
                }
            }

            sum.scale(1 / numVerts);
            avgVertex.add(sum);

            this.center.copy(avgVertex);

            // SECOND PASS:
            // Find the maximum (squared) distance of all vertices to the center...
            var maxDistSq = 0;
            var centerToVert = tmpVecD;

            for (i = 0; i < numVerts; i++) {
                vertex.set(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);

                centerToVert.sub2(vertex, this.center);
                maxDistSq = Math.max(centerToVert.lengthSq(), maxDistSq);
            }

            this.radius = Math.sqrt(maxDistSq);
        },

        /**
         * @function
         * @name pc.BoundingSphere#intersectsRay
         * @description Test if a ray intersects with the sphere.
         * @param {pc.Ray} ray Ray to test against (direction must be normalized).
         * @param {pc.Vec3} [point] If there is an intersection, the intersection point will be copied into here.
         * @returns {Boolean} True if there is an intersection.
         */
        intersectsRay: function (ray, point) {
            var m = tmpVecA.copy(ray.origin).sub(this.center);
            var b = m.dot(tmpVecB.copy(ray.direction).normalize());
            var c = m.dot(m) - this.radius * this.radius;

            // exit if ray's origin outside of sphere (c > 0) and ray pointing away from s (b > 0)
            if (c > 0 && b > 0)
                return null;

            var discr = b * b - c;
            // a negative discriminant corresponds to ray missing sphere
            if (discr < 0)
                return false;

            // ray intersects sphere, compute smallest t value of intersection
            var t = Math.abs(-b - Math.sqrt(discr));

            // if t is negative, ray started inside sphere so clamp t to zero
            if (point)
                point.copy(ray.direction).scale(t).add(ray.origin);

            return true;
        },

        /**
         * @function
         * @name pc.BoundingSphere#intersectsBoundingSphere
         * @description Test if a Bounding Sphere is overlapping, enveloping, or inside this Bounding Sphere.
         * @param {pc.BoundingSphere} sphere Bounding Sphere to test.
         * @returns {Boolean} true if the Bounding Sphere is overlapping, enveloping, or inside this Bounding Sphere and false otherwise.
         */
        intersectsBoundingSphere: function (sphere) {
            tmpVecA.sub2(sphere.center, this.center);
            var totalRadius = sphere.radius + this.radius;
            if (tmpVecA.lengthSq() <= totalRadius * totalRadius) {
                return true;
            }

            return false;
        }
    });

    return {
        BoundingSphere: BoundingSphere
    };
}());