From b0ce3eecece1a9157fa0e71ff57f42ab8af0ee3d Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Mon, 26 Apr 2021 22:51:49 +0200 Subject: [PATCH] add multiple samples per pixel --- in_one_weekend/src/camera.zig | 36 ++++++++++++++++++++++++++++++++ in_one_weekend/src/color.zig | 17 +++++++++++++++ in_one_weekend/src/main.zig | 39 ++++++++++++++++++++--------------- in_one_weekend/src/sdl.zig | 2 +- in_one_weekend/src/vec3.zig | 1 - 5 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 in_one_weekend/src/camera.zig create mode 100644 in_one_weekend/src/color.zig diff --git a/in_one_weekend/src/camera.zig b/in_one_weekend/src/camera.zig new file mode 100644 index 0000000..e1c7e63 --- /dev/null +++ b/in_one_weekend/src/camera.zig @@ -0,0 +1,36 @@ +const Point3 = @import("vec3.zig").Point3; +const Vec3 = @import("vec3.zig").Vec3; +const Ray = @import("ray.zig").Ray; + +pub const Camera = struct { + origin: Point3, + lowerLeftCorner: Point3, + horizontal: Vec3, + vertical: Vec3, + + pub fn init() Camera { + const aspectRatio = 16.0 / 9.0; + const viewportHeight = 2.0; + const viewportWidth = aspectRatio * viewportHeight; + const focalLength = 1.0; + + const origin = Vec3{}; + const horizontal = Vec3{ .x = viewportWidth }; + const vertical = Vec3{ .y = viewportHeight }; + const lowerLeftCorner = origin.sub(horizontal.div(2)).sub(vertical.div(2)).sub(Vec3{ .z = focalLength }); + + return Camera { + .origin = origin, + .horizontal = horizontal, + .vertical = vertical, + .lowerLeftCorner = lowerLeftCorner, + }; + } + + pub fn getRay(self: Camera, u: f32, v: f32) Ray { + return Ray{ + .origin = self.origin, + .direction = self.lowerLeftCorner.add(self.horizontal.mul(u)).add(self.vertical.mul(v)).sub(self.origin), + }; + } +}; \ No newline at end of file diff --git a/in_one_weekend/src/color.zig b/in_one_weekend/src/color.zig new file mode 100644 index 0000000..bd04896 --- /dev/null +++ b/in_one_weekend/src/color.zig @@ -0,0 +1,17 @@ +const std = @import("std"); +const math = std.math; +const Vec3 = @import("vec3.zig").Vec3; + +pub const Color = Vec3; + +pub fn averageColor(pixelColor: Color, samplesPerPixel: i32) Color { + // Divide the color by the number of samples. + // const scale = 1.0 / @intToFloat(f32, samplesPerPixel); + var scaledColor = pixelColor.div(@intToFloat(f32, samplesPerPixel)); + + return Color{ + .x = math.clamp(scaledColor.x, 0, 0.999), + .y = math.clamp(scaledColor.y, 0, 0.999), + .z = math.clamp(scaledColor.z, 0, 0.999), + }; +} \ No newline at end of file diff --git a/in_one_weekend/src/main.zig b/in_one_weekend/src/main.zig index 9affc5b..e7c252b 100644 --- a/in_one_weekend/src/main.zig +++ b/in_one_weekend/src/main.zig @@ -3,11 +3,13 @@ const print = std.debug.print; const sdl = @import("sdl.zig"); const vec3 = @import("vec3.zig"); const Vec3 = vec3.Vec3; -const Color = vec3.Color; const Point3 = vec3.Point3; +const color = @import("color.zig"); +const Color = color.Color; const Ray = @import("ray.zig").Ray; const Sphere = @import("sphere.zig").Sphere; const World = @import("world.zig").World; +const Camera = @import("camera.zig").Camera; // From: https://github.com/Nelarius/weekend-raytracer-zig/blob/master/src/main.zig // See https://github.com/zig-lang/zig/issues/565 @@ -53,6 +55,7 @@ pub fn main() anyerror!void { const aspectRatio: f32 = 16.0 / 9.0; const imageWidth = 600; const imageHeight = @floatToInt(usize, imageWidth / aspectRatio); + const samplesPerPixel = 100; // World const spheres = [_]Sphere{ @@ -62,14 +65,7 @@ pub fn main() anyerror!void { const world = World{ .spheres = spheres[0..spheres.len] }; // Camera - const viewportHeight = 2.0; - const viewportWidth = viewportHeight * aspectRatio; - const focalLength = 1.0; - - const origin = Vec3{}; - const horizontal = Vec3{ .x = viewportWidth }; - const vertical = Vec3{ .y = viewportHeight }; - const lowerLeftCorner = origin.sub(horizontal.div(2)).sub(vertical.div(2)).sub(Vec3{ .z = focalLength }); + const camera = Camera.init(); const window = sdl.c.SDL_CreateWindow( "Raytracing in One Weekend", @@ -88,6 +84,8 @@ pub fn main() anyerror!void { return error.SDLInitializationFailed; }; + var prng = std.rand.DefaultPrng.init(42); + { _ = sdl.c.SDL_LockSurface(surface); @@ -95,15 +93,22 @@ pub fn main() anyerror!void { while (j < imageHeight) { var i: usize = 0; while (i < imageWidth) { - const u = @intToFloat(f32, i) / @intToFloat(f32, (imageWidth - 1)); + var pixelColor = Color{}; + var k: usize = 0; + while (k < samplesPerPixel) { + const u = (@intToFloat(f32, i) + prng.random.float(f32)) / @intToFloat(f32, (imageWidth - 1)); + const v = (@intToFloat(f32, j) + prng.random.float(f32)) / @intToFloat(f32, (imageHeight - 1)); + const r = camera.getRay(u, v); + const sample = rayColor(r, world); + pixelColor = pixelColor.add(sample); + + k += 1; + } + + const averageColor = color.averageColor(pixelColor, samplesPerPixel); // SDL coordinate system is flipped compared to the raytracer - const v = @intToFloat(f32, (imageHeight - 1) - j) / @intToFloat(f32, (imageHeight - 1)); - const r = Ray{ - .origin = origin, - .direction = lowerLeftCorner.add(horizontal.mul(u)).add(vertical.mul(v)).sub(origin), - }; - const pixelColor = rayColor(r, world); - sdl.setSurfacePixel(surface, i, j, pixelColor); + sdl.setSurfacePixel(surface, i, imageHeight - 1 - j, averageColor); + i += 1; } j += 1; diff --git a/in_one_weekend/src/sdl.zig b/in_one_weekend/src/sdl.zig index 7b37350..5063659 100644 --- a/in_one_weekend/src/sdl.zig +++ b/in_one_weekend/src/sdl.zig @@ -1,5 +1,5 @@ pub const c = @cImport({ @cInclude("SDL2/SDL.h"); }); -const Color = @import("vec3.zig").Color; +const Color = @import("color.zig").Color; pub fn setSurfacePixel(surface: *c.SDL_Surface, i: usize, j: usize, color: Color) void { const bytePerPixel = 4; diff --git a/in_one_weekend/src/vec3.zig b/in_one_weekend/src/vec3.zig index bc607b2..8e0df49 100644 --- a/in_one_weekend/src/vec3.zig +++ b/in_one_weekend/src/vec3.zig @@ -67,7 +67,6 @@ pub fn unitVector(vec: Vec3) Vec3 { } pub const Point3 = Vec3; -pub const Color = Vec3; const assert = @import("std").debug.assert;