From 8bc5e347cc5d769335a9b953dc45ddd32acb4136 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Sun, 31 Jul 2022 16:34:26 -0700 Subject: [PATCH] Use ray casting to draw "blue sky" image. --- zigrtiow/src/main.zig | 45 ++++++++++++++++++++++++++++++++++--------- zigrtiow/src/ray.zig | 33 +++++++++++++++++++++++++++++++ zigrtiow/src/vec.zig | 18 +++++++++++++++++ 3 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 zigrtiow/src/ray.zig diff --git a/zigrtiow/src/main.zig b/zigrtiow/src/main.zig index b5e5ad6..b27e58a 100644 --- a/zigrtiow/src/main.zig +++ b/zigrtiow/src/main.zig @@ -1,13 +1,36 @@ const std = @import("std"); -const info = std.log.info; +const color = @import("./color.zig"); +const ray = @import("./ray.zig"); const vec = @import("./vec.zig"); -const Vec3 = vec.Vec3; + const Color = vec.Color; -const write_color = @import("./color.zig").write_color; +const Vec3 = vec.Vec3; +const Point3 = vec.Point3; +const info = std.log.info; +const write_color = color.write_color; +const Ray = ray.Ray; + +fn ray_color(r: Ray) Color { + var unit_direction = r.direction().unit(); + var t = 0.5 * (unit_direction.y() + 1); + return Color.init(1, 1, 1).scale(1 - t).add(Color.init(0.5, 0.7, 1.0).scale(t)); +} pub fn main() anyerror!void { - const image_width: isize = 256; - const image_height: isize = 256; + // Image + const aspect_ratio: f32 = 16.0 / 9.0; + const image_width = 400; + const image_height = @floatToInt(isize, @intToFloat(f32, image_width) / aspect_ratio); + + // Camera + const viewport_height = 2; + const viewport_width = aspect_ratio * viewport_height; + const focal_length = 1; + + const origin = Point3.init(0, 0, 0); + const horizontal = Vec3.init(viewport_width, 0, 0); + const vertical = Vec3.init(0, viewport_height, 0); + const lower_left_corner = origin.sub(horizontal.scale(0.5)).sub(vertical.scale(0.5)).sub(Vec3.init(0, 0, focal_length)); const stdout = std.io.getStdOut(); @@ -16,16 +39,20 @@ pub fn main() anyerror!void { var j: isize = image_height - 1; while (j >= 0) : (j -= 1) { - info("Scanlines remaining: {d}", .{j}); + //info("Scanlines remaining: {d}", .{j}); var i: isize = 0; while (i < image_width) : (i += 1) { - const pixel_color = Color.init(@intToFloat(f32, i) / @intToFloat(f32, image_width - 1), @intToFloat(f32, j) / @intToFloat(f32, image_height - 1), 0.25); + const u = @intToFloat(f32, i) / @intToFloat(f32, image_width - 1); + const v = @intToFloat(f32, j) / @intToFloat(f32, image_height - 1); + const r = Ray.init(origin, lower_left_corner.add(horizontal.scale(u)).add(vertical.scale(v)).sub(origin)); + const pixel_color = ray_color(r); try write_color(pixel_color); } } } -test "basic test" { - try std.testing.expectEqual(10, 3 + 7); +test { + // Run tests in imported source. + std.testing.refAllDecls(@This()); } diff --git a/zigrtiow/src/ray.zig b/zigrtiow/src/ray.zig new file mode 100644 index 0000000..b989e88 --- /dev/null +++ b/zigrtiow/src/ray.zig @@ -0,0 +1,33 @@ +const std = @import("std"); +const vec = @import("./vec.zig"); + +const Vec3 = vec.Vec3; +const Point3 = vec.Point3; + +pub const Ray = struct { + orig: Vec3, + dir: Vec3, + + pub fn init(orig: Point3, dir: Vec3) Ray { + return Ray{ + .orig = orig, + .dir = dir, + }; + } + pub fn origin(ray: Ray) Point3 { + return ray.orig; + } + pub fn direction(ray: Ray) Vec3 { + return ray.dir; + } + pub fn at(ray: Ray, t: f32) Point3 { + return ray.orig.add(ray.dir.scale(t)); + } +}; + +test "ray_at" { + const want = Point3.init(0, 0, 1.5); + const r = Ray.init(Point3.init(0, 0, 0), Vec3.init(0, 0, 1)); + const got = r.at(1.5); + try std.testing.expectEqual(want, got); +} diff --git a/zigrtiow/src/vec.zig b/zigrtiow/src/vec.zig index 30c4858..2a67544 100644 --- a/zigrtiow/src/vec.zig +++ b/zigrtiow/src/vec.zig @@ -14,6 +14,24 @@ pub const Vec3 = struct { pub fn z(vec: Vec3) f32 { return vec.v[2]; } + pub fn length(vec: Vec3) f32 { + return @sqrt(vec.length_squared()); + } + fn length_squared(vec: Vec3) f32 { + return vec.v[0] * vec.v[0] + vec.v[1] * vec.v[1] + vec.v[2] * vec.v[2]; + } + pub fn add(lhs: Vec3, rhs: Vec3) Vec3 { + return Vec3{ .v = lhs.v + rhs.v }; + } + pub fn sub(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) }; + } + pub fn unit(vec: Vec3) Vec3 { + return vec.scale(1 / vec.length()); + } }; pub const Color = Vec3; pub const Point3 = Vec3;