this repo has no description
at main 2.6 kB view raw
1const math = @import("std").math; 2 3const zm = @import("zmath"); 4 5const AABB = @import("../AABB.zig"); 6const IntervalF32 = @import("../interval.zig").IntervalF32; 7const Ray = @import("../Ray.zig"); 8const HitRecord = @import("../hittable.zig").HitRecord; 9const Material = @import("../material.zig").Material; 10 11const Sphere = @This(); 12 13center: zm.Vec, 14radius: f32, 15mat: *Material, 16is_moving: bool = false, 17center_vec: zm.Vec = zm.f32x4s(0), 18bbox: AABB, 19 20pub fn init(center: zm.Vec, radius: f32, mat: *Material) Sphere { 21 const rvec = zm.f32x4s(radius); 22 return Sphere{ 23 .center = center, 24 .radius = @max(0, radius), 25 .mat = mat, 26 .bbox = AABB.initP(center - rvec, center + rvec), 27 }; 28} 29 30pub fn initMoving(center1: zm.Vec, center2: zm.Vec, radius: f32, mat: *Material) Sphere { 31 const rvec = zm.f32x4s(radius); 32 const box1 = AABB.initP(center1 - rvec, center1 + rvec); 33 const box2 = AABB.initP(center2 - rvec, center2 + rvec); 34 35 return Sphere{ 36 .center = center1, 37 .radius = @max(0, radius), 38 .mat = mat, 39 .is_moving = true, 40 .center_vec = center2 - center1, 41 .bbox = AABB.initAB(&box1, &box2), 42 }; 43} 44 45pub inline fn boundingBox(self: *Sphere) AABB { 46 return self.bbox; 47} 48 49pub fn hit(self: *const Sphere, r: *Ray, ray_t: IntervalF32) ?HitRecord { 50 const center = self.sphereCenter(r.tm); 51 const oc = r.orig - center; 52 const a = zm.lengthSq3(r.dir)[0]; 53 const half_b = zm.dot3(oc, r.dir)[0]; 54 const c = zm.dot3(oc, oc)[0] - self.radius * self.radius; 55 56 const discriminant = half_b * half_b - a * c; 57 if (discriminant < 0) return null; 58 59 const sqrtd = @sqrt(discriminant); 60 61 // Find the nearest root that lies in the acceptable range 62 var root = (-half_b - sqrtd) / a; 63 if (!ray_t.surrounds(root)) { 64 root = (-half_b + sqrtd) / a; 65 if (!ray_t.surrounds(root)) return null; 66 } 67 68 var rec = HitRecord{ 69 .t = root, 70 .p = r.at(root), 71 .mat = self.mat, 72 }; 73 74 const outward_normal = (rec.p - self.center) / zm.f32x4s(self.radius); 75 rec.setFaceNormal(r, outward_normal); 76 setSphereUV(&rec, outward_normal); 77 78 return rec; 79} 80 81pub inline fn sphereCenter(self: *const Sphere, time: f32) zm.Vec { 82 if (!self.is_moving) return self.center; 83 return self.center + zm.f32x4s(time) * self.center_vec; 84} 85 86fn setSphereUV(rec: *HitRecord, p: zm.Vec) void { 87 const theta = math.acos(-p[1]); 88 const phi = math.atan2(-p[2], p[0]) + math.pi; 89 90 rec.u = phi / (2 * math.pi); 91 rec.v = theta / phi; 92}