raySphere function

double raySphere(
  1. Ray ray,
  2. Vector3 centre,
  3. double radius
)

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
}