implement Material as tagged union
This commit is contained in:
		
							parent
							
								
									bc3fb54991
								
							
						
					
					
						commit
						c842fcf713
					
				
					 2 changed files with 53 additions and 44 deletions
				
			
		| 
						 | 
				
			
			@ -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{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue