tangled
alpha
login
or
join now
altagos.dev
/
rayray
this repo has no description
0
fork
atom
overview
issues
pulls
pipelines
added world
altagos.dev
2 years ago
9763abcd
044c78d3
+143
-13
7 changed files
expand all
collapse all
unified
split
build.zig
src
camera.zig
hittable
sphere.zig
hittable.zig
main.zig
ray.zig
rayray.zig
+1
build.zig
···
24
.target = target,
25
.optimize = optimize,
26
});
0
27
exe.root_module.addImport("spall", spall.module("spall"));
28
exe.root_module.addImport("rayray", rayray);
29
···
24
.target = target,
25
.optimize = optimize,
26
});
27
+
addDeps(b, &exe.root_module);
28
exe.root_module.addImport("spall", spall.module("spall"));
29
exe.root_module.addImport("rayray", rayray);
30
+4
src/camera.zig
···
72
};
73
}
74
0
0
0
0
75
pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void {
76
if (x >= self.image_width or y >= self.image_height) return error.OutOfBounds;
77
const i = x + self.image_width * y;
···
72
};
73
}
74
75
+
pub fn deinit(self: *Camera) void {
76
+
self.image.deinit();
77
+
}
78
+
79
pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void {
80
if (x >= self.image_width or y >= self.image_height) return error.OutOfBounds;
81
const i = x + self.image_width * y;
+74
src/hittable.zig
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
const std = @import("std");
2
+
3
+
const zm = @import("zmath");
4
+
5
+
const Ray = @import("ray.zig");
6
+
pub const Sphere = @import("hittable/sphere.zig");
7
+
8
+
pub const HitRecord = struct {
9
+
p: zm.Vec,
10
+
normal: zm.Vec = zm.f32x4s(1.0),
11
+
t: f32,
12
+
front_face: bool = true,
13
+
14
+
pub fn setFaceNormal(self: *HitRecord, r: *Ray, outward_normal: zm.Vec) void {
15
+
self.front_face = zm.dot3(r.dir, outward_normal)[0] < 0.0;
16
+
self.normal = if (self.front_face) outward_normal else -outward_normal;
17
+
}
18
+
};
19
+
20
+
pub const HittableType = enum {
21
+
sphere,
22
+
};
23
+
24
+
pub const Hittable = union(HittableType) {
25
+
sphere: Sphere,
26
+
27
+
pub fn initSphere(sphere: Sphere) Hittable {
28
+
return .{ .sphere = sphere };
29
+
}
30
+
31
+
pub fn hit(self: *Hittable, r: *Ray, ray_tmin: f32, ray_tmax: f32) ?HitRecord {
32
+
switch (self.*) {
33
+
.sphere => |*sphere| {
34
+
return sphere.hit(r, ray_tmin, ray_tmax);
35
+
},
36
+
}
37
+
38
+
return null;
39
+
}
40
+
};
41
+
42
+
pub const HittableList = struct {
43
+
list: std.ArrayList(Hittable),
44
+
45
+
pub fn init(allocator: std.mem.Allocator) HittableList {
46
+
const list = std.ArrayList(Hittable).init(allocator);
47
+
48
+
return .{ .list = list };
49
+
}
50
+
51
+
pub fn deinit(self: *HittableList) void {
52
+
self.list.deinit();
53
+
}
54
+
55
+
pub fn add(self: *HittableList, item: Hittable) !void {
56
+
try self.list.append(item);
57
+
}
58
+
59
+
pub fn hit(self: *HittableList, r: *Ray, ray_tmin: f32, ray_tmax: f32) ?HitRecord {
60
+
var rec: ?HitRecord = null;
61
+
var hit_anything = false;
62
+
var closest_so_far = ray_tmax;
63
+
64
+
for (self.list.items) |*object| {
65
+
if (object.hit(r, ray_tmin, closest_so_far)) |new_rec| {
66
+
rec = new_rec;
67
+
hit_anything = true;
68
+
closest_so_far = new_rec.t;
69
+
}
70
+
}
71
+
72
+
return rec;
73
+
}
74
+
};
+38
src/hittable/sphere.zig
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
const zm = @import("zmath");
2
+
3
+
const Ray = @import("../ray.zig");
4
+
const HitRecord = @import("../hittable.zig").HitRecord;
5
+
6
+
const Sphere = @This();
7
+
8
+
center: zm.Vec,
9
+
radius: f32,
10
+
11
+
pub fn hit(self: *Sphere, r: *Ray, ray_tmin: f32, ray_tmax: f32) ?HitRecord {
12
+
const oc = r.orig - self.center;
13
+
const a = zm.lengthSq3(r.dir)[0];
14
+
const half_b = zm.dot3(oc, r.dir)[0];
15
+
const c = zm.dot3(oc, oc)[0] - self.radius * self.radius;
16
+
17
+
const discriminant = half_b * half_b - a * c;
18
+
if (discriminant < 0) return null;
19
+
20
+
const sqrtd = @sqrt(discriminant);
21
+
22
+
// Find the nearest root that lies in the acceptable range
23
+
var root = (-half_b - sqrtd) / a;
24
+
if (root <= ray_tmin or ray_tmax <= root) {
25
+
root = (-half_b + sqrtd) / a;
26
+
if (root <= ray_tmin or ray_tmax <= root) return null;
27
+
}
28
+
29
+
var rec = HitRecord{
30
+
.t = root,
31
+
.p = r.at(root),
32
+
};
33
+
34
+
const outward_normal = (rec.p - self.center) / zm.f32x4s(self.radius);
35
+
rec.setFaceNormal(r, outward_normal);
36
+
37
+
return rec;
38
+
}
+10
-2
src/main.zig
···
2
3
const a = @import("a");
4
const spall = @import("spall");
0
5
6
-
const Raytracer = @import("rayray").Raytracer;
0
0
0
7
8
pub const std_options = .{
9
.log_level = .debug,
···
21
spall.init_thread();
22
defer spall.deinit_thread();
23
0
0
0
0
24
const s = spall.trace(@src(), "Main", .{});
25
26
-
var raytracer = try Raytracer.init(allocator);
27
defer raytracer.deinit();
28
29
const img = try raytracer.render();
···
2
3
const a = @import("a");
4
const spall = @import("spall");
5
+
const zm = @import("zmath");
6
7
+
const rayray = @import("rayray");
8
+
const Hittable = rayray.hittable.Hittable;
9
+
const HittableList = rayray.hittable.HittableList;
10
+
const Sphere = rayray.hittable.Sphere;
11
12
pub const std_options = .{
13
.log_level = .debug,
···
25
spall.init_thread();
26
defer spall.deinit_thread();
27
28
+
var world = HittableList.init(allocator);
29
+
try world.add(Hittable.initSphere(Sphere{ .center = zm.f32x4(0, 0, -1, 0), .radius = 0.5 }));
30
+
try world.add(Hittable.initSphere(Sphere{ .center = zm.f32x4(0, -100.5, -1, 0), .radius = 100 }));
31
+
32
const s = spall.trace(@src(), "Main", .{});
33
34
+
var raytracer = try rayray.Raytracer.init(allocator, world);
35
defer raytracer.deinit();
36
37
const img = try raytracer.render();
+6
-5
src/ray.zig
···
0
0
1
const zm = @import("zmath");
2
0
3
const Ray = @This();
4
5
orig: zm.Vec,
···
16
return self.orig + zm.f32x4s(t) * self.dir;
17
}
18
19
-
pub fn color(r: *Ray) zm.Vec {
20
-
const t = hitSphere(zm.f32x4(0, 0, -1, 0), 0.5, r);
21
-
if (t > 0.0) {
22
-
const N = zm.normalize3(r.at(t) - zm.f32x4(0, 0, -1, 0));
23
-
return zm.f32x4s(0.5) * zm.f32x4(N[0] + 1, N[1] + 1, N[2] + 1, 1);
24
}
25
26
const unit_direction = zm.normalize3(r.dir);
···
1
+
const std = @import("std");
2
+
3
const zm = @import("zmath");
4
5
+
const hittable = @import("hittable.zig");
6
const Ray = @This();
7
8
orig: zm.Vec,
···
19
return self.orig + zm.f32x4s(t) * self.dir;
20
}
21
22
+
pub fn color(r: *Ray, world: *hittable.HittableList) zm.Vec {
23
+
if (world.hit(r, 0, std.math.inf(f32))) |rec| {
24
+
return zm.f32x4s(0.5) * (rec.normal + zm.f32x4(1, 1, 1, 1));
0
0
25
}
26
27
const unit_direction = zm.normalize3(r.dir);
+10
-6
src/rayray.zig
···
6
const zm = @import("zmath");
7
8
const Camera = @import("camera.zig");
0
9
const Ray = @import("ray.zig");
10
11
const log = std.log.scoped(.rayray);
···
16
allocator: std.mem.Allocator,
17
18
camera: Camera,
0
19
20
-
pub fn init(allocator: std.mem.Allocator) !Self {
21
return .{
22
.allocator = allocator,
23
.camera = try Camera.init(allocator, 400, 16.0 / 9.0),
0
24
};
25
}
26
27
-
pub fn deinit(self: *const Self) void {
28
-
_ = self;
0
29
}
30
31
// TODO: Render in cubes not in rows
···
50
const finished_threads = try self.allocator.alloc(bool, num_threads);
51
52
for (0..num_threads) |row| {
53
-
const t = try std.Thread.spawn(.{}, render_thread, .{ &self.camera, row, row_height, &threads[row].done });
54
threads[row].thread = t;
55
}
56
···
85
return self.camera.image;
86
}
87
88
-
fn render_thread(cam: *Camera, row: usize, height: usize, done: *bool) void {
89
spall.init_thread();
90
defer spall.deinit_thread();
91
···
102
const pixel_center = cam.pixel00_loc + (zm.f32x4s(@as(f32, @floatFromInt(i))) * cam.pixel_delta_u) + (zm.f32x4s(@as(f32, @floatFromInt(j))) * cam.pixel_delta_v);
103
const ray_direction = pixel_center - cam.camera_center;
104
var ray = Ray.init(cam.camera_center, ray_direction);
105
-
const col = vecToRgba(ray.color());
106
107
cam.setPixel(i, j, col) catch break;
108
}
···
6
const zm = @import("zmath");
7
8
const Camera = @import("camera.zig");
9
+
pub const hittable = @import("hittable.zig");
10
const Ray = @import("ray.zig");
11
12
const log = std.log.scoped(.rayray);
···
17
allocator: std.mem.Allocator,
18
19
camera: Camera,
20
+
world: hittable.HittableList,
21
22
+
pub fn init(allocator: std.mem.Allocator, world: hittable.HittableList) !Self {
23
return .{
24
.allocator = allocator,
25
.camera = try Camera.init(allocator, 400, 16.0 / 9.0),
26
+
.world = world,
27
};
28
}
29
30
+
pub fn deinit(self: *Self) void {
31
+
self.camera.deinit();
32
+
self.world.deinit();
33
}
34
35
// TODO: Render in cubes not in rows
···
54
const finished_threads = try self.allocator.alloc(bool, num_threads);
55
56
for (0..num_threads) |row| {
57
+
const t = try std.Thread.spawn(.{}, render_thread, .{ &self.camera, &self.world, row, row_height, &threads[row].done });
58
threads[row].thread = t;
59
}
60
···
89
return self.camera.image;
90
}
91
92
+
fn render_thread(cam: *Camera, world: *hittable.HittableList, row: usize, height: usize, done: *bool) void {
93
spall.init_thread();
94
defer spall.deinit_thread();
95
···
106
const pixel_center = cam.pixel00_loc + (zm.f32x4s(@as(f32, @floatFromInt(i))) * cam.pixel_delta_u) + (zm.f32x4s(@as(f32, @floatFromInt(j))) * cam.pixel_delta_v);
107
const ray_direction = pixel_center - cam.camera_center;
108
var ray = Ray.init(cam.camera_center, ray_direction);
109
+
const col = vecToRgba(ray.color(world));
110
111
cam.setPixel(i, j, col) catch break;
112
}