-
Notifications
You must be signed in to change notification settings - Fork 0
/
bvh.h
96 lines (72 loc) · 2.86 KB
/
bvh.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Bounding volume hierarchy
#ifndef BVH_H
#define BVH_H
#include "rtweekend.h"
#include "aabb.h"
#include "hittable.h"
#include "hittable_list.h"
#include <algorithm>
class bvh_node : public hittable {
public:
bvh_node(hittable_list list) : bvh_node(list.objects, 0, list.objects.size()) {
// create implicit copy of the hittable list, modify, persist resulting
// bounding volume hierarchy
}
bvh_node(std::vector<shared_ptr<hittable>>& objects, size_t start, size_t end) {
// the most complicated part is building the structure (construction)
// build bounding box of the span of source objects
bbox = aabb::empty;
for (size_t object_index = start; object_index < end; object_index++)
bbox = aabb(bbox, objects[object_index]->bounding_box());
// split along the longest axis
int axis = bbox.longest_axis();
auto comparator = (axis == 0) ? box_x_compare
: (axis == 1) ? box_y_compare
: box_z_compare;
size_t object_span = end - start;
if (object_span == 1) {
left = right = objects[start];
} else if (object_span == 2) {
left = objects[start];
right = objects[start+1];
} else {
std::sort(objects.begin() + start, objects.begin() + end, comparator);
auto mid = start + object_span/2;
left = make_shared<bvh_node>(objects, start, mid);
right = make_shared<bvh_node>(objects, mid, end);
}
}
bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
if (!bbox.hit(r, ray_t))
return false;
bool hit_left = left->hit(r, ray_t, rec);
// if left hit, only search for intersections in the interval thats closer to the camera than the hit location
// we only care about the closest hit location
bool hit_right = right->hit(r, interval(ray_t.min, hit_left ? rec.t : ray_t.max), rec);
return hit_left || hit_right;
}
aabb bounding_box() const override { return bbox; }
private:
shared_ptr<hittable> left;
shared_ptr<hittable> right;
aabb bbox;
static bool box_compare(
const shared_ptr<hittable> a,
const shared_ptr<hittable> b,
int axis_index
) {
auto a_axis_interval = a->bounding_box().axis_interval(axis_index);
auto b_axis_interval = b->bounding_box().axis_interval(axis_index);
return a_axis_interval.min < b_axis_interval.min;
}
static bool box_x_compare (const shared_ptr<hittable> a, const shared_ptr<hittable> b) {
return box_compare(a, b, 0);
}
static bool box_y_compare (const shared_ptr<hittable> a, const shared_ptr<hittable> b) {
return box_compare(a, b, 1);
}
static bool box_z_compare (const shared_ptr<hittable> a, const shared_ptr<hittable> b) {
return box_compare(a, b, 2);
}
};
#endif