const std = @import("std"); const Random = std.rand.Random; const vec3 = @import("vec3.zig"); const Color = @import("color.zig").Color; const Ray = @import("ray.zig").Ray; const HitRecord = @import("hittable.zig").HitRecord; pub const MaterialType = enum { lambertian, metal, }; pub const Lambertian = struct { color: Color, pub fn scatter(self: Lambertian, ray: Ray, hit: HitRecord, rng: *Random) ?ScatteredRay { var scatterDirection = hit.normal.add(vec3.random_unit_vector(rng)); // Catch degenerate scatter direction if (scatterDirection.nearZero()) { scatterDirection = hit.normal; } return ScatteredRay{ .ray = Ray{ .origin = hit.p, .direction = scatterDirection}, .color = self.color, }; } }; pub const Metal = struct { color: Color, // fuzzy: f32, pub fn scatter(self: Metal, ray: Ray, hit: HitRecord, rng: *Random) ?ScatteredRay { const reflected = ray.direction.unit().reflect(hit.normal); const scattered = Ray{ .origin = hit.p, .direction = reflected }; if (scattered.direction.dot(hit.normal) <= 0) { return null; } return ScatteredRay{ .ray = scattered, .color = self.color, }; } }; pub const ScatteredRay = struct { ray: Ray, color: Color, }; pub const Material = union(MaterialType) { lambertian: Lambertian, metal: Metal, }; pub fn scatter(ray: Ray, hit: HitRecord, rng: *Random) ?ScatteredRay { return switch (hit.material) { .lambertian => |m| m.scatter(ray, hit, rng), .metal => |m| m.scatter(ray, hit, rng), }; }