implement Material as tagged union

master
Fabien Freling 2021-05-27 21:19:31 +02:00
parent bc3fb54991
commit c842fcf713
2 changed files with 53 additions and 44 deletions

View File

@ -14,8 +14,6 @@ const World = @import("world.zig").World;
const Camera = @import("camera.zig").Camera; const Camera = @import("camera.zig").Camera;
const material = @import("material.zig"); const material = @import("material.zig");
const Material = material.Material; 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 // From: https://github.com/Nelarius/weekend-raytracer-zig/blob/master/src/main.zig
// See https://github.com/zig-lang/zig/issues/565 // 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 (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 sRay.color.mul(rayColor(sRay.ray, world, rng, depth - 1));
} }
return Color{ .x = 0, .y = 0, .z = 0 }; return Color{ .x = 0, .y = 0, .z = 0 };
@ -94,20 +92,24 @@ pub fn main() anyerror!void {
// World // World
const materialGround = Material{ const materialGround = Material{
.materialType = .Lambertian, .lambertian = material.Lambertian{
.color = Color{ .x = 0.8, .y = 0.8, .z = 0.0 }, .color = Color{ .x = 0.8, .y = 0.8, .z = 0.0 }
}
}; };
const materialCenter = Material{ const materialCenter = Material{
.materialType = .Lambertian, .lambertian = material.Lambertian{
.color = Color{ .x = 0.7, .y = 0.3, .z = 0.3 }, .color = Color{ .x = 0.7, .y = 0.3, .z = 0.3 }
}
}; };
const materialLeft = Material{ const materialLeft = Material{
.materialType = .Metal, .metal = material.Metal{
.color = Color{ .x = 0.8, .y = 0.8, .z = 0.8 }, .color = Color{ .x = 0.8, .y = 0.8, .z = 0.8 }
}
}; };
const materialRight = Material{ const materialRight = Material{
.materialType = .Metal, .metal = material.Metal{
.color = Color{ .x = 0.8, .y = 0.6, .z = 0.2 }, .color = Color{ .x = 0.8, .y = 0.6, .z = 0.2 }
}
}; };
const spheres = [_]Sphere{ const spheres = [_]Sphere{

View File

@ -7,13 +7,41 @@ const Ray = @import("ray.zig").Ray;
const HitRecord = @import("hittable.zig").HitRecord; const HitRecord = @import("hittable.zig").HitRecord;
pub const MaterialType = enum { pub const MaterialType = enum {
Lambertian, lambertian,
Metal, metal,
}; };
pub const Material = struct { pub const Lambertian = struct {
materialType: MaterialType,
color: Color, 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 { pub const ScatteredRay = struct {
@ -21,35 +49,14 @@ pub const ScatteredRay = struct {
color: Color, color: Color,
}; };
pub const Material = union(MaterialType) {
lambertian: Lambertian,
metal: Metal,
};
pub fn scatter(ray: Ray, hit: HitRecord, rng: *Random) ?ScatteredRay { pub fn scatter(ray: Ray, hit: HitRecord, rng: *Random) ?ScatteredRay {
const scatteredDirection = switch (hit.material.materialType) { return switch (hit.material) {
.lambertian => |m| m.scatter(ray, hit, rng),
.Lambertian => blk: { .metal => |m| m.scatter(ray, hit, rng),
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;
},
}; };
if (scatteredDirection) |dir| {
return ScatteredRay{
.ray = Ray{ .origin = hit.p, .direction = dir},
.color = hit.material.color,
};
}
return null;
} }