function sphere(center, radius) {
return function(ray, tMin, tMax, hit) {
const oc = vec3.sub(vec3.create(), ray.origin, center);
const a = vec3.squaredLength(ray.direction);
const halfB = vec3.dot(oc, ray.direction);
const c = vec3.squaredLength(oc) - radius*radius;
const discriminant = halfB*halfB - a*c;
if (discriminant < 0) return false;
const sqrtD = Math.sqrt(discriminant);
let root = (-halfB - sqrtD) / a;
if (root < tMin || tMax < root) {
root = (-halfB + sqrtD) / a;
if (root < tMin || tMax < root) return false;
}
hit.t = root;
hit.p = ray(hit.t);
const outwardNormal = vec3.scale(vec3.create(), vec3.subtract(vec3.create(), hit.p, center), 1 / radius);
hit.frontFace = vec3.dot(ray.direction, outwardNormal) < 0;
hit.normal = hit.frontFace ? outwardNormal : -outwardNormal;
return true;
}
}