zigrtiow: add camera class and support supersampling.

This commit is contained in:
Bill Thiede 2022-08-04 21:05:52 -07:00
parent 84a0ba2ec6
commit e31f5e0a3a
4 changed files with 73 additions and 17 deletions

33
zigrtiow/src/camera.zig Normal file
View File

@ -0,0 +1,33 @@
const vec = @import("./vec.zig");
const Ray = @import("./ray.zig").Ray;
const Point3 = vec.Point3;
const Vec3 = vec.Vec3;
pub const Camera = struct {
origin: Point3,
lower_left_corner: Point3,
horizontal: Vec3,
vertical: Vec3,
pub fn init() Camera {
const aspect_ratio = 16.0 / 9.0;
const viewport_height = 2.0;
const viewport_width = aspect_ratio * viewport_height;
const focal_length = 1.0;
const origin = Point3.init(0, 0, 0);
const horizontal = Vec3.init(viewport_width, 0.0, 0.0);
const vertical = Vec3.init(0.0, viewport_height, 0.0);
return Camera{
.origin = origin,
.horizontal = horizontal,
.vertical = vertical,
.lower_left_corner = origin.sub(horizontal.scale(0.5)).sub(vertical.scale(0.5)).sub(Vec3.init(0, 0, focal_length)),
};
}
pub fn get_ray(camera: Camera, u: f32, v: f32) Ray {
return Ray.init(camera.origin, camera.lower_left_corner.add(camera.horizontal.scale(u).add(camera.vertical.scale(v).sub(camera.origin))));
}
};

View File

@ -1,10 +1,24 @@
const std = @import("std");
const clamp = @import("./utils.zig").clamp;
const Color = @import("./vec.zig").Color;
pub fn write_color(c: Color) anyerror!void {
var ir = @floatToInt(u8, 255.999 * c.x());
var ig = @floatToInt(u8, 255.999 * c.y());
var ib = @floatToInt(u8, 255.999 * c.z());
pub fn write_color(c: Color, samples_per_pixel: isize) anyerror!void {
var r = c.x();
var g = c.y();
var b = c.z();
// Divide the color by the number of samples.
var scale = 1.0 / @intToFloat(f32, samples_per_pixel);
r *= scale;
g *= scale;
b *= scale;
// Write the translated [0,255] value of each color component.
var ir = @floatToInt(u8, 256 * clamp(r, 0, 0.999));
var ig = @floatToInt(u8, 256 * clamp(g, 0, 0.999));
var ib = @floatToInt(u8, 256 * clamp(b, 0, 0.999));
const stdout = std.io.getStdOut();
try stdout.writer().print("{d} {d} {d}\n", .{ ir, ig, ib });
}

View File

@ -1,4 +1,5 @@
const std = @import("std");
const camera = @import("./camera.zig");
const color = @import("./color.zig");
const ray = @import("./ray.zig");
const vec = @import("./vec.zig");
@ -6,6 +7,7 @@ const sphere = @import("./sphere.zig");
const hittable = @import("./hittable.zig");
const hittable_list = @import("./hittable_list.zig");
const Camera = camera.Camera;
const Color = vec.Color;
const Hittable = hittable.Hittable;
const HittableList = hittable_list.HittableList;
@ -36,6 +38,7 @@ pub fn main() anyerror!void {
const aspect_ratio: f32 = 16.0 / 9.0;
const image_width = 400;
const image_height = @floatToInt(isize, @intToFloat(f32, image_width) / aspect_ratio);
const samples_per_pixel = 100;
// World
var world = HittableList.init();
@ -43,31 +46,32 @@ pub fn main() anyerror!void {
try world.add(Hittable{ .sphere = Sphere.init(Point3.init(0, -100.5, -1), 100) });
// 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 cam = Camera.init();
// Render
const stdout = std.io.getStdOut();
info("Writing image {d}x{d}", .{ image_width, image_height });
try stdout.writer().print("P3\n{d} {d}\n255\n", .{ image_width, image_height });
var prng = std.rand.DefaultPrng.init(0);
const rand = prng.random();
var j: isize = image_height - 1;
while (j >= 0) : (j -= 1) {
//info("Scanlines remaining: {d}", .{j});
var i: isize = 0;
while (i < image_width) : (i += 1) {
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, Hittable{ .hittable_list = world });
try write_color(pixel_color);
var pixel_color = Color.init(0, 0, 0);
var s: isize = 0;
while (s < samples_per_pixel) : (s += 1) {
const u = (@intToFloat(f32, i) + rand.float(f32)) / @intToFloat(f32, image_width - 1);
const v = (@intToFloat(f32, j) + rand.float(f32)) / @intToFloat(f32, image_height - 1);
const r = cam.get_ray(u, v);
//Ray.init(origin, lower_left_corner.add(horizontal.scale(u)).add(vertical.scale(v)).sub(origin));
pixel_color = pixel_color.add(ray_color(r, Hittable{ .hittable_list = world }));
}
try write_color(pixel_color, samples_per_pixel);
}
}
info("Done", .{});

5
zigrtiow/src/utils.zig Normal file
View File

@ -0,0 +1,5 @@
pub fn clamp(x: f32, min: f32, max: f32) f32 {
if (x < min) return min;
if (x > max) return max;
return x;
}