this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

clean up + more build options

+98 -65
+9
build.zig
··· 10 10 const max_depth = b.option(u64, "max-depth", "Set the max depth of the BVH tree") orelse std.math.maxInt(u64); 11 11 options.addOption(u64, "max_depth", max_depth); 12 12 13 + const save_during_render = b.option(bool, "save-during-render", "Save image during the render process") orelse false; 14 + options.addOption(bool, "save_during_render", save_during_render); 15 + 16 + const output_file: std.Build.LazyPath = b.option(std.Build.LazyPath, "output", "File to save rendered image to") orelse { 17 + std.log.err("Please specify a save file location", .{}); 18 + return; 19 + }; 20 + options.addOption([]const u8, "output", output_file.getPath(b)); 21 + 13 22 const rayray = b.addModule("rayray", .{ 14 23 .root_source_file = b.path("src/rayray.zig"), 15 24 .target = target,
+6
src/Scene.zig
··· 1 1 const std = @import("std"); 2 2 3 + const zigimg = @import("zigimg"); 4 + 3 5 const Camera = @import("Camera.zig"); 4 6 const hittable = @import("hittable.zig"); 5 7 const Material = @import("material.zig").Material; ··· 55 57 pub fn setCamera(self: *Self, cam: Camera.Options) !void { 56 58 self.camera = try Camera.init(self.allocator, cam); 57 59 } 60 + 61 + pub fn writeToFilePath(self: *Self, path: []const u8, opts: zigimg.Image.EncoderOptions) !void { 62 + try self.camera.image.writeToFilePath(path, opts); 63 + }
+4 -2
src/main.zig
··· 10 10 const Sphere = rayray.hittable.Sphere; 11 11 const zm = rayray.zmath; 12 12 13 + const build_options = rayray.build_options; 14 + 13 15 const scenes = @import("scenes.zig"); 14 16 15 17 pub const std_options = Options{ ··· 48 50 49 51 printRenderTime(timer.lap()); 50 52 51 - try img.writeToFilePath("./out/out.png", .{ .png = .{} }); 52 - std.log.info("Image saved to: ./out/out.png", .{}); 53 + try img.writeToFilePath(build_options.output, .{ .png = .{} }); 54 + std.log.info("Image saved to: {s}", .{build_options.output}); 53 55 } 54 56 55 57 fn printRenderTime(t: u64) void {
+79 -63
src/rayray.zig
··· 1 1 const std = @import("std"); 2 - const build_options = @import("build-options"); 2 + pub const build_options = @import("build-options"); 3 3 4 4 pub const zmath = @import("zmath"); 5 5 ··· 32 32 thread_pool: *std.Thread.Pool, 33 33 34 34 scene: Scene, 35 + cols: usize, 36 + rows: usize, 37 + num_chunks: usize, 38 + num_threads: usize, 39 + chunks_per_thread: usize, 40 + 41 + const chunk_height: usize = 25; 42 + const chunk_width: usize = 25; 35 43 36 44 pub fn init(allocator: std.mem.Allocator, scene: Scene) !Self { 37 45 var thread_pool = try allocator.create(std.Thread.Pool); 38 46 try thread_pool.init(.{ .allocator = allocator }); 39 47 40 - return .{ 41 - .allocator = allocator, 42 - .thread_pool = thread_pool, 43 - .scene = scene, 48 + const num_threads = blk: { 49 + const count = try std.Thread.getCpuCount(); 50 + if (count > 1) { 51 + break :blk count; 52 + } else break :blk 1; 44 53 }; 45 - } 46 54 47 - pub fn deinit(self: *Self) void { 48 - self.scene.deinit(); 49 - self.thread_pool.deinit(); 50 - self.allocator.destroy(self.thread_pool); 51 - } 52 - 53 - pub fn render(self: *Self) !zigimg.Image { 54 - const chunk_height: usize = 25; 55 - const chunk_width: usize = 25; 56 - 57 - var rows: usize = @divTrunc(self.scene.camera.image_height, chunk_height); 58 - if (self.scene.camera.image_height % rows != 0) { 55 + var rows: usize = @divTrunc(scene.camera.image_height, chunk_height); 56 + if (scene.camera.image_height % rows != 0) { 59 57 rows += 1; 60 58 } 61 59 62 - var cols: usize = @divTrunc(self.scene.camera.image_width, chunk_width); 63 - if (self.scene.camera.image_width % cols != 0) { 60 + var cols: usize = @divTrunc(scene.camera.image_width, chunk_width); 61 + if (scene.camera.image_width % cols != 0) { 64 62 cols += 1; 65 63 } 66 64 67 65 const num_chunks = cols * rows; 68 - 69 - const num_threads = blk: { 70 - const count = try std.Thread.getCpuCount(); 71 - if (count > 1) { 72 - break :blk count; 73 - } else break :blk 1; 74 - }; 75 66 76 67 log.debug("with: {}, height: {}, rows: {}, cols: {}, chunk_height: {}, chunk_width: {}, num_chunks: {}, num_threads: {}", .{ 77 - self.scene.camera.image_width, 78 - self.scene.camera.image_height, 68 + scene.camera.image_width, 69 + scene.camera.image_height, 79 70 rows, 80 71 cols, 81 72 chunk_height, ··· 84 75 num_threads, 85 76 }); 86 77 78 + return .{ 79 + .allocator = allocator, 80 + .thread_pool = thread_pool, 81 + .scene = scene, 82 + .cols = cols, 83 + .rows = rows, 84 + .num_chunks = num_chunks, 85 + .num_threads = num_threads, 86 + .chunks_per_thread = num_chunks / num_threads, 87 + }; 88 + } 89 + 90 + pub fn deinit(self: *Self) void { 91 + self.scene.deinit(); 92 + self.thread_pool.deinit(); 93 + self.allocator.destroy(self.thread_pool); 94 + } 95 + 96 + pub fn render(self: *Self) !zigimg.Image { 87 97 var root_node = std.Progress.start(.{ 88 98 .root_name = "Ray Tracer", 89 99 .estimated_total_items = 4, ··· 94 104 var world_bvh = try BVH.init(self.allocator, self.scene.world, build_options.max_depth); 95 105 96 106 bvh_node.end(); 97 - root_node.setCompletedItems(0); 107 + // root_node.setCompletedItems(0); 98 108 99 109 var create_pixels_node = root_node.start("Create pixel array", 0); 100 110 ··· 103 113 // const l = pixels.ptr; 104 114 105 115 create_pixels_node.end(); 106 - root_node.setCompletedItems(1); 116 + // root_node.setCompletedItems(1); 107 117 108 118 var task_node = root_node.start("Creating render tasks", 0); 109 119 110 - const tasks: []TaskTracker = try self.allocator.alloc(TaskTracker, num_chunks); 120 + const tasks: []TaskTracker = try self.allocator.alloc(TaskTracker, self.num_chunks); 111 121 defer self.allocator.free(tasks); 112 122 113 123 for (tasks, 0..) |*t, id| { 114 124 // const row: usize = @divTrunc(id, cols) * chunk_height; 115 125 // const col: usize = (id - cols * @divTrunc(id, cols)) * chunk_width; 116 - const row: usize = (id / cols) * chunk_height; 117 - const col: usize = (id % cols) * chunk_width; 126 + const row: usize = (id / self.cols) * chunk_height; 127 + const col: usize = (id % self.cols) * chunk_width; 118 128 119 129 const c_height = IntervalUsize{ .min = row, .max = row + chunk_height }; 120 130 const c_width = IntervalUsize{ .min = col, .max = col + chunk_width + 1 }; ··· 136 146 } 137 147 138 148 task_node.end(); 139 - root_node.setCompletedItems(2); 149 + // root_node.setCompletedItems(2); 140 150 141 - var render_node = root_node.start("Rendering", num_chunks); 151 + var render_node = root_node.start("Rendering", self.num_chunks); 152 + 153 + try self.awaitTasks(&render_node, tasks); 154 + 155 + log.info("Rendering done!", .{}); 156 + 157 + render_node.end(); 158 + // root_node.setCompletedItems(4); 142 159 160 + var image_node = root_node.start("Creating Image", 0); 161 + defer image_node.end(); 162 + 163 + for (pixels, 0..) |pix, p| { 164 + const y = p / self.scene.camera.image_width; 165 + const x = p % self.scene.camera.image_width; 166 + if (pix[0] < 0 or pix[1] < 0 or pix[2] < 0) { 167 + // std.log.debug("wrong ({}, {}) {}", .{ x, y, pix }); 168 + try self.scene.camera.setPixel(x, y, zigimg.color.Rgba32.initRgb(255, 0, 0)); 169 + continue; 170 + } 171 + self.scene.camera.setPixel(x, y, vecToRgba(pix, self.scene.camera.samples_per_pixel_v)) catch continue; 172 + } 173 + 174 + return self.scene.camera.image; 175 + } 176 + 177 + fn awaitTasks(self: *Self, render_node: *std.Progress.Node, tasks: []TaskTracker) !void { 143 178 var thread_to_idx = std.ArrayList(std.Thread.Id).init(self.allocator); 144 179 defer thread_to_idx.deinit(); 145 180 ··· 166 201 167 202 const node_msg = try std.fmt.allocPrint(self.allocator, "Render Thread #{}", .{i}); 168 203 defer self.allocator.free(node_msg); 169 - try nodes.append(render_node.start(node_msg, num_chunks / num_threads)); 170 - root_node.setCompletedItems(3); 171 - // completed_chunks -= if (completed_chunks == 0) 0 else 1; 204 + try nodes.append(render_node.start(node_msg, self.chunks_per_thread)); 172 205 173 206 i += 1; 174 - std.debug.assert(i <= num_threads); 207 + std.debug.assert(i <= self.num_threads); 175 208 break :blk i - 1; 176 209 }; 177 210 nodes.items[idx].completeOne(); ··· 179 212 // if (i == 1) continue; 180 213 completed_chunks += 1; 181 214 render_node.setCompletedItems(completed_chunks); 182 - if (completed_chunks % self.thread_pool.threads.len == 0) try self.scene.camera.image.writeToFilePath("./out/out.png", .{ .png = .{} }); 215 + 216 + if (build_options.save_during_render and 217 + completed_chunks % self.thread_pool.threads.len == 0) 218 + try self.scene.writeToFilePath(build_options.output, .{ .png = .{} }); 183 219 } else if (!task_done) { 184 220 done = false; 185 221 } ··· 188 224 if (done or !self.thread_pool.is_running) break; 189 225 } 190 226 191 - std.debug.assert(completed_chunks == num_chunks); 192 - log.info("Rendering done!", .{}); 193 - 194 - render_node.end(); 195 - root_node.setCompletedItems(4); 196 - 197 - var image_node = root_node.start("Creating Image", 0); 198 - defer image_node.end(); 199 - 200 - for (pixels, 0..) |pix, p| { 201 - const y = p / self.scene.camera.image_width; 202 - const x = p % self.scene.camera.image_width; 203 - if (pix[0] < 0 or pix[1] < 0 or pix[2] < 0) { 204 - // std.log.debug("wrong ({}, {}) {}", .{ x, y, pix }); 205 - try self.scene.camera.setPixel(x, y, zigimg.color.Rgba32.initRgb(255, 0, 0)); 206 - continue; 207 - } 208 - self.scene.camera.setPixel(x, y, vecToRgba(pix, self.scene.camera.samples_per_pixel_v)) catch continue; 209 - } 210 - 211 - return self.scene.camera.image; 227 + std.debug.assert(completed_chunks == self.num_chunks); 212 228 } 213 229 }; 214 230 215 - pub fn renderThread(ctx: *tracer.Context, task: *TaskTracker) void { 231 + fn renderThread(ctx: *tracer.Context, task: *TaskTracker) void { 216 232 defer task.done.store(true, .release); 217 233 task.thread_id = std.Thread.getCurrentId(); 218 234 tracer.trace(ctx);