this repo has no description
1const std = @import("std");
2
3const spall = @import("spall");
4const zigimg = @import("zigimg");
5const zm = @import("zmath");
6
7const BVH = @import("BVH.zig");
8const Camera = @import("Camera.zig");
9const hittable = @import("hittable.zig");
10const material = @import("material.zig");
11const Ray = @import("Ray.zig");
12const util = @import("util.zig");
13
14const interval = @import("interval.zig");
15const IntervalUsize = interval.IntervalUsize;
16const IntervalF32 = interval.IntervalF32;
17
18const log = std.log.scoped(.tracer);
19
20pub const Context = struct {
21 pixels: []zm.Vec,
22 cam: *const Camera,
23 world: *const BVH,
24 height: IntervalUsize,
25 width: IntervalUsize,
26};
27
28const white = zm.f32x4s(1.0);
29const black = zm.f32x4(0, 0, 0, 1.0);
30
31pub fn rayColor(r: *Ray, world: *const BVH, depth: usize) zm.Vec {
32 @setFloatMode(.optimized);
33 if (depth == 0) return backgroundColor(r);
34
35 if (world.hit(r, .{ .min = 0.001, .max = std.math.inf(f32) })) |rec| {
36 var attenuation = zm.f32x4s(1.0);
37 if (rec.mat.scatter(r, &rec, &attenuation)) |new_r| {
38 return attenuation * rayColor(@constCast(&new_r), world, depth - 1);
39 }
40 }
41
42 return backgroundColor(r);
43}
44
45fn backgroundColor(r: *Ray) zm.Vec {
46 const unit_direction = zm.normalize3(r.dir);
47 const a = 0.5 * (unit_direction[1] + 1.0);
48 return zm.f32x4s(1.0 - a) * zm.f32x4s(1.0) + zm.f32x4s(a) * zm.f32x4(0.5, 0.7, 1.0, 1.0);
49}
50
51pub fn trace(ctx: *Context) void {
52 var height_iter = ctx.height.iter();
53 while (height_iter.nextInc()) |j| {
54 if (j >= ctx.cam.image_height) break;
55
56 var width_iter = ctx.width.iter();
57 while (width_iter.nextExc()) |i| inner: {
58 var col = zm.f32x4(0.0, 0.0, 0.0, 1.0);
59
60 for (0..ctx.cam.samples_per_pixel) |_| {
61 var ray = ctx.cam.getRay(i, j);
62 col += rayColor(&ray, ctx.world, ctx.cam.max_depth);
63 }
64
65 setPixel(ctx.pixels, ctx.cam, i, j, col) catch {
66 log.err("Trying to set a pixel out of bounds ({}, {})", .{ i, j });
67 break :inner;
68 };
69 }
70 }
71}
72
73const zero = zm.f32x4s(0.0);
74const nearly_one = zm.f32x4s(0.999);
75const v256 = zm.f32x4s(256);
76
77inline fn vecToRgba(v: zm.Vec, samples_per_pixel: zm.Vec) zigimg.color.Rgba32 {
78 const rgba = zm.clampFast(
79 @sqrt(v / samples_per_pixel),
80 zero,
81 nearly_one,
82 ) * v256; // linear to gamma
83
84 return zigimg.color.Rgba32.initRgba(
85 @intFromFloat(rgba[0]),
86 @intFromFloat(rgba[1]),
87 @intFromFloat(rgba[2]),
88 @intFromFloat(rgba[3]),
89 );
90}
91
92pub fn setPixel(pixels: []zm.Vec, cam: *const Camera, x: usize, y: usize, c: zm.Vec) !void {
93 if (x >= cam.image_width or y >= cam.image_height) return error.OutOfBounds;
94 const i = x + cam.image_width * y;
95 pixels[i] = c;
96 // try cam.setPixel(x, y, vecToRgba(c, cam.samples_per_pixel_v));
97}