52 lines
1.5 KiB
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;
|
|
}
|
|
};
|