diff --git a/in_one_weekend/src/main.zig b/in_one_weekend/src/main.zig index debe89f..55b97a8 100644 --- a/in_one_weekend/src/main.zig +++ b/in_one_weekend/src/main.zig @@ -76,6 +76,94 @@ fn setProgress(surface: *sdl.c.SDL_Surface, width: usize, height: usize, percent } } +fn setupWorld(world: *World, rng: *Random) !void { + try world.spheres.append(Sphere{ + .center = Point3{ .x = 0, .y = -1000, .z = 0 }, + .radius = 1000, + .material = Material{ .lambertian = material.Lambertian{ + .color = Color{ .x = 0.5, .y = 0.5, .z = 0.5 } + }} + }); + + var a: f32 = -11; + while (a < 11) : (a += 1) { + var b: f32 = -11; + while (b < 11) : (b += 1) { + const chooseMat = rng.float(f32); + const center = Point3{ + .x = a + 0.9 * rng.float(f32), + .y = 0.2, + .z = b + 0.9 * rng.float(f32), + }; + + if (center.sub(Point3{ .x = 4, .y = 0.2 }).length() > 0.9) { + if (chooseMat < 0.8) { + // diffuse + try world.spheres.append(Sphere{ + .center = center, + .radius = 0.2, + .material = Material{ .lambertian = material.Lambertian{ + .color = Color{ + .x = rng.float(f32) * rng.float(f32), + .y = rng.float(f32) * rng.float(f32), + .z = rng.float(f32) * rng.float(f32), + } + }}, + }); + } else if (chooseMat < 0.95) { + // metal + try world.spheres.append(Sphere{ + .center = center, + .radius = 0.2, + .material = Material{ .metal = material.Metal{ + .color = Color{ + .x = 0.5 + rng.float(f32) / 2, + .y = 0.5 + rng.float(f32) / 2, + .z = 0.5 + rng.float(f32) / 2, + }, + .fuzz = rng.float(f32) / 2, + }}, + }); + } else { + // glass + try world.spheres.append(Sphere{ + .center = center, + .radius = 0.2, + .material = Material{ .dielectric = material.Dielectric{ + .refraction_index = 1.5, + }}, + }); + } + } + } + } + + try world.spheres.append(Sphere{ + .center = Point3{ .x = 0, .y = 1, .z = 0 }, + .radius = 1, + .material = Material{ .dielectric = material.Dielectric{ + .refraction_index = 1.5 + }}, + }); + + try world.spheres.append(Sphere{ + .center = Point3{ .x = -4, .y = 1, .z = 0 }, + .radius = 1, + .material = Material{ .lambertian = material.Lambertian{ + .color = Color{ .x = 0.4, .y = 0.2, .z = 0.1 } + }}, + }); + + try world.spheres.append(Sphere{ + .center = Point3{ .x = 4, .y = 1, .z = 0 }, + .radius = 1, + .material = Material{ .metal = material.Metal{ + .color = Color{ .x = 0.7, .y = 0.6, .z = 0.5 }, + .fuzz = 0.0 + }}, + }); +} + pub fn main() anyerror!void { if (sdl.c.SDL_Init(sdl.c.SDL_INIT_VIDEO) != 0) { std.log.err("Unable to initialize SDL: {}", .{sdl.c.SDL_GetError()}); @@ -83,6 +171,9 @@ pub fn main() anyerror!void { } defer sdl.c.SDL_Quit(); + var prng = std.rand.DefaultPrng.init(42); + + // Image const aspectRatio: f32 = 16.0 / 9.0; const imageWidth = 600; @@ -91,43 +182,16 @@ pub fn main() anyerror!void { const maxDepth = 50; // World - const materialGround = Material{ - .lambertian = material.Lambertian{ - .color = Color{ .x = 0.8, .y = 0.8, .z = 0.0 }, - } - }; - const materialCenter = Material{ - .lambertian = material.Lambertian{ - .color = Color{ .x = 0.1, .y = 0.2, .z = 0.5 }, - } - }; - const materialLeft = Material{ - .dielectric = material.Dielectric{ - .refraction_index = 1.5, - } - }; - const materialRight = Material{ - .metal = material.Metal{ - .color = Color{ .x = 0.8, .y = 0.6, .z = 0.2 }, - .fuzz = 1.0, - } - }; - - const spheres = [_]Sphere{ - Sphere{ .center = Point3{ .x = 0, .y = -100.5, .z = -1 }, .radius = 100, .material = materialGround }, - Sphere{ .center = Point3{ .x = 0, .y = 0, .z = -1 }, .radius = 0.5, .material = materialCenter }, - Sphere{ .center = Point3{ .x = -1, .y = 0, .z = -1 }, .radius = 0.5, .material = materialLeft }, - Sphere{ .center = Point3{ .x = -1, .y = 0, .z = -1 }, .radius = -0.45, .material = materialLeft }, - Sphere{ .center = Point3{ .x = 1, .y = 0, .z = -1 }, .radius = 0.5, .material = materialRight }, - }; - const world = World{ .spheres = spheres[0..spheres.len] }; + var world = World.init(); + defer world.deinit(); + try setupWorld(&world, &prng.random); // Camera - const lookFrom = Point3{ .x = 3, .y = 3, .z = 2 }; - const lookAt = Point3{ .x = 0, .y = 0, .z = -1 }; + const lookFrom = Point3{ .x = 13, .y = 2, .z = 3 }; + const lookAt = Point3{ .x = 0, .y = 0, .z = 0 }; const vup = Vec3{ .x = 0, .y = 1, .z = 0 }; - const distToFocus = lookFrom.sub(lookAt).length(); - const aperture = 2.0; + const distToFocus = 10; + const aperture = 0.1; const camera = Camera.init( lookFrom, lookAt, @@ -155,7 +219,6 @@ pub fn main() anyerror!void { return error.SDLInitializationFailed; }; - var prng = std.rand.DefaultPrng.init(42); var pixelAccu: [imageWidth * imageHeight]Color = undefined; for (pixelAccu) |*pixel| { pixel.* = Color{}; diff --git a/in_one_weekend/src/world.zig b/in_one_weekend/src/world.zig index a07a8e8..71432a3 100644 --- a/in_one_weekend/src/world.zig +++ b/in_one_weekend/src/world.zig @@ -1,15 +1,28 @@ +const std = @import("std"); +const ArrayList = std.ArrayList; + const Sphere = @import("sphere.zig").Sphere; const HitRecord = @import("hittable.zig").HitRecord; const Ray = @import("ray.zig").Ray; pub const World = struct { - spheres: []const Sphere, + spheres: ArrayList(Sphere), - pub fn hit(self: World, ray: Ray, t_min: f32, t_max: f32) ?HitRecord { + pub fn init() World { + return World { + .spheres = ArrayList(Sphere).init(std.testing.allocator) + }; + } + + pub fn deinit(self: *World) void { + self.spheres.deinit(); + } + + pub fn hit(self: *const World, ray: Ray, t_min: f32, t_max: f32) ?HitRecord { var hitRecord: ?HitRecord = null; var closest = t_max; - for (self.spheres) |sphere| { + for (self.spheres.items) |sphere| { if (sphere.hit(ray, t_min, closest)) |localHit| { closest = localHit.t; hitRecord = localHit;