From c842fcf713e9c7e6777019a6822feb9ed1aefd07 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Thu, 27 May 2021 21:19:31 +0200 Subject: [PATCH] implement Material as tagged union --- in_one_weekend/src/main.zig | 24 ++++++----- in_one_weekend/src/material.zig | 73 ++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/in_one_weekend/src/main.zig b/in_one_weekend/src/main.zig index ab41cc1..656f66b 100644 --- a/in_one_weekend/src/main.zig +++ b/in_one_weekend/src/main.zig @@ -14,8 +14,6 @@ const World = @import("world.zig").World; const Camera = @import("camera.zig").Camera; const material = @import("material.zig"); const Material = material.Material; -const MaterialType = material.MaterialType; -const scatter = @import("material.zig").scatter; // From: https://github.com/Nelarius/weekend-raytracer-zig/blob/master/src/main.zig // See https://github.com/zig-lang/zig/issues/565 @@ -46,7 +44,7 @@ fn rayColor(ray: Ray, world: World, rng: *Random, depth: i32) Color { } if (world.hit(ray, 0.001, 99999)) |hit| { - if (scatter(ray, hit, rng)) |sRay| { + if (material.scatter(ray, hit, rng)) |sRay| { return sRay.color.mul(rayColor(sRay.ray, world, rng, depth - 1)); } return Color{ .x = 0, .y = 0, .z = 0 }; @@ -94,20 +92,24 @@ pub fn main() anyerror!void { // World const materialGround = Material{ - .materialType = .Lambertian, - .color = Color{ .x = 0.8, .y = 0.8, .z = 0.0 }, + .lambertian = material.Lambertian{ + .color = Color{ .x = 0.8, .y = 0.8, .z = 0.0 } + } }; const materialCenter = Material{ - .materialType = .Lambertian, - .color = Color{ .x = 0.7, .y = 0.3, .z = 0.3 }, + .lambertian = material.Lambertian{ + .color = Color{ .x = 0.7, .y = 0.3, .z = 0.3 } + } }; const materialLeft = Material{ - .materialType = .Metal, - .color = Color{ .x = 0.8, .y = 0.8, .z = 0.8 }, + .metal = material.Metal{ + .color = Color{ .x = 0.8, .y = 0.8, .z = 0.8 } + } }; const materialRight = Material{ - .materialType = .Metal, - .color = Color{ .x = 0.8, .y = 0.6, .z = 0.2 }, + .metal = material.Metal{ + .color = Color{ .x = 0.8, .y = 0.6, .z = 0.2 } + } }; const spheres = [_]Sphere{ diff --git a/in_one_weekend/src/material.zig b/in_one_weekend/src/material.zig index 174bd05..95edca2 100644 --- a/in_one_weekend/src/material.zig +++ b/in_one_weekend/src/material.zig @@ -7,13 +7,41 @@ const Ray = @import("ray.zig").Ray; const HitRecord = @import("hittable.zig").HitRecord; pub const MaterialType = enum { - Lambertian, - Metal, + lambertian, + metal, }; -pub const Material = struct { - materialType: MaterialType, +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 { @@ -21,35 +49,14 @@ pub const ScatteredRay = struct { color: Color, }; +pub const Material = union(MaterialType) { + lambertian: Lambertian, + metal: Metal, +}; + pub fn scatter(ray: Ray, hit: HitRecord, rng: *Random) ?ScatteredRay { - const scatteredDirection = switch (hit.material.materialType) { - - .Lambertian => blk: { - var scatterDirection = hit.normal.add(vec3.random_unit_vector(rng)); - // Catch degenerate scatter direction - if (scatterDirection.nearZero()) { - scatterDirection = hit.normal; - } - break :blk scatterDirection; - }, - - .Metal => blk: { - const reflected = ray.direction.unit().reflect(hit.normal); - const scattered = Ray{ .origin = hit.p, .direction = reflected }; - if (scattered.direction.dot(hit.normal) <= 0) { - break :blk null; - } - break :blk scattered.direction; - }, - + return switch (hit.material) { + .lambertian => |m| m.scatter(ray, hit, rng), + .metal => |m| m.scatter(ray, hit, rng), }; - - if (scatteredDirection) |dir| { - return ScatteredRay{ - .ray = Ray{ .origin = hit.p, .direction = dir}, - .color = hit.material.color, - }; - } - - return null; } \ No newline at end of file