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