Something went wrong. Try again.
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798const std = @import("std");
const spall = @import("spall");const zigimg = @import("zigimg");const zm = @import("zmath");
const BVH = @import("BVH.zig");const Camera = @import("Camera.zig");const hittable = @import("hittable.zig");const material = @import("material.zig");const Ray = @import("Ray.zig");const util = @import("util.zig");
const interval = @import("interval.zig");const IntervalUsize = interval.IntervalUsize;const IntervalF32 = interval.IntervalF32;
const log = std.log.scoped(.tracer);
pub const Context = struct { pixels: []zm.Vec, cam: *const Camera, world: *const BVH, height: IntervalUsize, width: IntervalUsize,};
const white = zm.f32x4s(1.0);const black = zm.f32x4(0, 0, 0, 1.0);
pub fn rayColor(r: *Ray, world: *const BVH, depth: usize) zm.Vec { @setFloatMode(.optimized); if (depth == 0) return backgroundColor(r);
if (world.hit(r, .{ .min = 0.001, .max = std.math.inf(f32) })) |rec| { var attenuation = zm.f32x4s(1.0); if (rec.mat.scatter(r, &rec, &attenuation)) |new_r| { return attenuation * rayColor(@constCast(&new_r), world, depth - 1); } }
return backgroundColor(r);}
fn backgroundColor(r: *Ray) zm.Vec { const unit_direction = zm.normalize3(r.dir); const a = 0.5 * (unit_direction[1] + 1.0); return zm.f32x4s(1.0 - a) * zm.f32x4s(1.0) + zm.f32x4s(a) * zm.f32x4(0.5, 0.7, 1.0, 1.0);}
pub fn trace(ctx: *Context) void { var height_iter = ctx.height.iter(); while (height_iter.nextInc()) |j| { if (j >= ctx.cam.image_height) break;
var width_iter = ctx.width.iter(); while (width_iter.nextExc()) |i| inner: { var col = zm.f32x4(0.0, 0.0, 0.0, 1.0);
for (0..ctx.cam.samples_per_pixel) |_| { var ray = ctx.cam.getRay(i, j); col += rayColor(&ray, ctx.world, ctx.cam.max_depth); }
setPixel(ctx.pixels, ctx.cam, i, j, col) catch { log.err("Trying to set a pixel out of bounds ({}, {})", .{ i, j }); break :inner; }; } }}
const zero = zm.f32x4s(0.0);const nearly_one = zm.f32x4s(0.999);const v256 = zm.f32x4s(256);
inline fn vecToRgba(v: zm.Vec, samples_per_pixel: zm.Vec) zigimg.color.Rgba32 { const rgba = zm.clampFast( @sqrt(v / samples_per_pixel), zero, nearly_one, ) * v256; // linear to gamma
return zigimg.color.Rgba32.initRgba( @intFromFloat(rgba[0]), @intFromFloat(rgba[1]), @intFromFloat(rgba[2]), @intFromFloat(rgba[3]), );}
pub fn setPixel(pixels: []zm.Vec, cam: *const Camera, x: usize, y: usize, c: zm.Vec) !void { if (x >= cam.image_width or y >= cam.image_height) return error.OutOfBounds; const i = x + cam.image_width * y; pixels[i] = c; // try cam.setPixel(x, y, vecToRgba(c, cam.samples_per_pixel_v));}