48 lines
1.5 KiB
Zig
48 lines
1.5 KiB
Zig
const math = @import("std").math;
|
|
|
|
const Point3 = @import("vec3.zig").Point3;
|
|
const Vec3 = @import("vec3.zig").Vec3;
|
|
const HitRecord = @import("hittable.zig").HitRecord;
|
|
const Ray = @import("ray.zig").Ray;
|
|
const Material = @import("material.zig").Material;
|
|
|
|
pub const Sphere = struct {
|
|
center: Point3,
|
|
radius: f32,
|
|
material: Material,
|
|
|
|
pub fn hit(self: Sphere, ray: Ray, t_min: f32, t_max: f32) ?HitRecord {
|
|
const oc = ray.origin.sub(self.center);
|
|
const a = ray.direction.length_squared();
|
|
const half_b = Vec3.dot(oc, ray.direction);
|
|
const c = oc.length_squared() - self.radius * self.radius;
|
|
|
|
const discriminant = half_b * half_b - a * c;
|
|
if (discriminant < 0) {
|
|
return null;
|
|
}
|
|
|
|
const sqrtd = math.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 rayAtRoot = ray.at(root);
|
|
var hitLocal = HitRecord{
|
|
.t = root,
|
|
.p = rayAtRoot,
|
|
.normal = rayAtRoot.sub(self.center).div(self.radius),
|
|
.front_face = false,
|
|
.material = self.material,
|
|
};
|
|
const outwardNormal = hitLocal.p.sub(self.center).div(self.radius);
|
|
HitRecord.setFaceNormal(&hitLocal, ray, outwardNormal);
|
|
return hitLocal;
|
|
}
|
|
}; |