this repo has no description
0
fork

Configure Feed

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

implemented stuff from the book but does not work yet

Altagos 3615ebf3 f81139a6

+356 -55
+2 -1
build.zig.zon
··· 1 1 .{ 2 2 .name = "rayray", 3 3 .version = "0.1.0", 4 - .minimum_zig_version = "0.12.0-dev.2631+3069669bc", 4 + .zig_version = "v0.13.0-dev.3+dddddcffd", 5 + .minimum_zig_version = "0.13.0-dev.3+dddddcffd", 5 6 .dependencies = .{ 6 7 // libs folder 7 8 .zmath = .{ .path = "libs/zmath" },
+84
src/AABB.zig
··· 1 + const zm = @import("zmath"); 2 + 3 + const HitRecord = @import("hittable.zig").HitRecord; 4 + const Interval = @import("interval.zig").IntervalF32; 5 + const Ray = @import("Ray.zig"); 6 + 7 + const AABB = @This(); 8 + 9 + x: Interval = Interval.empty, 10 + y: Interval = Interval.empty, 11 + z: Interval = Interval.empty, 12 + 13 + pub fn init(x: Interval, y: Interval, z: Interval) AABB { 14 + return AABB{ .x = x, .y = y, .z = z }; 15 + } 16 + 17 + pub fn initP(a: zm.Vec, b: zm.Vec) AABB { 18 + // Treat the two points a and b as extrema for the bounding box, so we don't require a 19 + // particular minimum/maximum coordinate order. 20 + return AABB{ 21 + .x = blk: { 22 + if (a[0] <= b[0]) break :blk Interval.init(a[0], b[0]) else break :blk Interval.init(b[0], a[0]); 23 + }, 24 + .y = blk: { 25 + if (a[1] <= b[1]) break :blk Interval.init(a[1], b[1]) else break :blk Interval.init(b[1], a[1]); 26 + }, 27 + .z = blk: { 28 + if (a[2] <= b[2]) break :blk Interval.init(a[2], b[2]) else break :blk Interval.init(b[2], a[2]); 29 + }, 30 + }; 31 + } 32 + 33 + pub fn initAB(a: *const AABB, b: *const AABB) AABB { 34 + return AABB{ 35 + .x = Interval.initI(a.x, b.x), 36 + .y = Interval.initI(a.y, b.y), 37 + .z = Interval.initI(a.z, b.z), 38 + }; 39 + } 40 + 41 + pub fn axisInterval(self: *const AABB, n: i32) Interval { 42 + if (n == 1) return self.y; 43 + if (n == 2) return self.z; 44 + return self.x; 45 + } 46 + 47 + pub fn hit(self: *AABB, r: *Ray, ray_t: Interval) bool { 48 + const ray_orig = r.orig; 49 + const ray_dir = r.dir; 50 + 51 + var t = ray_t; 52 + 53 + for (0..3) |axis| { 54 + const ax = self.axisInterval(@intCast(axis)); 55 + const adinv = 1.0 / ray_dir[axis]; 56 + 57 + const t0 = (ax.min - ray_orig[axis]) * adinv; 58 + const t1 = (ax.max - ray_orig[axis]) * adinv; 59 + 60 + if (t0 < t1) { 61 + if (t0 > t.min) t.min = t0; 62 + if (t1 < t.max) t.max = t1; 63 + } else { 64 + if (t1 > t.min) t.min = t1; 65 + if (t0 < t.max) t.max = t0; 66 + } 67 + 68 + if (ray_t.max <= ray_t.min) return false; 69 + } 70 + 71 + return true; 72 + } 73 + 74 + pub fn longestAxis(self: *AABB) i32 { 75 + if (self.x.size() > self.y.size()) { 76 + if (self.x.size() > self.z.size()) { 77 + return 0; 78 + } else return 2; 79 + } else { 80 + if (self.y.size() > self.z.size()) { 81 + return 1; 82 + } else return 2; 83 + } 84 + }
+33
src/hittable.zig
··· 2 2 3 3 const zm = @import("zmath"); 4 4 5 + const AABB = @import("AABB.zig"); 5 6 const IntervalF32 = @import("interval.zig").IntervalF32; 6 7 const Material = @import("material.zig").Material; 7 8 const Ray = @import("Ray.zig"); 8 9 9 10 // Hittable Objects 10 11 pub const Sphere = @import("hittable/Sphere.zig"); 12 + pub const BVH = @import("hittable/BVH.zig"); 11 13 12 14 pub const HitRecord = struct { 13 15 p: zm.Vec, ··· 24 26 25 27 pub const Hittable = union(enum) { 26 28 sphere: Sphere, 29 + bvh_node: BVH, 27 30 28 31 pub fn sphere(s: Sphere) Hittable { 32 + // std.log.info("created sphere with mat: {}", .{s.mat}); 29 33 return .{ .sphere = s }; 30 34 } 31 35 36 + pub fn bvh(b: BVH) Hittable { 37 + return .{ .bvh_node = b }; 38 + } 39 + 40 + pub fn boundingBox(self: *Hittable) AABB { 41 + switch (self.*) { 42 + .sphere => |*s| return s.boundingBox(), 43 + .bvh_node => |*s| return s.boundingBox(), 44 + } 45 + } 46 + 32 47 pub fn hit(self: *Hittable, r: *Ray, ray_t: IntervalF32) ?HitRecord { 33 48 switch (self.*) { 34 49 .sphere => |*s| { 50 + std.log.debug("try to hit Sphere: {}", .{s}); 51 + // std.log.info("hitting sphere with mat: {}", .{s.mat}); 52 + return s.hit(r, ray_t); 53 + }, 54 + .bvh_node => |*s| { 55 + // std.log.debug("try to hit BVH", .{}); 35 56 return s.hit(r, ray_t); 36 57 }, 37 58 } ··· 42 63 43 64 pub const HittableList = struct { 44 65 list: std.ArrayList(Hittable), 66 + bbox: AABB = AABB{}, 45 67 46 68 pub fn init(allocator: std.mem.Allocator) HittableList { 47 69 const list = std.ArrayList(Hittable).init(allocator); ··· 49 71 return .{ .list = list }; 50 72 } 51 73 74 + pub fn initH(allocator: std.mem.Allocator, item: Hittable) !HittableList { 75 + var list = std.ArrayList(Hittable).init(allocator); 76 + try list.append(item); 77 + return .{ .list = list, .bbox = AABB.initAB(&AABB{}, &(@constCast(&item).boundingBox())) }; 78 + } 79 + 52 80 pub fn deinit(self: *HittableList) void { 53 81 self.list.deinit(); 54 82 } 55 83 56 84 pub fn add(self: *HittableList, item: Hittable) !void { 57 85 try self.list.append(item); 86 + self.bbox = AABB.initAB(&self.bbox, &(@constCast(&item).boundingBox())); 87 + } 88 + 89 + pub fn boundingBox(self: *HittableList) AABB { 90 + return self.bbox; 58 91 } 59 92 60 93 pub fn hit(self: *HittableList, r: *Ray, ray_t: IntervalF32) ?HitRecord {
+106
src/hittable/BVH.zig
··· 1 + const std = @import("std"); 2 + 3 + const AABB = @import("../AABB.zig"); 4 + const hittable = @import("../hittable.zig"); 5 + const Hittable = hittable.Hittable; 6 + const HitRecord = hittable.HitRecord; 7 + const IntervalF32 = @import("../interval.zig").IntervalF32; 8 + const Ray = @import("../Ray.zig"); 9 + const util = @import("../util.zig"); 10 + 11 + pub const BVH = @This(); 12 + 13 + objects: *hittable.HittableList, 14 + left: *Hittable, 15 + right: *Hittable, 16 + bbox: AABB, 17 + 18 + pub fn initL(objects: *hittable.HittableList) BVH { 19 + std.log.info("starting to create BVH", .{}); 20 + return BVH.init(objects, 0, objects.list.items.len); 21 + } 22 + 23 + pub fn init(objects: *hittable.HittableList, start: usize, end: usize) BVH { 24 + const list = objects.list.items; 25 + var bbox = AABB{}; 26 + for (start..end) |idx| { 27 + bbox = AABB.initAB(&bbox, &list[idx].boundingBox()); 28 + } 29 + 30 + const axis = bbox.longestAxis(); 31 + 32 + // const comparator = blk: { 33 + // if (axis == 0) { 34 + // break :blk &boxXCompare; 35 + // } else if (axis == 1) { 36 + // break :blk &boxYCompare; 37 + // } 38 + // break :blk &boxZCompare; 39 + // }; 40 + 41 + const object_span = end - start; 42 + 43 + var left = &list[start]; 44 + var right = &list[start]; 45 + if (object_span == 2) { 46 + left = &list[start]; 47 + right = &list[start + 1]; 48 + } else if (object_span > 2) { 49 + std.log.debug("BVH.init axis={} start={} end={}", .{axis, start, end}); 50 + if (axis == 0) { 51 + // break :blk&boxXCompare; 52 + std.mem.sort(Hittable, list, .{}, boxXCompare); 53 + } else if (axis == 1) { 54 + // break :blk &boxYCompare; 55 + std.mem.sort(Hittable, list, .{}, boxYCompare); 56 + } else { 57 + // break :blk &boxZCompare; 58 + std.mem.sort(Hittable, list, .{}, boxZCompare); 59 + } 60 + // std.mem.sort(Hittable, list, null, comparator); 61 + 62 + const mid = start + object_span / 2; 63 + left = @constCast(&Hittable.bvh(BVH.init(objects, start, mid))); 64 + right = @constCast(&Hittable.bvh(BVH.init(objects, mid, end))); 65 + } 66 + 67 + std.log.info("BVH created", .{}); 68 + 69 + return .{ 70 + .objects = objects, 71 + .left = left, 72 + .right = right, 73 + .bbox = bbox, 74 + }; 75 + } 76 + 77 + pub fn hit(self: *BVH, r: *Ray, ray_t: IntervalF32) ?HitRecord { 78 + if (!self.bbox.hit(r, ray_t)) { 79 + return null; 80 + } 81 + 82 + if (self.left.hit(r, ray_t)) |rec| return rec; 83 + if (self.right.hit(r, ray_t)) |rec| return rec; 84 + return null; 85 + } 86 + 87 + pub fn boundingBox(self: *BVH) AABB { 88 + return self.bbox; 89 + } 90 + 91 + fn boxCompare(a: *Hittable, b: *Hittable, axis_index: i32) bool { 92 + const a_axis_interval = a.boundingBox().axisInterval(axis_index); 93 + const b_axis_interval = b.boundingBox().axisInterval(axis_index); 94 + return a_axis_interval.min < b_axis_interval.min; 95 + } 96 + 97 + fn boxXCompare(_: @TypeOf(.{}), a: Hittable, b: Hittable) bool { 98 + return boxCompare(@constCast(&a), @constCast(&b), 0); 99 + } 100 + 101 + fn boxYCompare(_: @TypeOf(.{}), a: Hittable, b: Hittable) bool { 102 + return boxCompare(@constCast(&a), @constCast(&b), 1); 103 + } 104 + fn boxZCompare(_: @TypeOf(.{}), a: Hittable, b: Hittable) bool { 105 + return boxCompare(@constCast(&a), @constCast(&b), 2); 106 + }
+19 -2
src/hittable/sphere.zig
··· 1 1 const zm = @import("zmath"); 2 2 3 + const AABB = @import("../AABB.zig"); 3 4 const IntervalF32 = @import("../interval.zig").IntervalF32; 4 5 const Ray = @import("../Ray.zig"); 5 6 const HitRecord = @import("../hittable.zig").HitRecord; ··· 12 13 mat: *Material, 13 14 is_moving: bool = false, 14 15 center_vec: zm.Vec = zm.f32x4s(0), 16 + bbox: ?AABB = null, 15 17 16 - pub fn initMoving(center1: zm.Vec, center2: zm.Vec, radius: f32, mat: *Material) Sphere { 17 - return .{ 18 + pub fn initMoving(center1: zm.Vec, center2: zm.Vec, radius: f32, mat: Material) Sphere { 19 + const rvec = zm.f32x4s(radius); 20 + const box1 = AABB.initP(center1 - rvec, center1 + rvec); 21 + const box2 = AABB.initP(center2 - rvec, center2 + rvec); 22 + 23 + return Sphere{ 18 24 .center = center1, 19 25 .radius = @max(0, radius), 20 26 .mat = mat, 21 27 .is_moving = true, 22 28 .center_vec = center2 - center1, 29 + .bbox = AABB.initAB(&box1, &box2), 23 30 }; 31 + } 32 + 33 + pub fn boundingBox(self: *Sphere) AABB { 34 + if (self.bbox) |bbox| { 35 + return bbox; 36 + } else { 37 + const rvec = zm.f32x4s(self.radius); 38 + self.bbox = AABB.initP(self.center - rvec, self.center + rvec); 39 + return self.bbox.?; 40 + } 24 41 } 25 42 26 43 pub fn hit(self: *Sphere, r: *Ray, ray_t: IntervalF32) ?HitRecord {
+18 -2
src/interval.zig
··· 82 82 return .{ .min = min, .max = max }; 83 83 } 84 84 85 + pub fn initI(a: Self, b: Self) Self { 86 + return Self{ .min = @min(a.min, b.min), .max = @max(a.max, b.max) }; 87 + } 88 + 85 89 pub fn contains(self: *const Self, x: T) bool { 86 90 return self.min <= x and x <= self.max; 87 91 } ··· 101 105 return .{ .min = self.min - padding, .max = self.max + padding }; 102 106 } 103 107 108 + pub fn size(self: *const Self) T { 109 + return self.max - self.min; 110 + } 111 + 104 112 pub fn iter(self: *const Self) Iterator { 105 113 return Iterator{ 106 114 .interval = self.*, ··· 121 129 max: T, 122 130 123 131 pub fn init(min: T, max: T) Self { 124 - return .{ .min = min, .max = max }; 132 + return Self{ .min = min, .max = max }; 133 + } 134 + 135 + pub fn initI(a: Self, b: Self) Self { 136 + return Self{ .min = @min(a.min, b.min), .max = @max(a.max, b.max) }; 125 137 } 126 138 127 139 pub fn contains(self: *const Self, x: T) bool { ··· 138 150 return x; 139 151 } 140 152 141 - pub fn expand(self: *const Self, delta: T) Interval { 153 + pub fn expand(self: *const Self, delta: T) Self { 142 154 const padding = delta / 2; 143 155 return .{ .min = self.min - padding, .max = self.max + padding }; 156 + } 157 + 158 + pub fn size(self: *const Self) T { 159 + return self.max - self.min; 144 160 } 145 161 }; 146 162 }
+6 -49
src/main.zig
··· 10 10 const Material = rayray.material.Material; 11 11 const Sphere = rayray.hittable.Sphere; 12 12 13 + const scences = @import("scences.zig"); 14 + 13 15 pub const std_options = .{ 14 16 .log_level = .debug, 15 17 .logFn = aa.log.logFn, ··· 27 29 defer spall.deinit_thread(); 28 30 29 31 // Setting up the world 30 - var material_ground = Material.lambertian(zm.f32x4(0.5, 0.5, 0.5, 1.0)); 31 - 32 - var world = HittableList.init(allocator); 33 - try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, -1000, 0, 0), .radius = 1000, .mat = &material_ground })); 34 - 35 - var a: isize = -11; 36 - while (a < 11) : (a += 1) { 37 - var b: isize = -11; 38 - while (b < 11) : (b += 1) { 39 - const choose_mat = rayray.util.randomF32(); 40 - const center = zm.f32x4( 41 - @as(f32, @floatFromInt(a)) + 0.9 * rayray.util.randomF32(), 42 - 0.2, 43 - @as(f32, @floatFromInt(b)) + 0.9 * rayray.util.randomF32(), 44 - 0, 45 - ); 32 + var scence = try scences.inOneWeekend(allocator); 33 + defer scence.deinit(); 46 34 47 - if (zm.length3(center - zm.f32x4(4, 0.2, 0, 0))[0] > 0.9) { 48 - const material = try allocator.create(Material); 49 - 50 - if (choose_mat < 0.8) { 51 - // diffuse 52 - const albedo = rayray.util.randomVec3() * rayray.util.randomVec3() + zm.f32x4(0, 0, 0, 1); 53 - material.* = Material.lambertian(albedo); 54 - const center2 = center + zm.f32x4(0, rayray.util.randomF32M(0, 0.5), 0, 0); 55 - try world.add(Hittable.sphere(Sphere.initMoving(center, center2, 0.2, material))); 56 - } else if (choose_mat < 0.95) { 57 - // metal 58 - const albedo = rayray.util.randomVec3M(0.5, 1) + zm.f32x4(0, 0, 0, 1); 59 - const fuzz = rayray.util.randomF32M(0, 0.5); 60 - material.* = Material.metal(albedo, fuzz); 61 - try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material })); 62 - } else { 63 - // glass 64 - material.* = Material.dielectric(1.5); 65 - try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material })); 66 - } 67 - } 68 - } 69 - } 70 - 71 - var material1 = Material.dielectric(1.5); 72 - try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, 1, 0, 0), .radius = 1, .mat = &material1 })); 73 - 74 - var material2 = Material.lambertian(zm.f32x4(0.4, 0.2, 0.1, 1)); 75 - try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(-4, 1, 0, 0), .radius = 1, .mat = &material2 })); 76 - 77 - var material3 = Material.metal(zm.f32x4(0.7, 0.6, 0.5, 1), 0); 78 - try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(4, 1, 0, 0), .radius = 1, .mat = &material3 })); 35 + std.log.info("World created", .{}); 79 36 80 37 const s = spall.trace(@src(), "Raytracer", .{}); 81 38 82 39 // Raytracing part 83 - var raytracer = try rayray.Raytracer.init(allocator, world, .{ 40 + var raytracer = try rayray.Raytracer.init(allocator, scence.world, .{ 84 41 .aspect_ratio = 16.0 / 9.0, 85 42 .image_width = 400, 86 43 .samples_per_pixel = 100,
+1 -1
src/rayray.zig
··· 136 136 }; 137 137 138 138 pub fn renderThread(ctx: tracer.Context, task: *TaskTracker, id: usize) void { 139 + defer task.done.store(true, .release); 139 140 _ = id; 140 141 tracer.trace(ctx); 141 - task.done.store(true, .release); 142 142 }
+1
src/scences.zig
··· 1 + pub const inOneWeekend = @import("scences/in_one_weekend.zig").scene;
+76
src/scences/in_one_weekend.zig
··· 1 + const std = @import("std"); 2 + 3 + const zm = @import("zmath"); 4 + 5 + const rayray = @import("rayray"); 6 + const Hittable = rayray.hittable.Hittable; 7 + const HittableList = rayray.hittable.HittableList; 8 + const Material = rayray.material.Material; 9 + const Sphere = rayray.hittable.Sphere; 10 + const BVH = rayray.hittable.BVH; 11 + 12 + world: HittableList, 13 + allocator: std.mem.Allocator, 14 + 15 + pub fn scene(allocator: std.mem.Allocator) !@This() { 16 + var world = HittableList.init(allocator); 17 + 18 + const material_ground = try allocator.create(Material); 19 + material_ground.* = Material.lambertian(zm.f32x4(0.5, 0.5, 0.5, 1.0)); 20 + try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, -1000, 0, 0), .radius = 1000, .mat = material_ground })); 21 + 22 + var a: isize = -11; 23 + while (a < 11) : (a += 1) { 24 + var b: isize = -11; 25 + while (b < 11) : (b += 1) { 26 + const choose_mat = rayray.util.randomF32(); 27 + const center = zm.f32x4( 28 + @as(f32, @floatFromInt(a)) + 0.9 * rayray.util.randomF32(), 29 + 0.2, 30 + @as(f32, @floatFromInt(b)) + 0.9 * rayray.util.randomF32(), 31 + 0, 32 + ); 33 + 34 + if (zm.length3(center - zm.f32x4(4, 0.2, 0, 0))[0] > 0.9) { 35 + const material = try allocator.create(Material); 36 + 37 + if (choose_mat < 0.8) { 38 + // diffuse 39 + const albedo = rayray.util.randomVec3() * rayray.util.randomVec3() + zm.f32x4(0, 0, 0, 1); 40 + material.* = Material.lambertian(albedo); 41 + try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material })); 42 + } else if (choose_mat < 0.95) { 43 + // metal 44 + const albedo = rayray.util.randomVec3M(0.5, 1) + zm.f32x4(0, 0, 0, 1); 45 + const fuzz = rayray.util.randomF32M(0, 0.5); 46 + material.* = Material.metal(albedo, fuzz); 47 + try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material })); 48 + } else { 49 + // glass 50 + material.* = Material.dielectric(1.5); 51 + try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material })); 52 + } 53 + } 54 + } 55 + } 56 + 57 + const material1 = try allocator.create(Material); 58 + material1.* = Material.dielectric(1.5); 59 + try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, 1, 0, 0), .radius = 1, .mat = material1 })); 60 + 61 + const material2 = try allocator.create(Material); 62 + material2.* = Material.lambertian(zm.f32x4(0.4, 0.2, 0.1, 1)); 63 + try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(-4, 1, 0, 0), .radius = 1, .mat = material2 })); 64 + 65 + const material3 = try allocator.create(Material); 66 + material3.* = Material.metal(zm.f32x4(0.7, 0.6, 0.5, 1), 0); 67 + try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(4, 1, 0, 0), .radius = 1, .mat = material3 })); 68 + 69 + var world2 = HittableList.init(allocator); 70 + try world2.add(Hittable.bvh(BVH.initL(&world))); 71 + return .{ .allocator = allocator, .world = world2 }; 72 + } 73 + 74 + pub fn deinit(self: *@This()) void { 75 + self.world.deinit(); 76 + }
+10
src/util.zig
··· 17 17 return min + (max - min) * randomF32(); 18 18 } 19 19 20 + /// Returns a random real in [0,1). 21 + pub inline fn randomI32() i32 { 22 + return random.float(i32); 23 + } 24 + 25 + /// Returns a random real in [min,max). 26 + pub inline fn randomI32M(min: i32, max: i32) i32 { 27 + return min + (max - min) * randomI32(); 28 + } 29 + 20 30 pub inline fn randomVec2() zm.Vec { 21 31 return zm.f32x4(randomF32(), randomF32(), 0, 0); 22 32 }