raySphere function
Distance along ray to a sphere, or kNoHit. Inside counts as 0.
Implementation
double raySphere(Ray ray, Vector3 centre, double radius) {
if (radius <= 0.0) return kNoHit;
// Solved with the origin-to-centre vector rather than by expanding the
// quadratic, which keeps the numbers small when the sphere is far away.
final ocX = ray.origin.x - centre.x;
final ocY = ray.origin.y - centre.y;
final ocZ = ray.origin.z - centre.z;
final d = ray.direction;
final a = d.x * d.x + d.y * d.y + d.z * d.z;
if (a < 1e-20) return kNoHit;
final b = 2.0 * (ocX * d.x + ocY * d.y + ocZ * d.z);
final c = ocX * ocX + ocY * ocY + ocZ * ocZ - radius * radius;
final discriminant = b * b - 4.0 * a * c;
if (discriminant < 0.0) return kNoHit;
final root = math.sqrt(discriminant);
final inverse = 1.0 / (2.0 * a);
final near = (-b - root) * inverse;
if (near >= 0.0) return near;
final far = (-b + root) * inverse;
if (far < 0.0) return kNoHit;
return 0.0; // the origin is inside
}