diff --git a/src/BVH.zig b/src/BVH.zig index 8665f82..e36cd8b 100644 --- a/src/BVH.zig +++ b/src/BVH.zig @@ -194,9 +194,10 @@ pub inline fn hit(self: *BVH, r: *Ray, ray_t: IntervalF32) ?HitRecord { } inline fn boxCompare(a: *Hittable, b: *Hittable, axis_index: i32) bool { + @setFloatMode(std.builtin.FloatMode.optimized); const a_axis_interval = a.boundingBox().axisInterval(axis_index); const b_axis_interval = b.boundingBox().axisInterval(axis_index); - return a_axis_interval.min <= b_axis_interval.min; + return a_axis_interval.min < b_axis_interval.min; } fn boxXCompare(_: @TypeOf(.{}), a: Hittable, b: Hittable) bool { diff --git a/src/hittable/sphere.zig b/src/hittable/sphere.zig index d919b0c..e3463b0 100644 --- a/src/hittable/sphere.zig +++ b/src/hittable/sphere.zig @@ -30,7 +30,7 @@ pub fn initMoving(center1: zm.Vec, center2: zm.Vec, radius: f32, mat: *Material) }; } -pub fn boundingBox(self: *Sphere) AABB { +pub inline fn boundingBox(self: *Sphere) AABB { if (self.bbox) |bbox| { return bbox; } else { @@ -40,7 +40,7 @@ pub fn boundingBox(self: *Sphere) AABB { } } -pub fn hit(self: *Sphere, r: *Ray, ray_t: IntervalF32) ?HitRecord { +pub inline fn hit(self: *Sphere, r: *Ray, ray_t: IntervalF32) ?HitRecord { const center = blk: { if (self.is_moving) { break :blk self.sphereCenter(r.tm); @@ -77,6 +77,6 @@ pub fn hit(self: *Sphere, r: *Ray, ray_t: IntervalF32) ?HitRecord { return rec; } -pub fn sphereCenter(self: *Sphere, time: f32) zm.Vec { +pub inline fn sphereCenter(self: *Sphere, time: f32) zm.Vec { return self.center + zm.f32x4s(time) * self.center_vec; } diff --git a/src/main.zig b/src/main.zig index a374997..21c2b7c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -39,7 +39,7 @@ pub fn main() !void { // Raytracing part var raytracer = try rayray.Raytracer.init(allocator, scence.world, .{ .aspect_ratio = 16.0 / 9.0, - .image_width = 800, + .image_width = 400, .samples_per_pixel = 100, .max_depth = 50, diff --git a/src/material.zig b/src/material.zig index 4aaf1e5..49c83cd 100644 --- a/src/material.zig +++ b/src/material.zig @@ -23,7 +23,7 @@ pub const Material = union(enum) { return .{ .dielectric = .{ .refraction_index = refraction_index } }; } - pub fn scatter(self: *Material, r: *Ray, rec: *hittable.HitRecord, attenuation: *zm.Vec) ?Ray { + pub inline fn scatter(self: *Material, r: *Ray, rec: *hittable.HitRecord, attenuation: *zm.Vec) ?Ray { return switch (self.*) { .lambertian => |*lambert| lambert.scatter(r, rec, attenuation), .metal => |*met| met.scatter(r, rec, attenuation), @@ -35,13 +35,14 @@ pub const Material = union(enum) { pub const Lambertian = struct { albedo: zm.Vec, - pub fn scatter(self: *Lambertian, r: *Ray, rec: *hittable.HitRecord, attenuation: *zm.Vec) ?Ray { + pub inline fn scatter(self: *Lambertian, r: *Ray, rec: *hittable.HitRecord, attenuation: *zm.Vec) ?Ray { var scatter_dir = rec.normal + util.randomUnitVec(); if (util.nearZero(scatter_dir)) scatter_dir = rec.normal; attenuation.* = self.albedo; - return Ray.initT(rec.p, scatter_dir, r.tm); + // return Ray.initT(rec.p, scatter_dir, r.tm); + return Ray{ .orig = rec.p, .dir = scatter_dir, .tm = r.tm }; } }; @@ -50,7 +51,7 @@ pub const Metal = struct { /// fuzz < 1 fuzz: f32, - pub fn scatter(self: *Metal, r: *Ray, rec: *hittable.HitRecord, attenuation: *zm.Vec) ?Ray { + pub inline fn scatter(self: *Metal, r: *Ray, rec: *hittable.HitRecord, attenuation: *zm.Vec) ?Ray { const reflected = util.reflect(r.dir, rec.normal); const scattered = Ray.initT(rec.p, zm.normalize3(reflected) + zm.f32x4s(self.fuzz) * util.randomUnitVec(), r.tm); attenuation.* = self.albedo; @@ -67,21 +68,19 @@ pub const Dielectric = struct { const unit_direction = zm.normalize3(r.dir); const cos_theta = @min(zm.dot3(-unit_direction, rec.normal)[0], 1.0); - const sin_theta = @sqrt(1.0 - cos_theta * cos_theta); + const sin_theta = @sqrt(1.0 - math.pow(f32, cos_theta, 2)); const cannot_refract = ri * sin_theta > 1.0; - const direction = blk: { - if (cannot_refract or reflectance(cos_theta, ri) > util.randomF32()) { - break :blk util.reflect(unit_direction, rec.normal); - } else { - break :blk util.refract(unit_direction, rec.normal, ri); - } - }; + const direction = if (cannot_refract or reflectance(cos_theta, ri) > util.randomF32()) + util.reflect(unit_direction, rec.normal) + else + util.refract(unit_direction, rec.normal, ri); - return Ray.initT(rec.p, direction, r.tm); + // return Ray.initT(rec.p, direction, r.tm); + return Ray{ .orig = rec.p, .dir = direction, .tm = r.tm }; } - fn reflectance(cosine: f32, refraction_index: f32) f32 { + inline fn reflectance(cosine: f32, refraction_index: f32) f32 { var r0 = (1 - refraction_index) / (1 + refraction_index); r0 = r0 * r0; return r0 + (1 - r0) * math.pow(f32, 1 - cosine, 5); diff --git a/src/ray.zig b/src/ray.zig index 44b5945..35a04c7 100644 --- a/src/ray.zig +++ b/src/ray.zig @@ -1,5 +1,3 @@ -const std = @import("std"); - const zm = @import("zmath"); const Ray = @This(); @@ -24,6 +22,6 @@ pub fn initT(origin: zm.Vec, direction: zm.Vec, tm: f32) Ray { }; } -pub fn at(self: *Ray, t: f32) zm.Vec { +pub inline fn at(self: *Ray, t: f32) zm.Vec { return self.orig + zm.f32x4s(t) * self.dir; } diff --git a/src/rayray.zig b/src/rayray.zig index 897d921..7609afb 100644 --- a/src/rayray.zig +++ b/src/rayray.zig @@ -93,8 +93,6 @@ pub const Raytracer = struct { .width = c_width, }; - // log.debug("Spawning chunk: {}, row start: {}, col start: {}", .{ id, row, col }); - try self.thread_pool.spawn( renderThread, .{ ctx, t, id }, diff --git a/src/scences/in_one_weekend.zig b/src/scences/in_one_weekend.zig index 9d860d0..e74497e 100644 --- a/src/scences/in_one_weekend.zig +++ b/src/scences/in_one_weekend.zig @@ -7,7 +7,6 @@ const Hittable = rayray.hittable.Hittable; const HittableList = rayray.hittable.HittableList; const Material = rayray.material.Material; const Sphere = rayray.hittable.Sphere; -const BVH = rayray.hittable.BVH; world: HittableList, allocator: std.mem.Allocator, @@ -19,10 +18,10 @@ pub fn scene(allocator: std.mem.Allocator) !@This() { material_ground.* = Material.lambertian(zm.f32x4(0.5, 0.5, 0.5, 1.0)); try world.add(Hittable.sphere("Ground", Sphere{ .center = zm.f32x4(0, -1000, 0, 0), .radius = 1000, .mat = material_ground })); - var a: isize = -11; - while (a < 11) : (a += 1) { - var b: isize = -11; - while (b < 11) : (b += 1) { + var a: isize = -22; + while (a < 22) : (a += 1) { + var b: isize = -22; + while (b < 22) : (b += 1) { const choose_mat = rayray.util.randomF32(); const center = zm.f32x4( @as(f32, @floatFromInt(a)) + 0.9 * rayray.util.randomF32(), diff --git a/src/tracer.zig b/src/tracer.zig index 160839e..7c9f450 100644 --- a/src/tracer.zig +++ b/src/tracer.zig @@ -25,7 +25,8 @@ pub const Context = struct { }; pub fn rayColor(r: *Ray, world: *BVH, depth: usize) zm.Vec { - if (depth <= 0) return zm.f32x4(0, 0, 0, 1.0); + @setFloatMode(.optimized); + if (depth == 0) return zm.f32x4(0, 0, 0, 1.0); if (world.hit(r, .{ .min = 0.001, .max = std.math.inf(f32) })) |rec| { var attenuation = zm.f32x4s(1.0); @@ -59,23 +60,19 @@ pub fn trace(ctx: Context) void { } } -fn vecToRgba(v: zm.Vec, samples_per_pixel: usize) zigimg.color.Rgba32 { - const scale: f32 = 1.0 / @as(f32, @floatFromInt(samples_per_pixel)); - const intensity = IntervalF32.init(0.0, 0.999); - - const r_scaled = linearToGamma(v[0] * scale); - const g_scaled = linearToGamma(v[1] * scale); - const b_scaled = linearToGamma(v[2] * scale); - const a_scaled = linearToGamma(v[3] * scale); - - const r: u8 = @intFromFloat(256 * intensity.clamp(r_scaled)); - const g: u8 = @intFromFloat(256 * intensity.clamp(g_scaled)); - const b: u8 = @intFromFloat(256 * intensity.clamp(b_scaled)); - const a: u8 = @intFromFloat(256 * intensity.clamp(a_scaled)); - - return zigimg.color.Rgba32.initRgba(r, g, b, a); +inline fn vecToRgba(v: zm.Vec, samples_per_pixel: usize) zigimg.color.Rgba32 { + var rgba = linearToGamma(zm.Vec, v / zm.f32x4s(@as(f32, @floatFromInt(samples_per_pixel)))); + rgba = zm.clampFast(rgba, zm.f32x4s(0.0), zm.f32x4s(0.999)); + rgba = rgba * zm.f32x4s(256); + + return zigimg.color.Rgba32.initRgba( + @intFromFloat(rgba[0]), + @intFromFloat(rgba[1]), + @intFromFloat(rgba[2]), + @intFromFloat(rgba[3]), + ); } -inline fn linearToGamma(linear_component: f32) f32 { +inline fn linearToGamma(comptime T: type, linear_component: T) T { return @sqrt(linear_component); } diff --git a/src/util.zig b/src/util.zig index 6e95709..e2c4ded 100644 --- a/src/util.zig +++ b/src/util.zig @@ -77,7 +77,7 @@ pub inline fn randomOnHemisphere(normal: zm.Vec) zm.Vec { -on_unit_sphere; } -pub fn nearZero(e: zm.Vec) bool { +pub inline fn nearZero(e: zm.Vec) bool { const s = 1e-8; return (@abs(e[0]) < s) and (@abs(e[1]) < s) and (@abs(e[2]) < s); }