this repo has no description

+

+161 -78
+2 -2
.gitignore
··· 1 - **/zig-cache 2 - **/zig-out 1 + *.zig-cache 2 + *zig-out 3 3 /out
+8 -8
build.zig
··· 4 4 const target = b.standardTargetOptions(.{}); 5 5 const optimize = b.standardOptimizeOption(.{}); 6 6 7 - const enable_spall = b.option(bool, "enable_spall", "Enable spall profiling") orelse false; 8 - const spall = b.dependency("spall", .{ 9 - .enable = enable_spall, 10 - }); 7 + // const enable_spall = b.option(bool, "enable_spall", "Enable spall profiling") orelse false; 8 + // const spall = b.dependency("spall", .{ 9 + // .enable = enable_spall, 10 + // }); 11 11 12 12 const strip = b.option(bool, "strip", "") orelse (optimize != .Debug); 13 13 14 14 const rayray = b.addModule("rayray", .{ 15 - .root_source_file = .{ .path = "src/rayray.zig" }, 15 + .root_source_file = b.path("src/rayray.zig"), 16 16 .target = target, 17 17 .optimize = optimize, 18 18 }); 19 19 rayray.strip = strip; 20 20 21 - rayray.addImport("spall", spall.module("spall")); 21 + // rayray.addImport("spall", spall.module("spall")); 22 22 23 23 addDeps(b, rayray); 24 24 25 25 const exe = b.addExecutable(.{ 26 26 .name = "rayray", 27 - .root_source_file = .{ .path = "src/main.zig" }, 27 + .root_source_file = b.path("src/main.zig"), 28 28 .target = target, 29 29 .optimize = optimize, 30 30 }); 31 31 exe.root_module.strip = strip; 32 32 33 33 // addDeps(b, &exe.root_module); 34 - exe.root_module.addImport("spall", spall.module("spall")); 34 + // exe.root_module.addImport("spall", spall.module("spall")); 35 35 exe.root_module.addImport("rayray", rayray); 36 36 37 37 const alib = b.dependency("a", .{
+8 -8
build.zig.zon
··· 9 9 10 10 // See `zig fetch --save <url>` for a command-line interface for adding dependencies. 11 11 .a = .{ 12 - .url = "git+https://git.sr.ht/~altagos/a#8c8f2cc405743d062f5b617e2f8ab85ce5dc0409", 13 - .hash = "12203338074c5e0fed0696abfa1ec868da0d1bb22539e5fd4220b2585a8f3cf0c788", 14 - }, 15 - .spall = .{ 16 - .url = "git+https://git.sr.ht/~altagos/zig-spall#7cae52aa2d1a519006e0c90fbd179cf7fcac0c83", 17 - .hash = "1220753b2f9e7c4f3fb6cdc8fc275cc9073904ea7032a1f5596aa776a857de69f72c", 12 + .url = "git+https://git.sr.ht/~altagos/a#78b378a924008a072ede6be850398299d233e55e", 13 + .hash = "12209a07e35e58e69838fd66b68a13ee2b1fbf999e6242acdec0d7354be1324aef76", 18 14 }, 15 + // .spall = .{ 16 + // .url = "git+https://git.sr.ht/~altagos/zig-spall#7cae52aa2d1a519006e0c90fbd179cf7fcac0c83", 17 + // .hash = "1220753b2f9e7c4f3fb6cdc8fc275cc9073904ea7032a1f5596aa776a857de69f72c", 18 + // }, 19 19 .zigimg = .{ 20 - .url = "git+https://github.com/MidlightStudio/zigimg#637974e2d31dcdbc33f1e9cc8ffb2e46abd2e215", 21 - .hash = "122012026c3a65ff1d4acba3b3fe80785f7cee9c6b4cdaff7ed0fbf23b0a6c803989", 20 + .url = "git+https://github.com/altagos/zigimg#a5a18768691c27cf3b312b67ca5084148a502e3e", 21 + .hash = "1220e69e80741a9650a86e4369128698005f0049c6508b788e7fe1809480af62f4f8", 22 22 }, 23 23 }, 24 24 .paths = .{
+22
libs/zmath/LICENSE
··· 1 + MIT License 2 + 3 + Copyright (c) 2021 Michal Ziulek 4 + Copyright (c) 2024 zig-gamedev contributors 5 + 6 + Permission is hereby granted, free of charge, to any person obtaining a copy 7 + of this software and associated documentation files (the "Software"), to deal 8 + in the Software without restriction, including without limitation the rights 9 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + copies of the Software, and to permit persons to whom the Software is 11 + furnished to do so, subject to the following conditions: 12 + 13 + The above copyright notice and this permission notice shall be included in all 14 + copies or substantial portions of the Software. 15 + 16 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + SOFTWARE.
+3 -3
libs/zmath/build.zig
··· 26 26 const options_module = options_step.createModule(); 27 27 28 28 const zmath = b.addModule("root", .{ 29 - .root_source_file = .{ .path = "src/main.zig" }, 29 + .root_source_file = b.path("src/main.zig"), 30 30 .imports = &.{ 31 31 .{ .name = "zmath_options", .module = options_module }, 32 32 }, ··· 36 36 37 37 const tests = b.addTest(.{ 38 38 .name = "zmath-tests", 39 - .root_source_file = .{ .path = "src/main.zig" }, 39 + .root_source_file = b.path("src/main.zig"), 40 40 .target = target, 41 41 .optimize = options.optimize, 42 42 }); ··· 50 50 51 51 const benchmarks = b.addExecutable(.{ 52 52 .name = "zmath-benchmarks", 53 - .root_source_file = .{ .path = "src/benchmark.zig" }, 53 + .root_source_file = b.path("src/benchmark.zig"), 54 54 .target = target, 55 55 .optimize = options.optimize, 56 56 });
+5 -5
libs/zmath/src/util.zig
··· 111 111 var identity = zm.identity(); 112 112 var z_vec = getAxisZ(identity); 113 113 try expect(zm.approxEqAbs(z_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.0001)); 114 - const rot_yaw = zm.rotationY(degToRad(f32, 90)); 114 + const rot_yaw = zm.rotationY(degToRad(90)); 115 115 identity = zm.mul(identity, rot_yaw); 116 116 z_vec = getAxisZ(identity); 117 117 try expect(zm.approxEqAbs(z_vec, zm.f32x4(1.0, 0.0, 0.0, 0), 0.0001)); ··· 122 122 var identity = zm.identity(); 123 123 var y_vec = getAxisY(identity); 124 124 try expect(zm.approxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01)); 125 - const rot_yaw = zm.rotationY(degToRad(f32, 90)); 125 + const rot_yaw = zm.rotationY(degToRad(90)); 126 126 identity = zm.mul(identity, rot_yaw); 127 127 y_vec = getAxisY(identity); 128 128 try expect(zm.approxEqAbs(y_vec, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01)); 129 - const rot_pitch = zm.rotationX(degToRad(f32, 90)); 129 + const rot_pitch = zm.rotationX(degToRad(90)); 130 130 identity = zm.mul(identity, rot_pitch); 131 131 y_vec = getAxisY(identity); 132 132 try expect(zm.approxEqAbs(y_vec, zm.f32x4(0.0, 0.0, 1.0, 0), 0.01)); ··· 137 137 var identity = zm.identity(); 138 138 var right = getAxisX(identity); 139 139 try expect(zm.approxEqAbs(right, zm.f32x4(1.0, 0.0, 0.0, 0), 0.01)); 140 - const rot_yaw = zm.rotationY(degToRad(f32, 90)); 140 + const rot_yaw = zm.rotationY(degToRad(90)); 141 141 identity = zm.mul(identity, rot_yaw); 142 142 right = getAxisX(identity); 143 143 try expect(zm.approxEqAbs(right, zm.f32x4(0.0, 0.0, -1.0, 0), 0.01)); 144 - const rot_pitch = zm.rotationX(degToRad(f32, 90)); 144 + const rot_pitch = zm.rotationX(degToRad(90)); 145 145 identity = zm.mul(identity, rot_pitch); 146 146 right = getAxisX(identity); 147 147 try expect(zm.approxEqAbs(right, zm.f32x4(0.0, 1.0, 0.0, 0), 0.01));
+2 -2
libs/zmath/src/zmath.zig
··· 3089 3089 const singularity = p[0] * p[2] + sign * p[1] * p[3]; 3090 3090 if (singularity > 0.499) { 3091 3091 angles[0] = math.pi * 0.5; 3092 - angles[1] = 2.0 * math.atan2(f32, p[1], p[0]); 3092 + angles[1] = 2.0 * math.atan2(p[1], p[0]); 3093 3093 angles[2] = 0.0; 3094 3094 } else if (singularity < -0.499) { 3095 3095 angles[0] = -math.pi * 0.5; 3096 - angles[1] = 2.0 * math.atan2(f32, p[1], p[0]); 3096 + angles[1] = 2.0 * math.atan2(p[1], p[0]); 3097 3097 angles[2] = 0.0; 3098 3098 } else { 3099 3099 const sq = p * p;
+44 -17
src/BVH.zig
··· 35 35 } 36 36 }; 37 37 38 - const Leaf = Hittable; 38 + const Leaf = struct { 39 + objects: []Hittable, 40 + bbox: AABB, 41 + 42 + pub inline fn hit(self: *Leaf, r: *Ray, ray_t: IntervalF32) ?HitRecord { 43 + var rec: ?HitRecord = null; 44 + var interval = ray_t; 45 + for (self.objects) |obj| { 46 + if (@constCast(&obj).hit(r, interval)) |res| { 47 + interval = IntervalF32.init(ray_t.min, res.t); 48 + rec = res; 49 + } 50 + } 51 + return rec; 52 + } 53 + }; 54 + 55 + threadlocal var reached_depth: usize = 0; 56 + threadlocal var max_objects: usize = 0; 39 57 40 58 const Node = union(enum) { 41 59 ast: Ast, ··· 44 62 pub fn init( 45 63 self: *Node, 46 64 allocator: std.mem.Allocator, 47 - objects: []hittable.Hittable, 65 + objects: []Hittable, 66 + max_depth: usize, 67 + depth: usize, 48 68 ) !void { 49 - if (objects.len == 1) { 50 - self.* = .{ .leaf = objects[0] }; 51 - return; 52 - } 69 + if (reached_depth < depth) reached_depth = depth; 53 70 54 71 var ast_bbox = AABB{}; 55 72 for (0..objects.len) |idx| { 56 73 ast_bbox = AABB.initAB(&ast_bbox, &objects[idx].boundingBox()); 57 74 } 58 75 76 + if (depth >= max_depth or objects.len <= 2) { 77 + if (max_objects < objects.len) max_objects = objects.len; 78 + self.* = .{ .leaf = .{ .objects = objects, .bbox = ast_bbox } }; 79 + return; 80 + } 81 + 59 82 const axis = ast_bbox.longestAxis(); 60 - 61 - var left = try allocator.create(Node); 62 - var right = try allocator.create(Node); 63 83 64 84 if (axis == 0) { 65 85 std.mem.sort(Hittable, objects, .{}, boxXCompare); ··· 69 89 std.mem.sort(Hittable, objects, .{}, boxZCompare); 70 90 } 71 91 92 + var left = try allocator.create(Node); 93 + var right = try allocator.create(Node); 94 + 72 95 const mid = objects.len / 2; 73 - try left.init(allocator, objects[0..mid]); 74 - try right.init(allocator, objects[mid..]); 96 + try left.init(allocator, objects[0..mid], max_depth, depth + 1); 97 + try right.init(allocator, objects[mid..], max_depth, depth + 1); 75 98 76 99 self.* = .{ .ast = .{ 77 100 .left = left, ··· 92 115 allocator.destroy(right); 93 116 } 94 117 }, 95 - else => {}, 118 + .leaf => |*l| { 119 + allocator.destroy(&l.objects); 120 + }, 96 121 } 97 122 } 98 123 99 124 pub inline fn bbox(self: *Node) AABB { 100 125 switch (self.*) { 101 126 .ast => |*a| return a.bbox, 102 - .leaf => |l| return @constCast(&l).boundingBox(), 127 + .leaf => |*l| return l.bbox, 103 128 } 104 129 } 105 130 ··· 115 140 116 141 fn recomputeBbox(self: *Node) AABB { 117 142 switch (self.*) { 118 - .leaf => |*l| return l.boundingBox(), 143 + .leaf => |*l| return l.bbox, 119 144 .ast => |*a| { 120 145 var left = AABB{}; 121 146 var right = AABB{}; ··· 145 170 if (a.left) |left| left.print(depth + 1, 1); 146 171 if (a.right) |right| right.print(depth + 1, 2); 147 172 }, 148 - .leaf => |*l| std.debug.print("Leaf = {s}\n", .{l.getName()}), 173 + .leaf => |*l| std.debug.print("Leafs = {}\n", .{l}), 149 174 } 150 175 } 151 176 ··· 164 189 root: *Node, 165 190 bbox: AABB, 166 191 167 - pub fn init(allocator: std.mem.Allocator, objects: hittable.HittableList) !BVH { 192 + pub fn init(allocator: std.mem.Allocator, objects: hittable.HittableList, max_depth: usize) !BVH { 168 193 defer @constCast(&objects).deinit(); 169 194 std.log.info("Creating BVH Tree with {} objects", .{objects.list.items.len}); 170 195 171 196 const root = try allocator.create(Node); 172 - try root.init(allocator, objects.list.items); 197 + try root.init(allocator, objects.list.items, max_depth, 0); 173 198 const bbox = root.recomputeBbox(); 199 + 200 + std.log.debug("Reached depth of: {}, max objects: {}", .{ reached_depth, max_objects }); 174 201 175 202 // root.print(0, 0); 176 203 return .{
+12 -12
src/main.zig
··· 1 1 const std = @import("std"); 2 2 3 3 const aa = @import("a"); 4 - const spall = @import("spall"); 4 + // const spall = @import("spall"); 5 5 6 6 const rayray = @import("rayray"); 7 7 const Hittable = rayray.hittable.Hittable; ··· 22 22 defer arena.deinit(); 23 23 const allocator = arena.allocator(); 24 24 25 - try spall.init("./out/trace.spall"); 26 - defer spall.deinit(); 25 + // try spall.init("./out/trace.spall"); 26 + // defer spall.deinit(); 27 27 28 - spall.init_thread(); 29 - defer spall.deinit_thread(); 28 + // spall.init_thread(); 29 + // defer spall.deinit_thread(); 30 30 31 31 // Setting up the world 32 32 var scence = try scences.inOneWeekend(allocator); ··· 34 34 35 35 std.log.info("World created", .{}); 36 36 37 - const s = spall.trace(@src(), "Raytracer", .{}); 37 + // const s = spall.trace(@src(), "Raytracer", .{}); 38 38 39 39 // Raytracing part 40 40 var raytracer = try rayray.Raytracer.init(allocator, scence.world, .{ 41 41 .aspect_ratio = 16.0 / 9.0, 42 - .image_width = 4000, 43 - .samples_per_pixel = 500, 44 - .max_depth = 100, 42 + .image_width = 400, 43 + .samples_per_pixel = 50, 44 + .max_depth = 50, 45 45 46 46 .vfov = 20, 47 47 .look_from = zm.f32x4(20, 6, 6, 0), ··· 60 60 61 61 std.log.info("Image rendered ({}s)", .{rendering_time / std.time.ns_per_s}); 62 62 63 - s.end(); 63 + // s.end(); 64 64 65 65 // Saving to file 66 - const s_saving = spall.trace(@src(), "Write Image", .{}); 67 - defer s_saving.end(); 66 + // const s_saving = spall.trace(@src(), "Write Image", .{}); 67 + // defer s_saving.end(); 68 68 69 69 try img.writeToFilePath("./out/out.png", .{ .png = .{} }); 70 70 std.log.info("Image saved to: ./out/out.png", .{});
+43 -15
src/rayray.zig
··· 2 2 3 3 pub const zmath = @import("zmath"); 4 4 5 - const spall = @import("spall"); 5 + // const spall = @import("spall"); 6 6 const zigimg = @import("zigimg"); 7 7 const color = zigimg.color; 8 8 ··· 20 20 pub const TaskTracker = struct { 21 21 marked_as_done: bool = false, 22 22 done: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), 23 + thread_id: std.Thread.Id = 0, 23 24 }; 24 25 25 26 pub const Raytracer = struct { ··· 39 40 .allocator = allocator, 40 41 .thread_pool = thread_pool, 41 42 .camera = try Camera.init(allocator, camera_opts), 42 - .world = try BVH.init(allocator, world), 43 + .world = try BVH.init(allocator, world, 100), 43 44 }; 44 45 } 45 46 ··· 52 53 } 53 54 54 55 pub fn render(self: *Self) !zigimg.Image { 55 - const s = spall.trace(@src(), "Render", .{}); 56 - defer s.end(); 56 + // const s = spall.trace(@src(), "Render", .{}); 57 + // defer s.end(); 57 58 58 59 const chunk_height: usize = 25; 59 60 const chunk_width: usize = 25; ··· 102 103 ); 103 104 } 104 105 105 - const stderr = std.io.getStdErr(); 106 + // const stderr = std.io.getStdErr(); 106 107 107 - var progress = std.Progress{ 108 - .terminal = stderr, 109 - .supports_ansi_escape_codes = true, 110 - }; 111 - var node = progress.start("Rendered Chunks", num_chunks); 112 - node.setCompletedItems(0); 113 - node.context.refresh(); 108 + // var progress = std.Progress{ 109 + // .terminal = stderr, 110 + // .supports_ansi_escape_codes = true, 111 + // }; 112 + // var node = progress.start("Rendered Chunks", num_chunks); 113 + // node.setCompletedItems(0); 114 + // node.context.refresh(); 114 115 115 - var completed_chunks: u64 = 0; 116 + const num_threads = try std.Thread.getCpuCount(); 117 + var thread_to_idx = std.ArrayList(std.Thread.Id).init(self.allocator); 118 + defer thread_to_idx.deinit(); 116 119 120 + var root_node = std.Progress.start(.{ 121 + .root_name = "Ray Tracer", 122 + .estimated_total_items = num_threads, 123 + }); 124 + var nodes = std.ArrayList(std.Progress.Node).init(self.allocator); 125 + defer nodes.deinit(); 126 + 127 + for (0..num_threads) |_| { 128 + try nodes.append(root_node.start("Chunks Rendered", num_chunks / num_threads)); 129 + } 130 + 131 + var completed_chunks: u64 = 0; 132 + var i: usize = 0; 117 133 while (true) { 118 134 var done = true; 119 135 ··· 122 138 123 139 if (task_done and !t.marked_as_done) { 124 140 t.marked_as_done = true; 125 - node.completeOne(); 141 + 142 + const idx = blk: { 143 + for (thread_to_idx.items, 0..) |value, idx| { 144 + if (value == t.thread_id) break :blk idx; 145 + } 146 + try thread_to_idx.append(t.thread_id); 147 + const idx = i; 148 + i += 1; 149 + break :blk idx; 150 + }; 151 + nodes.items[idx].completeOne(); 152 + 126 153 completed_chunks += 1; 127 154 if (completed_chunks % self.thread_pool.threads.len == 0) try self.camera.image.writeToFilePath("./out/out.png", .{ .png = .{} }); 128 155 } else if (!task_done) { ··· 133 160 if (done or !self.thread_pool.is_running) break; 134 161 } 135 162 136 - node.end(); 163 + // node.end(); 137 164 138 165 return self.camera.image; 139 166 } ··· 141 168 142 169 pub fn renderThread(ctx: tracer.Context, task: *TaskTracker, id: usize) void { 143 170 defer task.done.store(true, .release); 171 + task.thread_id = std.Thread.getCurrentId(); 144 172 _ = id; 145 173 tracer.trace(ctx); 146 174 }
+11 -6
src/scences/in_one_weekend.zig
··· 17 17 material_ground.* = Material.lambertian(zm.f32x4(0.5, 0.5, 0.5, 1.0)); 18 18 try world.add(Hittable.sphere("Ground", Sphere{ .center = zm.f32x4(0, -1000, 0, 0), .radius = 1000, .mat = material_ground })); 19 19 20 - var a: isize = -33; 21 - while (a < 11) : (a += 1) { 22 - var b: isize = -22; 23 - while (b < 7) : (b += 1) { 20 + const a_max = 50; 21 + const b_max = 50; 22 + 23 + var a: isize = -a_max; 24 + while (a < a_max) : (a += 1) { 25 + var b: isize = -b_max; 26 + while (b < b_max) : (b += 1) { 24 27 const choose_mat = rayray.util.randomF32(); 25 28 const center = zm.f32x4( 26 29 @as(f32, @floatFromInt(a)) + 0.9 * rayray.util.randomF32(), ··· 55 58 56 59 const material1 = try allocator.create(Material); 57 60 material1.* = Material.dielectric(1.5); 58 - try world.add(Hittable.sphere("One: Dielectric", Sphere{ .center = zm.f32x4(0, 1, 0, 0), .radius = 1, .mat = material1 })); 61 + // try world.add(Hittable.sphere("One: Dielectric", Sphere{ .center = zm.f32x4(0, 1, 0, 0), .radius = 1, .mat = material1 })); 59 62 60 63 const material2 = try allocator.create(Material); 61 64 material2.* = Material.lambertian(zm.f32x4(0.4, 0.2, 0.1, 1)); 62 - try world.add(Hittable.sphere("Two: Lambertian", Sphere{ .center = zm.f32x4(-4, 1, 0, 0), .radius = 1, .mat = material2 })); 65 + try world.add(Hittable.sphere("Two: Lambertian", Sphere{ .center = zm.f32x4(-4, 1, 0, 0), .radius = 1, .mat = material1 })); 63 66 64 67 const material3 = try allocator.create(Material); 65 68 material3.* = Material.metal(zm.f32x4(0.7, 0.6, 0.5, 1), 0); 66 69 try world.add(Hittable.sphere("Three: Metal", Sphere{ .center = zm.f32x4(4, 1, 0, 0), .radius = 1, .mat = material3 })); 70 + 71 + try world.add(Hittable.sphere("One: Dielectric", Sphere{ .center = zm.f32x4(0, 1, 0, 0), .radius = 1, .mat = material2 })); 67 72 68 73 return .{ .allocator = allocator, .world = world }; 69 74 }
+1
src/tracer.zig
··· 40 40 const unit_direction = zm.normalize3(r.dir); 41 41 const a = 0.5 * (unit_direction[1] + 1.0); 42 42 return zm.f32x4s(1.0 - a) * zm.f32x4s(1.0) + zm.f32x4s(a) * zm.f32x4(0.5, 0.7, 1.0, 1.0); 43 + // return zm.f32x4s(1.0); 43 44 } 44 45 45 46 pub fn trace(ctx: Context) void {