const vec = @import("./vec.zig"); const ray = @import("./ray.zig"); const hittable = @import("./hittable.zig"); const Vec3 = vec.Vec3; const Point3 = vec.Point3; const Ray = ray.Ray; const HitRecord = hittable.HitRecord; pub const Sphere = struct { center: Point3, radius: f32, pub fn init(center: Point3, radius: f32) Sphere { return Sphere{ .center = center, .radius = radius, }; } pub fn hit(sphere: Sphere, r: Ray, t_min: f32, t_max: f32) ?HitRecord { const center = sphere.center; const radius = sphere.radius; const oc = r.origin().sub(center); const a = r.direction().length_squared(); const half_b = Vec3.dot(oc, r.direction()); const c = oc.length_squared() - radius * radius; const discriminant = half_b * half_b - a * c; if (discriminant < 0) return null; const sqrtd = @sqrt(discriminant); // Find the nearest root that lies in the acceptable range. var root = (-half_b - sqrtd) / a; if ((root < t_min) or (t_max < root)) { root = (-half_b + sqrtd) / a; if ((root < t_min) or (t_max < root)) return null; } const p = r.at(root); const outward_normal = p.sub(center).scale(1 / radius); var hr = HitRecord{ .t = root, .p = p, .normal = Vec3.init(0, 0, 0), .front_face = false, }; hr.set_face_normal(r, outward_normal); return hr; } };