Skip to content

Commit 9996e7c

Browse files
committed
Added Bounding Volume Heirarchies to optimize ray-object intersection
1 parent d419575 commit 9996e7c

File tree

7 files changed

+224
-4
lines changed

7 files changed

+224
-4
lines changed

aabb.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifndef AABBH
2+
#define AABBH
3+
4+
#include "hittable.h"
5+
#include "ray.h"
6+
7+
// Return the min and max for float values
8+
inline float ffmin(float a, float b) { return a < b ? a : b; }
9+
inline float ffmax(float a, float b) { return a > b ? a : b; }
10+
11+
// An AABB is bounded by a vector of min x, min y, min z
12+
// and a vector of max x, max y, max z of all the objects in it
13+
class aabb {
14+
public:
15+
aabb() {}
16+
aabb(const vec3& a, const vec3& b) { _min = a; _max = b;}
17+
18+
vec3 min() const {return _min; }
19+
vec3 max() const {return _max; }
20+
21+
bool hit(const ray& r, float tmin, float tmax) const;
22+
23+
vec3 _min;
24+
vec3 _max;
25+
};
26+
27+
// Check if ray r hits the bouding box
28+
// The t values for the intersection in the x, y, and z axis must
29+
// all overlap for the ray to intersect the box
30+
inline bool aabb::hit(const ray& r, float tmin, float tmax) const {
31+
for (int a = 0; a < 3; a++) {
32+
float invD = 1.0f / r.direction()[a];
33+
float t0 = (min()[a] - r.origin()[a]) * invD;
34+
float t1 = (max()[a] - r.origin()[a]) * invD;
35+
if (invD < 0.0f)
36+
std::swap(t0, t1);
37+
tmin = t0 > tmin ? t0 : tmin;
38+
tmax = t1 < tmax ? t1 : tmax;
39+
if (tmax <= tmin)
40+
return false;
41+
}
42+
return true;
43+
}
44+
45+
// Create an AABB which bounds box0 and box1
46+
aabb surrounding_box(aabb box0, aabb box1) {
47+
vec3 small( ffmin(box0.min().x(), box1.min().x()),
48+
ffmin(box0.min().y(), box1.min().y()),
49+
ffmin(box0.min().z(), box1.min().z()));
50+
vec3 big ( ffmax(box0.max().x(), box1.max().x()),
51+
ffmax(box0.max().y(), box1.max().y()),
52+
ffmax(box0.max().z(), box1.max().z()));
53+
return aabb(small,big);
54+
}
55+
56+
#endif

bvh.h

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#ifndef BVHH
2+
#define BVHH
3+
4+
#include "hittable.h"
5+
#include "random.h"
6+
7+
// A node in the BVH tree
8+
class bvh_node : public hittable {
9+
public:
10+
bvh_node() {}
11+
bvh_node(hittable **l, int n, float time0, float time1);
12+
virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const;
13+
virtual bool bounding_box(float t0, float t1, aabb& box) const;
14+
hittable *left;
15+
hittable *right;
16+
aabb box;
17+
};
18+
19+
// Each node has a corresponding bouding box
20+
bool bvh_node::bounding_box(float t0, float t1, aabb& b) const {
21+
b = box;
22+
return true;
23+
}
24+
25+
// Check whether the ray r hits the left or right child of the bvh_node
26+
bool bvh_node::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {
27+
if (box.hit(r, t_min, t_max)) {
28+
hit_record left_rec, right_rec;
29+
bool hit_left = left->hit(r, t_min, t_max, left_rec);
30+
bool hit_right = right->hit(r, t_min, t_max, right_rec);
31+
if (hit_left && hit_right) {
32+
if (left_rec.t < right_rec.t)
33+
rec = left_rec;
34+
else
35+
rec = right_rec;
36+
return true;
37+
}
38+
else if (hit_left) {
39+
rec = left_rec;
40+
return true;
41+
}
42+
else if (hit_right) {
43+
rec = right_rec;
44+
return true;
45+
}
46+
else
47+
return false;
48+
}
49+
else return false;
50+
}
51+
52+
53+
int box_x_compare (const void * a, const void * b) {
54+
aabb box_left, box_right;
55+
hittable *ah = *(hittable**)a;
56+
hittable *bh = *(hittable**)b;
57+
if(!ah->bounding_box(0,0, box_left) || !bh->bounding_box(0,0, box_right))
58+
std::cerr << "no bounding box in bvh_node constructor\n";
59+
if ( box_left.min().x() - box_right.min().x() < 0.0 )
60+
return -1;
61+
else
62+
return 1;
63+
}
64+
65+
int box_y_compare (const void * a, const void * b)
66+
{
67+
aabb box_left, box_right;
68+
hittable *ah = *(hittable**)a;
69+
hittable *bh = *(hittable**)b;
70+
if(!ah->bounding_box(0,0, box_left) || !bh->bounding_box(0,0, box_right))
71+
std::cerr << "no bounding box in bvh_node constructor\n";
72+
if ( box_left.min().y() - box_right.min().y() < 0.0 )
73+
return -1;
74+
else
75+
return 1;
76+
}
77+
int box_z_compare (const void * a, const void * b)
78+
{
79+
aabb box_left, box_right;
80+
hittable *ah = *(hittable**)a;
81+
hittable *bh = *(hittable**)b;
82+
if(!ah->bounding_box(0,0, box_left) || !bh->bounding_box(0,0, box_right))
83+
std::cerr << "no bounding box in bvh_node constructor\n";
84+
if ( box_left.min().z() - box_right.min().z() < 0.0 )
85+
return -1;
86+
else
87+
return 1;
88+
}
89+
90+
// Construct the bvh node
91+
bvh_node::bvh_node(hittable **l, int n, float time0, float time1) {
92+
int axis = int(3*random_double());
93+
if (axis == 0)
94+
qsort(l, n, sizeof(hittable *), box_x_compare);
95+
else if (axis == 1)
96+
qsort(l, n, sizeof(hittable *), box_y_compare);
97+
else
98+
qsort(l, n, sizeof(hittable *), box_z_compare);
99+
if (n == 1) {
100+
left = right = l[0];
101+
}
102+
else if (n == 2) {
103+
left = l[0];
104+
right = l[1];
105+
}
106+
else {
107+
left = new bvh_node(l, n/2, time0, time1);
108+
right = new bvh_node(l + n/2, n - n/2, time0, time1);
109+
}
110+
aabb box_left, box_right;
111+
if(!left->bounding_box(time0,time1, box_left) || !right->bounding_box(time0,time1, box_right))
112+
std::cerr << "no bounding box in bvh_node constructor\n";
113+
box = surrounding_box(box_left, box_right);
114+
}
115+
116+
#endif

gen-sphere.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ hittable *random_scene() {
8686
int main()
8787
{
8888
// Image is 200x100 pixels
89-
int nx = 800;
90-
int ny = 400;
89+
int nx = 200;
90+
int ny = 100;
9191
// Number of samples
9292
int ns = 100;
9393
// Standard formatting of a .ppm file

hittable.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define HITTABLEH
33

44
#include "ray.h"
5+
#include "aabb.h"
56

67
class material;
78

@@ -22,6 +23,7 @@ class hittable
2223
{
2324
public:
2425
virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const = 0;
26+
virtual bool bounding_box(float t0, float t1, aabb& box) const = 0;
2527
};
2628

2729
#endif

hittable_list.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define HITTABLELISTH
33

44
#include "hittable.h"
5+
#include "aabb.h"
56

67
// Class for list of hitable items
78
class hittable_list : public hittable
@@ -14,6 +15,7 @@ class hittable_list : public hittable
1415
list_size = n;
1516
}
1617
virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const;
18+
virtual bool bounding_box(float t0, float t1, aabb& box) const;
1719
// List of pointers to hitable item pointers
1820
hittable **list;
1921
int list_size;
@@ -40,4 +42,24 @@ bool hittable_list::hit(const ray& r, float t_min, float t_max, hit_record& rec)
4042
return hit_anything;
4143
}
4244

45+
// Create an AABB to bound all items in the list
46+
// t0 and t1 are needed to bound moving objects
47+
bool hittable_list::bounding_box(float t0, float t1, aabb& box) const {
48+
if (list_size < 1) return false;
49+
aabb temp_box;
50+
bool first_true = list[0]->bounding_box(t0, t1, temp_box);
51+
if (!first_true)
52+
return false;
53+
else
54+
box = temp_box;
55+
for (int i = 1; i < list_size; i++) {
56+
if(list[i]->bounding_box(t0, t1, temp_box)) {
57+
box = surrounding_box(box, temp_box);
58+
}
59+
else
60+
return false;
61+
}
62+
return true;
63+
}
64+
4365
#endif

moving_sphere.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define MOVINGSPHEREH
33

44
#include "hittable.h"
5+
#include "aabb.h"
56

67
class moving_sphere: public hittable {
78
public:
@@ -10,7 +11,7 @@ class moving_sphere: public hittable {
1011
: center0(cen0), center1(cen1), time0(t0), time1(t1), radius(r), mat_ptr(m)
1112
{};
1213
virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const;
13-
// virtual bool bounding_box(float t0, float t1, aabb& box) const;
14+
virtual bool bounding_box(float t0, float t1, aabb& box) const;
1415
vec3 center(float time) const;
1516
// Center at time0 and time1
1617
vec3 center0, center1;
@@ -20,12 +21,13 @@ class moving_sphere: public hittable {
2021
material *mat_ptr;
2122
};
2223

23-
// Center at time
24+
// Find where the center of the sphere is at `time`
2425
vec3 moving_sphere::center(float time) const{
2526
return center0 + ((time - time0) / (time1 - time0))*(center1 - center0);
2627
}
2728

2829
// Find the positive solution of the interection of the ray and the sphere
30+
// The position of the center of the sphere depends on the ray's time
2931
bool moving_sphere::hit(
3032
const ray& r, float t_min, float t_max, hit_record& rec) const {
3133
vec3 oc = r.origin() - center(r.time());
@@ -54,4 +56,15 @@ bool moving_sphere::hit(
5456
return false;
5557
}
5658

59+
// Create a static AABB which always bounds the sphere
60+
// at any point in its motion
61+
bool moving_sphere::bounding_box(float t0, float t1, aabb& box) const {
62+
aabb box0(center(t0) - vec3(radius, radius, radius),
63+
center(t0) + vec3(radius, radius, radius));
64+
aabb box1(center(t1) - vec3(radius, radius, radius),
65+
center(t1) + vec3(radius, radius, radius));
66+
box = surrounding_box(box0, box1);
67+
return true;
68+
}
69+
5770
#endif

sphere.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define SPHEREH
33

44
#include "hittable.h"
5+
#include "aabb.h"
56

67
class sphere: public hittable
78
{
@@ -14,6 +15,7 @@ class sphere: public hittable
1415
mat_ptr = m;
1516
}
1617
virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const;
18+
virtual bool bounding_box(float t0, float t1, aabb& box) const;
1719
vec3 center;
1820
float radius;
1921
material *mat_ptr;
@@ -52,4 +54,13 @@ bool sphere::hit(const ray& r, float t_min, float t_max, hit_record& rec) const
5254
return false;
5355
}
5456

57+
// Create an AABB for the sphere
58+
// Since this sphere doesn't move, t0 and t1 aren't required
59+
// They are just part of the function definition
60+
bool sphere::bounding_box(float t0, float t1, aabb& box) const {
61+
box = aabb(center - vec3(radius, radius, radius),
62+
center + vec3(radius, radius, radius));
63+
return true;
64+
}
65+
5566
#endif

0 commit comments

Comments
 (0)