const vec = @import("./vec.zig"); const Ray = @import("./ray.zig").Ray; const HitRecord = @import("./hittable.zig").HitRecord; const Vec3 = vec.Vec3; const Color = vec.Color; const random_unit_vector = vec.random_unit_vector; pub const Material = union(enum) { labertian: Labertian, metal: Metal, pub fn scatter(material: Material, r_in: Ray, rec: HitRecord) ?ScatterRec { return switch (material) { .labertian => |labertian| labertian.scatter(r_in, rec), .metal => |metal| metal.scatter(r_in, rec), }; } }; pub const ScatterRec = struct { attenuation: Color, scattered: Ray }; pub const Labertian = struct { albedo: Vec3, pub fn scatter(labertian: Labertian, r_in: Ray, rec: HitRecord) ?ScatterRec { _ = r_in; var scatter_direction = rec.normal.add(random_unit_vector()); if (scatter_direction.near_zero()) { scatter_direction = rec.normal; } return ScatterRec{ .scattered = Ray.init(rec.p, scatter_direction), .attenuation = labertian.albedo, }; } }; pub const Metal = struct { albedo: Vec3, pub fn scatter(metal: Metal, r_in: Ray, rec: HitRecord) ?ScatterRec { const reflected = reflect(r_in.direction().unit(), rec.normal); const scattered = Ray.init(rec.p, reflected); const attenuation = metal.albedo; if (scattered.direction().dot(rec.normal) > 0) { return ScatterRec{ .scattered = scattered, .attenuation = attenuation, }; } else { return null; } } fn reflect(v: Vec3, n: Vec3) Vec3 { return v.sub(n.scale(v.dot(n) * 2)); } };