1 #ifndef __BVH_TREE_H_INCLUDED
2 #define __BVH_TREE_H_INCLUDED
3
4 #include "Box.hxx"
5
6 class BVH
7 {
8 // A BVH node (template)
9 struct Node
10 {
11 Box bbox;
12
13 //Note: the result is stored in ray! (in ray.t and ray.hit)
14 virtual void traverse(Ray &ray) = 0;
15
16 virtual ~Node(){};
17 };
18
19 // This node stores only superior bounding boxes, but no primitives
20 struct InnerNode : public Node
21 {
22 Node *leftChild, *rightChild;
23
24 InnerNode(const Box& aBBox)
25 {
26 bbox = aBBox;
27 }
28
29 // Traverses the ray and sets hit and t accordingly
30 virtual void traverse(Ray &ray)
31 {
32 std::pair<float, float> leftPair = leftChild->bbox.Intersect(ray),
33 rightPair = rightChild->bbox.Intersect(ray);
34
35 if (leftPair.first < rightPair.first)
36 {
37 // Left is near
38 if (leftPair.first < FLT_MAX)
39 leftChild->traverse(ray);
40
41 if (rightPair.first < FLT_MAX && (!ray.hit || ray.t > rightPair.first))
42 rightChild->traverse(ray);
43 }
44 else
45 {
46 // Right is near
47 if (rightPair.first < FLT_MAX)
48 rightChild->traverse(ray);
49
50 if (leftPair.first < FLT_MAX && (!ray.hit || ray.t > leftPair.first))
51 leftChild->traverse(ray);
52 }
53 }
54
55 virtual ~InnerNode() {}
56 };
57
58 // This node stores a vector of primitives
59 struct LeafNode : public Node
60 {
61 vector<Primitive *> primitive;
62
63 LeafNode(const Box& aBBox, vector<Primitive *> &prim)
64 {
65 bbox = aBBox;
66 primitive = prim;
67 }
68
69 // Intersects with all included primitives
70 virtual void traverse(Ray &ray)
71 {
72 for (vector<Primitive *>::iterator it = primitive.begin(); it != primitive.end(); ++it)
73 (*it)->Intersect(ray);
74 }
75
76 virtual ~LeafNode() {}
77 };
78
79 public:
80 int maxDepth, minTri;
81
82 // In this exercise, we use the median instead of halving the distance in each step, because
83 // this balances the tree further, which increases rendering speed (as the bounding boxes are
84 // shrinked to minimal size, which eliminates most of the problems described in lecture)
85 Node *BuildTree(Box &bounds, vector<Primitive *> prim, int depth = 0)
86 {
87 if (static_cast<int>(prim.size()) <= minTri || depth >= maxDepth)
88 {
89 // Generate a voxel
90 return new LeafNode(bounds, prim);
91 }
92 else
93 {
94 // Generate inner node
95 Vec3f sum(0);
96 Vec3f minimum(Infinity),
97 maximum(-Infinity),
98 elongation;
99 Box box;
100
101 InnerNode *thisnode = new InnerNode(bounds);
102
103 for (vector<Primitive *>::iterator it = prim.begin(); it != prim.end(); ++it)
104 {
105 box = (*it)->CalcBounds();
106
107 // Median calculation
108 sum += box.max + box.min;
109
110 // Investgation of greatest elongation
111 minimum.SetMin(box.min);
112 maximum.SetMax(box.max);
113 }
114
115 Vec3f median = sum / static_cast<float>(prim.size());
116
117 vector<Primitive *> leftPrim,
118 rightPrim;
119
120 Box leftBox, rightBox;
121
122 // Determine elongation
123 elongation = maximum - minimum;
124
125 if (elongation.x > elongation.y && elongation.x > elongation.z)
126 {
127 // Divide in x
128 for (vector<Primitive *>::iterator it = prim.begin(); it != prim.end(); ++it)
129 {
130 box = (*it)->CalcBounds();
131 if (box.max.x + box.min.x < median.x)
132 {
133 leftPrim.push_back(*it);
134 leftBox.Extend(box.max);
135 leftBox.Extend(box.min);
136 }
137 else
138 {
139 rightPrim.push_back(*it);
140 rightBox.Extend(box.max);
141 rightBox.Extend(box.min);
142 }
143 }
144 }
145 else if (elongation.y > elongation.x && elongation.y > elongation.z)
146 {
147 // Divide in y
148 for (vector<Primitive *>::iterator it = prim.begin(); it != prim.end(); ++it)
149 {
150 box = (*it)->CalcBounds();
151 if (box.max.y + box.min.y < median.y)
152 {
153 leftPrim.push_back(*it);
154 leftBox.Extend(box.max);
155 leftBox.Extend(box.min);
156 }
157 else
158 {
159 rightPrim.push_back(*it);
160 rightBox.Extend(box.max);
161 rightBox.Extend(box.min);
162 }
163 }
164 }
165 else
166 {
167 // Divide in z
168 for (vector<Primitive *>::iterator it = prim.begin(); it != prim.end(); ++it)
169 {
170 box = (*it)->CalcBounds();
171 if (box.max.z + box.min.z < median.z)
172 {
173 leftPrim.push_back(*it);
174 leftBox.Extend(box.max);
175 leftBox.Extend(box.min);
176 }
177 else
178 {
179 rightPrim.push_back(*it);
180 rightBox.Extend(box.max);
181 rightBox.Extend(box.min);
182 }
183 }
184 }
185 thisnode->leftChild = BuildTree(leftBox, leftPrim, depth + 1);
186 thisnode->rightChild = BuildTree(rightBox, rightPrim, depth + 1);
187 return thisnode;
188 }
189 }
190
191 // Root of the BVH tree
192 Node *root;
193
194 BVH(Box topBox, vector<Primitive *> primitives)
195 {
196 maxDepth = 25;
197 minTri = 3;
198 root = BuildTree(topBox, primitives, 0);
199 }
200
201 virtual ~BVH(){};
202
203 // Traverse the tree for intersection check
204 bool Intersect(Ray &ray)
205 {
206 ray.hit = NULL;
207 ray.t = Infinity;
208
209 root->traverse(ray);
210
211 return ray.hit != NULL;
212 }
213
214 // Traverse the tree for occudance check
215 bool Occluded(Ray &ray, Vec3f &color)
216 {
217 ray.hit = NULL;
218
219 root->traverse(ray);
220
221 if (!ray.hit)
222 return false;
223
224 // We approximate the transparency by returning the filter color
225 // This is not correct, but it pays off for the simple SchlickShader
226 if (ray.hit->shader->material->transparency <= 0.0)
227 return true;
228 else if (ray.t > Epsilon)
229 {
230 Vec3f newcolor = color;
231 Ray newray;
232
233 newray.org = ray.org + ray.t * ray.dir;
234 newray.dir = ray.dir;
235
236 if (!Occluded(newray, newcolor))
237 {
238 color = ray.hit->shader->material->color;
239 color = color + ray.hit->shader->material->transparency * (newcolor - color);
240 }
241 }
242
243 return false;
244 }
245 };
246
247 #endif
syntax highlighted by Code2HTML, v. 0.9.1