this repo has no description

antialiasing

+60 -20
+20
src/camera.zig
··· 1 1 const std = @import("std"); 2 + const random = std.crypto.random; 2 3 3 4 const zigimg = @import("zigimg"); 4 5 const color = zigimg.color; 5 6 const zm = @import("zmath"); 7 + 8 + pub const Ray = @import("ray.zig"); 6 9 7 10 const log = std.log.scoped(.camera); 8 11 ··· 11 14 pub const Options = struct { 12 15 image_width: usize, 13 16 aspect_ratio: f32, 17 + samples_per_pixel: usize, 14 18 }; 15 19 16 20 image_height: usize, 17 21 image_width: usize, 18 22 aspect_ratio: f32, 23 + samples_per_pixel: usize, 19 24 20 25 focal_lenght: f32, 21 26 viewport_height: f32, ··· 61 66 .image_width = image_width, 62 67 .image_height = image_height, 63 68 .aspect_ratio = aspect_ratio, 69 + .samples_per_pixel = opts.samples_per_pixel, 64 70 65 71 .focal_lenght = focal_lenght, 66 72 .viewport_height = viewport_height, ··· 83 89 self.image.deinit(); 84 90 } 85 91 92 + pub fn getRay(self: *Camera, i: usize, j: usize) Ray { 93 + const pixel_center = self.pixel00_loc + (zm.f32x4s(@as(f32, @floatFromInt(i))) * self.pixel_delta_u) + (zm.f32x4s(@as(f32, @floatFromInt(j))) * self.pixel_delta_v); 94 + const pixel_sample = pixel_center + self.pixelSamplesSq(); 95 + 96 + const ray_direction = pixel_sample - self.camera_center; 97 + return Ray.init(self.camera_center, ray_direction); 98 + } 99 + 86 100 pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void { 87 101 if (x >= self.image_width or y >= self.image_height) return error.OutOfBounds; 88 102 const i = x + self.image_width * y; 89 103 self.image.pixels.rgba32[i] = c; 90 104 } 105 + 106 + fn pixelSamplesSq(self: *Camera) zm.Vec { 107 + const px = zm.f32x4s(-0.5 + random.float(f32)); 108 + const py = zm.f32x4s(-0.5 + random.float(f32)); 109 + return (px * self.pixel_delta_u) + (py * self.pixel_delta_v); 110 + }
+12
src/interval.zig
··· 81 81 return self.min < x and x < self.max; 82 82 } 83 83 84 + pub fn clamp(self: *const Self, x: T) T { 85 + if (x < self.min) return self.min; 86 + if (x > self.max) return self.max; 87 + return x; 88 + } 89 + 84 90 pub fn iter(self: *const Self) Iterator { 85 91 return Iterator{ 86 92 .interval = self.*, ··· 108 114 109 115 pub fn surrounds(self: *const Self, x: T) bool { 110 116 return self.min < x and x < self.max; 117 + } 118 + 119 + pub fn clamp(self: *const Self, x: T) T { 120 + if (x < self.min) return self.min; 121 + if (x > self.max) return self.max; 122 + return x; 111 123 } 112 124 }; 113 125 } else {
+1 -1
src/main.zig
··· 33 33 const s = spall.trace(@src(), "Raytracer", .{}); 34 34 35 35 // Raytracing part 36 - var raytracer = try rayray.Raytracer.init(allocator, world, .{ .aspect_ratio = 16.0 / 9.0, .image_width = 400 }); 36 + var raytracer = try rayray.Raytracer.init(allocator, world, .{ .aspect_ratio = 16.0 / 9.0, .image_width = 400, .samples_per_pixel = 100 }); 37 37 defer raytracer.deinit(); 38 38 39 39 const img = try raytracer.render();
+8 -9
src/rayray.zig
··· 64 64 threads[row].thread = t; 65 65 } 66 66 67 - // const stderr = std.io.getStdErr(); 68 - // // defer stderr.close(); 67 + const stderr = std.io.getStdErr(); 69 68 70 - // var progress = std.Progress{ 71 - // .terminal = stderr, 72 - // .supports_ansi_escape_codes = true, 73 - // }; 74 - // var node = progress.start("Rendering Completed", num_threads); 75 - // node.activate(); 69 + var progress = std.Progress{ 70 + .terminal = stderr, 71 + .supports_ansi_escape_codes = true, 72 + }; 73 + var node = progress.start("Rendering Completed", num_threads); 74 + node.activate(); 76 75 77 76 while (true) { 78 77 var done = true; ··· 93 92 if (done) break; 94 93 } 95 94 96 - // node.end(); 95 + node.end(); 97 96 98 97 return self.camera.image; 99 98 }
+19 -10
src/renderer.zig
··· 36 36 37 37 var width_iter = width.iter(); 38 38 while (width_iter.nextExc()) |i| { 39 - const pixel_center = ctx.cam.pixel00_loc + (zm.f32x4s(@as(f32, @floatFromInt(i))) * ctx.cam.pixel_delta_u) + (zm.f32x4s(@as(f32, @floatFromInt(j))) * ctx.cam.pixel_delta_v); 40 - const ray_direction = pixel_center - ctx.cam.camera_center; 41 - var ray = Ray.init(ctx.cam.camera_center, ray_direction); 42 - const col = vecToRgba(rayColor(&ray, ctx.world)); 39 + var col = zm.f32x4(0.0, 0.0, 0.0, 1.0); 40 + for (0..ctx.cam.samples_per_pixel) |_| { 41 + var ray = ctx.cam.getRay(i, j); 42 + col += rayColor(&ray, ctx.world); 43 + } 43 44 44 - ctx.cam.setPixel(i, j, col) catch break; 45 + ctx.cam.setPixel(i, j, vecToRgba(col, ctx.cam.samples_per_pixel)) catch break; 45 46 } 46 47 } 47 48 } ··· 63 64 done.store(true, .Release); 64 65 } 65 66 66 - fn vecToRgba(v: zm.Vec) zigimg.color.Rgba32 { 67 - const r: u8 = @intFromFloat(255.999 * v[0]); 68 - const g: u8 = @intFromFloat(255.999 * v[1]); 69 - const b: u8 = @intFromFloat(255.999 * v[2]); 70 - const a: u8 = @intFromFloat(255.999 * v[3]); 67 + fn vecToRgba(v: zm.Vec, samples_per_pixel: usize) zigimg.color.Rgba32 { 68 + const scale: f32 = 1.0 / @as(f32, @floatFromInt(samples_per_pixel)); 69 + const intensity = IntervalF32.init(0.0, 0.999); 70 + 71 + const r_scaled = v[0] * scale; 72 + const g_scaled = v[1] * scale; 73 + const b_scaled = v[2] * scale; 74 + const a_scaled = v[3] * scale; 75 + 76 + const r: u8 = @intFromFloat(256 * intensity.clamp(r_scaled)); 77 + const g: u8 = @intFromFloat(256 * intensity.clamp(g_scaled)); 78 + const b: u8 = @intFromFloat(256 * intensity.clamp(b_scaled)); 79 + const a: u8 = @intFromFloat(256 * intensity.clamp(a_scaled)); 71 80 72 81 return zigimg.color.Rgba32.initRgba(r, g, b, a); 73 82 }