From d15a9e6c3e1b4f131ae138d9a12e380bd5529087 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sat, 6 Aug 2022 08:06:53 -0700 Subject: [PATCH] zigrtiow: add material property to hittable. --- zigrtiow/src/hittable.zig | 3 +++ zigrtiow/src/main.zig | 22 +++++++++++++++------- zigrtiow/src/material.zig | 34 ++++++++++++++++++++++++++++++++++ zigrtiow/src/sphere.zig | 7 ++++++- zigrtiow/src/vec.zig | 9 +++++++++ 5 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 zigrtiow/src/material.zig diff --git a/zigrtiow/src/hittable.zig b/zigrtiow/src/hittable.zig index d009b3f..3dbffd3 100644 --- a/zigrtiow/src/hittable.zig +++ b/zigrtiow/src/hittable.zig @@ -1,6 +1,8 @@ const vec = @import("./vec.zig"); const ray = @import("./ray.zig"); +const Material = @import("./material.zig").Material; + const Sphere = @import("./sphere.zig").Sphere; const HittableList = @import("./hittable_list.zig").HittableList; @@ -25,6 +27,7 @@ pub const HitRecord = struct { normal: Vec3, t: f32, front_face: bool, + material: Material, pub fn set_face_normal(hr: *HitRecord, r: Ray, outward_normal: Vec3) void { hr.front_face = r.direction().dot(outward_normal) < 0; diff --git a/zigrtiow/src/main.zig b/zigrtiow/src/main.zig index 9494faf..d4912c2 100644 --- a/zigrtiow/src/main.zig +++ b/zigrtiow/src/main.zig @@ -6,27 +6,31 @@ const vec = @import("./vec.zig"); const sphere = @import("./sphere.zig"); const hittable = @import("./hittable.zig"); const hittable_list = @import("./hittable_list.zig"); +const material = @import("./material.zig"); const Camera = camera.Camera; const Color = vec.Color; const Hittable = hittable.Hittable; const HittableList = hittable_list.HittableList; +const Labertian = material.Labertian; +const Material = material.Material; const Point3 = vec.Point3; const Ray = ray.Ray; const Sphere = sphere.Sphere; const Vec3 = vec.Vec3; -const random_in_hemisphere = vec.random_in_hemisphere; const info = std.log.info; +const random_in_hemisphere = vec.random_in_hemisphere; const write_color = color.write_color; fn ray_color(r: Ray, world: Hittable, depth: isize) Color { // If we've exceeded the ray bounce limit, no more light is gathered. if (depth <= 0) return Color.init(0, 0, 0); - var hit = world.hit(r, 0.0001, std.math.inf(f32)); - if (hit) |rec| { - const target = rec.p.add(rec.normal.add(random_in_hemisphere(rec.normal))); - return ray_color(Ray.init(rec.p, target.sub(rec.p)), world, depth - 1).scale(0.5); + if (world.hit(r, 0.0001, std.math.inf(f32))) |hit_rec| { + if (hit_rec.material.scatter(r, hit_rec)) |scatter_rec| { + return scatter_rec.attenuation.mul(ray_color(scatter_rec.scattered, world, depth - 1)); + } + return Color.init(0, 0, 0); } var unit_direction = r.direction().unit(); const t = 0.5 * (unit_direction.y() + 1); @@ -43,8 +47,12 @@ pub fn main() anyerror!void { // World var tmp_world = HittableList.init(); - try tmp_world.add(Hittable{ .sphere = Sphere.init(Point3.init(0, 0, -1), 0.5) }); - try tmp_world.add(Hittable{ .sphere = Sphere.init(Point3.init(0, -100.5, -1), 100) }); + + const material_ground = Material{ .labertian = Labertian{ .albedo = Color.init(0.8, 0.8, 0.0) } }; + const material_center = Material{ .labertian = Labertian{ .albedo = Color.init(0.7, 0.3, 0.3) } }; + + try tmp_world.add(Hittable{ .sphere = Sphere.init(Point3.init(0, -100.5, -1), 100, material_ground) }); + try tmp_world.add(Hittable{ .sphere = Sphere.init(Point3.init(0, 0, -1), 0.5, material_center) }); const world = Hittable{ .hittable_list = tmp_world }; // Camera diff --git a/zigrtiow/src/material.zig b/zigrtiow/src/material.zig new file mode 100644 index 0000000..cb455ac --- /dev/null +++ b/zigrtiow/src/material.zig @@ -0,0 +1,34 @@ +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, + + pub fn scatter(material: Material, r_in: Ray, rec: HitRecord) ?ScatterRec { + return switch (material) { + .labertian => |labertian| labertian.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, + }; + } +}; diff --git a/zigrtiow/src/sphere.zig b/zigrtiow/src/sphere.zig index 81eaa23..7052988 100644 --- a/zigrtiow/src/sphere.zig +++ b/zigrtiow/src/sphere.zig @@ -2,6 +2,8 @@ const vec = @import("./vec.zig"); const ray = @import("./ray.zig"); const hittable = @import("./hittable.zig"); +const Material = @import("./material.zig").Material; + const Vec3 = vec.Vec3; const Point3 = vec.Point3; const Ray = ray.Ray; @@ -10,11 +12,13 @@ const HitRecord = hittable.HitRecord; pub const Sphere = struct { center: Point3, radius: f32, + material: Material, - pub fn init(center: Point3, radius: f32) Sphere { + pub fn init(center: Point3, radius: f32, material: Material) Sphere { return Sphere{ .center = center, .radius = radius, + .material = material, }; } pub fn hit(sphere: Sphere, r: Ray, t_min: f32, t_max: f32) ?HitRecord { @@ -44,6 +48,7 @@ pub const Sphere = struct { .p = p, .normal = Vec3.init(0, 0, 0), .front_face = false, + .material = sphere.material, }; hr.set_face_normal(r, outward_normal); return hr; diff --git a/zigrtiow/src/vec.zig b/zigrtiow/src/vec.zig index 298547d..fc91855 100644 --- a/zigrtiow/src/vec.zig +++ b/zigrtiow/src/vec.zig @@ -34,6 +34,9 @@ pub const Vec3 = struct { pub fn sub(lhs: Vec3, rhs: Vec3) Vec3 { return Vec3{ .v = lhs.v - rhs.v }; } + pub fn mul(lhs: Vec3, rhs: Vec3) Vec3 { + return Vec3{ .v = lhs.v * rhs.v }; + } pub fn scale(vec: Vec3, t: f32) Vec3 { return Vec3{ .v = vec.v * @splat(3, t) }; } @@ -52,6 +55,12 @@ pub const Vec3 = struct { rand.float(f32) * 2 - 1, ); } + pub fn near_zero(vec: Vec3) bool { + // Return true if the vector is close to zero in all dimensions. + const s = 1e-8; + const e = vec.v; + return (@fabs(e[0]) < s) and (@fabs(e[1]) < s) and (@fabs(e[2]) < s); + } }; pub fn random_in_unit_sphere() Vec3 {