raytracers/zigrtiow/src/sphere.zig

52 lines
1.5 KiB
Zig

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;
}
};