tangled
alpha
login
or
join now
altagos.dev
/
rayray
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
pulls
pipelines
bvh works but not completly
altagos.dev
2 years ago
4d6fe1d1
3615ebf3
+149
-88
6 changed files
expand all
collapse all
unified
split
build.zig.zon
src
hittable
BVH.zig
hittable.zig
rayray.zig
scences
in_one_weekend.zig
tracer.zig
+2
-2
build.zig.zon
···
17
17
.hash = "1220753b2f9e7c4f3fb6cdc8fc275cc9073904ea7032a1f5596aa776a857de69f72c",
18
18
},
19
19
.zigimg = .{
20
20
-
.url = "git+https://github.com/MidlightStudio/zigimg#29d34702995a7e84e097004e87ede905cdb674dd",
21
21
-
.hash = "12206b669a4712ff9c06d4111a650f298d7597dd39f9d4853858d7f298c819353a65",
20
20
+
.url = "git+https://github.com/MidlightStudio/zigimg#637974e2d31dcdbc33f1e9cc8ffb2e46abd2e215",
21
21
+
.hash = "122012026c3a65ff1d4acba3b3fe80785f7cee9c6b4cdaff7ed0fbf23b0a6c803989",
22
22
},
23
23
},
24
24
.paths = .{
+11
-15
src/hittable.zig
···
25
25
};
26
26
27
27
pub const Hittable = union(enum) {
28
28
-
sphere: Sphere,
29
29
-
bvh_node: BVH,
28
28
+
sphere: struct {Sphere, []const u8},
30
29
31
31
-
pub fn sphere(s: Sphere) Hittable {
30
30
+
pub fn sphere(name: []const u8, s: Sphere) Hittable {
32
31
// std.log.info("created sphere with mat: {}", .{s.mat});
33
33
-
return .{ .sphere = s };
32
32
+
return .{ .sphere = .{ s, name }};
34
33
}
35
34
36
36
-
pub fn bvh(b: BVH) Hittable {
37
37
-
return .{ .bvh_node = b };
35
35
+
pub fn boundingBox(self: *Hittable) AABB {
36
36
+
switch (self.*) {
37
37
+
.sphere => |*s| return s[0].boundingBox(),
38
38
+
}
38
39
}
39
40
40
40
-
pub fn boundingBox(self: *Hittable) AABB {
41
41
+
pub fn getName(self: *Hittable) []const u8 {
41
42
switch (self.*) {
42
42
-
.sphere => |*s| return s.boundingBox(),
43
43
-
.bvh_node => |*s| return s.boundingBox(),
43
43
+
.sphere => |*s| return s[1],
44
44
}
45
45
}
46
46
47
47
pub fn hit(self: *Hittable, r: *Ray, ray_t: IntervalF32) ?HitRecord {
48
48
switch (self.*) {
49
49
.sphere => |*s| {
50
50
-
std.log.debug("try to hit Sphere: {}", .{s});
50
50
+
// std.log.debug("try to hit Sphere: {}", .{s});
51
51
// std.log.info("hitting sphere with mat: {}", .{s.mat});
52
52
-
return s.hit(r, ray_t);
53
53
-
},
54
54
-
.bvh_node => |*s| {
55
55
-
// std.log.debug("try to hit BVH", .{});
56
56
-
return s.hit(r, ray_t);
52
52
+
return s[0].hit(r, ray_t);
57
53
},
58
54
}
59
55
+124
-57
src/hittable/BVH.zig
···
10
10
11
11
pub const BVH = @This();
12
12
13
13
-
objects: *hittable.HittableList,
14
14
-
left: *Hittable,
15
15
-
right: *Hittable,
16
16
-
bbox: AABB,
13
13
+
const Node = struct {
14
14
+
left: ?*Node = null,
15
15
+
right: ?*Node = null,
16
16
+
bbox: AABB = AABB{},
17
17
+
hittable: ?Hittable = null,
18
18
+
19
19
+
// pub fn add(self: *Node, allocator: std.mem.Allocator, object: *Hittable) void {}
20
20
+
//
21
21
+
pub fn init(
22
22
+
self: *Node,
23
23
+
allocator: std.mem.Allocator,
24
24
+
objects: []hittable.Hittable,
25
25
+
// start: usize,
26
26
+
// end: usize,
27
27
+
) !void {
28
28
+
for (0..objects.len) |idx| {
29
29
+
self.bbox = AABB.initAB(&self.bbox, &objects[idx].boundingBox());
30
30
+
}
31
31
+
32
32
+
const axis = self.bbox.longestAxis();
33
33
+
const object_span = objects.len;
34
34
+
35
35
+
if (object_span == 1) {
36
36
+
self.hittable = objects[0];
37
37
+
// std.log.info("Node.hittable = .{?}", .{self.hittable});
38
38
+
return;
39
39
+
}
40
40
+
41
41
+
var left = try allocator.create(Node);
42
42
+
var right = try allocator.create(Node);
43
43
+
44
44
+
// if (object_span == 2) {
45
45
+
// try left.init(allocator, objects, start, start + 1);
46
46
+
// try right.init(allocator, objects, start + 1, start + 2);
47
47
+
// } else
48
48
+
if (object_span >= 2) {
49
49
+
// std.log.debug("Node.init axis={} start={} end={}", .{ axis, start, end });
50
50
+
if (axis == 0) {
51
51
+
// break :blk&boxXCompare;
52
52
+
std.mem.sort(Hittable, objects, .{}, boxXCompare);
53
53
+
} else if (axis == 1) {
54
54
+
// break :blk &boxYCompare;
55
55
+
std.mem.sort(Hittable, objects, .{}, boxYCompare);
56
56
+
} else {
57
57
+
// break :blk &boxZCompare;
58
58
+
std.mem.sort(Hittable, objects, .{}, boxZCompare);
59
59
+
}
60
60
+
// std.mem.sort(Hittable, list, null, comparator);
61
61
+
62
62
+
const mid = object_span / 2;
63
63
+
try left.init(allocator, objects[0..mid]);
64
64
+
try right.init(allocator, objects[mid..]);
65
65
+
}
66
66
+
67
67
+
self.left = left;
68
68
+
self.right = right;
17
69
18
18
-
pub fn initL(objects: *hittable.HittableList) BVH {
19
19
-
std.log.info("starting to create BVH", .{});
20
20
-
return BVH.init(objects, 0, objects.list.items.len);
21
21
-
}
70
70
+
// std.log.info("Node created", .{});
71
71
+
}
22
72
23
23
-
pub fn init(objects: *hittable.HittableList, start: usize, end: usize) BVH {
24
24
-
const list = objects.list.items;
25
25
-
var bbox = AABB{};
26
26
-
for (start..end) |idx| {
27
27
-
bbox = AABB.initAB(&bbox, &list[idx].boundingBox());
73
73
+
pub fn deinit(self: *Node, allocator: std.mem.Allocator) void {
74
74
+
if (self.left) |l| {
75
75
+
l.deinit(allocator);
76
76
+
allocator.destroy(l);
77
77
+
}
78
78
+
if (self.right) |r| {
79
79
+
r.deinit(allocator);
80
80
+
allocator.destroy(r);
81
81
+
}
28
82
}
29
83
30
30
-
const axis = bbox.longestAxis();
84
84
+
pub fn hit(self: *Node, r: *Ray, ray_t: IntervalF32) ?HitRecord {
85
85
+
if (!self.bbox.hit(r, ray_t)) {
86
86
+
return null;
87
87
+
}
88
88
+
89
89
+
if (self.hittable) |object| {
90
90
+
return @constCast(&object).hit(r, ray_t);
91
91
+
}
92
92
+
93
93
+
if (self.left) |left| {
94
94
+
if (left.hit(r, ray_t)) |rec| {
95
95
+
return rec;
96
96
+
}
97
97
+
}
31
98
32
32
-
// const comparator = blk: {
33
33
-
// if (axis == 0) {
34
34
-
// break :blk &boxXCompare;
35
35
-
// } else if (axis == 1) {
36
36
-
// break :blk &boxYCompare;
37
37
-
// }
38
38
-
// break :blk &boxZCompare;
39
39
-
// };
99
99
+
if (self.right) |right| {
100
100
+
if (right.hit(r, ray_t)) |rec| {
101
101
+
return rec;
102
102
+
}
103
103
+
}
104
104
+
105
105
+
return null;
106
106
+
}
40
107
41
41
-
const object_span = end - start;
108
108
+
pub fn print(self: *Node, depth: usize, side: u8) void {
109
109
+
for (0..depth) |_| std.debug.print(" ", .{});
42
110
43
43
-
var left = &list[start];
44
44
-
var right = &list[start];
45
45
-
if (object_span == 2) {
46
46
-
left = &list[start];
47
47
-
right = &list[start + 1];
48
48
-
} else if (object_span > 2) {
49
49
-
std.log.debug("BVH.init axis={} start={} end={}", .{axis, start, end});
50
50
-
if (axis == 0) {
51
51
-
// break :blk&boxXCompare;
52
52
-
std.mem.sort(Hittable, list, .{}, boxXCompare);
53
53
-
} else if (axis == 1) {
54
54
-
// break :blk &boxYCompare;
55
55
-
std.mem.sort(Hittable, list, .{}, boxYCompare);
56
56
-
} else {
57
57
-
// break :blk &boxZCompare;
58
58
-
std.mem.sort(Hittable, list, .{}, boxZCompare);
111
111
+
if (side == 1) {
112
112
+
std.debug.print("Left = ", .{});
113
113
+
} else if (side >= 2) {
114
114
+
std.debug.print("Right = ", .{});
59
115
}
60
60
-
// std.mem.sort(Hittable, list, null, comparator);
61
116
62
62
-
const mid = start + object_span / 2;
63
63
-
left = @constCast(&Hittable.bvh(BVH.init(objects, start, mid)));
64
64
-
right = @constCast(&Hittable.bvh(BVH.init(objects, mid, end)));
117
117
+
const has_hit = if (self.hittable) |h| @constCast(&h).getName() else "Ast";
118
118
+
std.debug.print("Node hittable={s}\n", .{has_hit});
119
119
+
120
120
+
if (self.left) |left| left.print(depth + 1, 1);
121
121
+
if (self.right) |right| right.print(depth + 1, 2);
65
122
}
123
123
+
};
124
124
+
125
125
+
allocator: std.mem.Allocator,
126
126
+
// objects: hittable.HittableList,
127
127
+
root: Node,
66
128
67
67
-
std.log.info("BVH created", .{});
129
129
+
pub fn init(allocator: std.mem.Allocator, objects: hittable.HittableList) !BVH {
130
130
+
std.log.info("Creating BVH Tree with {} objects", .{objects.list.items.len});
131
131
+
// return BVH.init(objects, 0, objects.list.items.len);
132
132
+
var root = Node{};
133
133
+
try root.init(allocator, objects.list.items);
134
134
+
defer @constCast(&objects).deinit();
135
135
+
136
136
+
root.print(0, 0);
68
137
69
138
return .{
70
70
-
.objects = objects,
71
71
-
.left = left,
72
72
-
.right = right,
73
73
-
.bbox = bbox,
139
139
+
.allocator = allocator,
140
140
+
// .objects = objects,
141
141
+
.root = root,
74
142
};
75
143
}
76
144
77
77
-
pub fn hit(self: *BVH, r: *Ray, ray_t: IntervalF32) ?HitRecord {
78
78
-
if (!self.bbox.hit(r, ray_t)) {
79
79
-
return null;
80
80
-
}
145
145
+
pub fn deinit(self: *BVH) void {
146
146
+
self.root.deinit(self.allocator);
147
147
+
// self.objects.deinit();
148
148
+
}
81
149
82
82
-
if (self.left.hit(r, ray_t)) |rec| return rec;
83
83
-
if (self.right.hit(r, ray_t)) |rec| return rec;
84
84
-
return null;
150
150
+
pub fn hit(self: *BVH, r: *Ray, ray_t: IntervalF32) ?HitRecord {
151
151
+
return self.root.hit(r, ray_t);
85
152
}
86
153
87
154
pub fn boundingBox(self: *BVH) AABB {
88
88
-
return self.bbox;
155
155
+
return self.root.bbox;
89
156
}
90
157
91
158
fn boxCompare(a: *Hittable, b: *Hittable, axis_index: i32) bool {
92
159
const a_axis_interval = a.boundingBox().axisInterval(axis_index);
93
160
const b_axis_interval = b.boundingBox().axisInterval(axis_index);
94
94
-
return a_axis_interval.min < b_axis_interval.min;
161
161
+
return a_axis_interval.min > b_axis_interval.min;
95
162
}
96
163
97
164
fn boxXCompare(_: @TypeOf(.{}), a: Hittable, b: Hittable) bool {
+2
-2
src/rayray.zig
···
25
25
thread_pool: *std.Thread.Pool,
26
26
27
27
camera: Camera,
28
28
-
world: hittable.HittableList,
28
28
+
world: hittable.BVH,
29
29
30
30
pub fn init(allocator: std.mem.Allocator, world: hittable.HittableList, camera_opts: Camera.Options) !Self {
31
31
var thread_pool = try allocator.create(std.Thread.Pool);
···
35
35
.allocator = allocator,
36
36
.thread_pool = thread_pool,
37
37
.camera = try Camera.init(allocator, camera_opts),
38
38
-
.world = world,
38
38
+
.world = try hittable.BVH.init(allocator, world),
39
39
};
40
40
}
41
41
+8
-10
src/scences/in_one_weekend.zig
···
17
17
18
18
const material_ground = try allocator.create(Material);
19
19
material_ground.* = Material.lambertian(zm.f32x4(0.5, 0.5, 0.5, 1.0));
20
20
-
try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, -1000, 0, 0), .radius = 1000, .mat = material_ground }));
20
20
+
try world.add(Hittable.sphere("Ground", Sphere{ .center = zm.f32x4(0, -1000, 0, 0), .radius = 1000, .mat = material_ground }));
21
21
22
22
var a: isize = -11;
23
23
while (a < 11) : (a += 1) {
···
38
38
// diffuse
39
39
const albedo = rayray.util.randomVec3() * rayray.util.randomVec3() + zm.f32x4(0, 0, 0, 1);
40
40
material.* = Material.lambertian(albedo);
41
41
-
try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material }));
41
41
+
try world.add(Hittable.sphere("Lambertian", Sphere{ .center = center, .radius = 0.2, .mat = material }));
42
42
} else if (choose_mat < 0.95) {
43
43
// metal
44
44
const albedo = rayray.util.randomVec3M(0.5, 1) + zm.f32x4(0, 0, 0, 1);
45
45
const fuzz = rayray.util.randomF32M(0, 0.5);
46
46
material.* = Material.metal(albedo, fuzz);
47
47
-
try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material }));
47
47
+
try world.add(Hittable.sphere("Metal", Sphere{ .center = center, .radius = 0.2, .mat = material }));
48
48
} else {
49
49
// glass
50
50
material.* = Material.dielectric(1.5);
51
51
-
try world.add(Hittable.sphere(Sphere{ .center = center, .radius = 0.2, .mat = material }));
51
51
+
try world.add(Hittable.sphere("Dielectric", Sphere{ .center = center, .radius = 0.2, .mat = material }));
52
52
}
53
53
}
54
54
}
···
56
56
57
57
const material1 = try allocator.create(Material);
58
58
material1.* = Material.dielectric(1.5);
59
59
-
try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, 1, 0, 0), .radius = 1, .mat = material1 }));
59
59
+
try world.add(Hittable.sphere("One", Sphere{ .center = zm.f32x4(0, 1, 0, 0), .radius = 1, .mat = material1 }));
60
60
61
61
const material2 = try allocator.create(Material);
62
62
material2.* = Material.lambertian(zm.f32x4(0.4, 0.2, 0.1, 1));
63
63
-
try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(-4, 1, 0, 0), .radius = 1, .mat = material2 }));
63
63
+
try world.add(Hittable.sphere("Two", Sphere{ .center = zm.f32x4(-4, 1, 0, 0), .radius = 1, .mat = material2 }));
64
64
65
65
const material3 = try allocator.create(Material);
66
66
material3.* = Material.metal(zm.f32x4(0.7, 0.6, 0.5, 1), 0);
67
67
-
try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(4, 1, 0, 0), .radius = 1, .mat = material3 }));
67
67
+
try world.add(Hittable.sphere("Three", Sphere{ .center = zm.f32x4(4, 1, 0, 0), .radius = 1, .mat = material3 }));
68
68
69
69
-
var world2 = HittableList.init(allocator);
70
70
-
try world2.add(Hittable.bvh(BVH.initL(&world)));
71
71
-
return .{ .allocator = allocator, .world = world2 };
69
69
+
return .{ .allocator = allocator, .world = world };
72
70
}
73
71
74
72
pub fn deinit(self: *@This()) void {
+2
-2
src/tracer.zig
···
18
18
19
19
pub const Context = struct {
20
20
cam: *Camera,
21
21
-
world: *hittable.HittableList,
21
21
+
world: *hittable.BVH,
22
22
height: IntervalUsize,
23
23
width: IntervalUsize,
24
24
};
25
25
26
26
-
pub fn rayColor(r: *Ray, world: *hittable.HittableList, depth: usize) zm.Vec {
26
26
+
pub fn rayColor(r: *Ray, world: *hittable.BVH, depth: usize) zm.Vec {
27
27
if (depth <= 0) return zm.f32x4(0, 0, 0, 1.0);
28
28
29
29
if (world.hit(r, .{ .min = 0.001, .max = std.math.inf(f32) })) |rec| {