00001 #ifndef BIHNODE_HPP_
00002 #define BIHNODE_HPP_
00003
00004 #include <iostream>
00005 #include <limits>
00006 #include <algorithm>
00007 #include <stdexcept>
00008 #include <vector>
00009 #include "Traceable.h"
00010 #include "primitives/AABB.h"
00011 #include "loaders/conversion.hpp"
00012
00013 namespace rcrt
00014 {
00015
00019 class BIHSplit
00020 {
00021 public:
00022 float split;
00023 Axis axis;
00024
00025 BIHSplit(float s, Axis ax) : split(s), axis(ax)
00026 {}
00027 };
00028
00029
00034 template<class T>
00035 class BIHNode
00036 {
00037 private:
00043 BIHNode<T>* children[2];
00044
00048 std::vector<T*>* traceables;
00049
00053 int leftIndex;
00054
00058 int rightIndex;
00059
00066 float clip[2];
00067
00071 Axis splitAxis;
00072
00073
00080 Intersection leafIntersect(Ray& r, const float& tMin, const float& tMax) const
00081 {
00082 Intersection hit;
00083 if(leftIndex > rightIndex)
00084 return hit;
00085 for(int i = leftIndex; i < rightIndex+1; i++){
00086 float rmin = r.minDist();
00087 float rmax = r.maxDist();
00088 r.setMinDist(std::max(tMin,rmin));
00089 r.setMaxDist(std::min(tMax,rmax));
00090 Intersection curr = traceables->at(i)->intersect(r);
00091 r.setMaxDist(rmax);
00092 r.setMinDist(rmin);
00093 if(curr.isValid()){
00094 if(curr.getDistance() < hit.getDistance()){
00095 hit = curr;
00096 }
00097 if(curr.getDistance() < r.maxDist())
00098 r.setMaxDist(curr.getDistance());
00099 }
00100
00101 }
00102 return hit;
00103
00104 }
00105
00111 void initNodeAsLeaf(std::vector<T*>* trList, int left, int right)
00112 {
00113 children[0] = children[1] = 0;
00114 clip[0] = clip[1] = 0;
00115 traceables = trList;
00116 leftIndex = left;
00117 rightIndex = right;
00118 splitAxis = X_AXIS;
00119 }
00120
00129 void initNode(const AABB& bbox, std::vector<T*>* trList, int left, int right, int depth, int singleDepth = 0)
00130 {
00131 int n = right-left+1;
00132 int MAXDEPTH = 100;
00133 int MAXSINGLED = 12;
00134 if(n <= 0){
00135 throw std::runtime_error("[BIH-Build] - error: indices overlap: left=" + toString(left) + " right=" + toString(right));
00136 }
00137 else if(n == 1 || depth > MAXDEPTH || singleDepth > MAXSINGLED){
00138
00139 initNodeAsLeaf(trList,left,right);
00140 return;
00141 }
00142 else {
00143
00144 BIHSplit sp = getSplitPlane(bbox);
00145
00146
00147 int i = left;
00148 int j = right;
00149
00150
00151 float minL = std::numeric_limits<float>::infinity();
00152 float minR = std::numeric_limits<float>::infinity();
00153 float maxL = -std::numeric_limits<float>::infinity();
00154 float maxR = -std::numeric_limits<float>::infinity();
00155
00156 while(i <= j){
00157 const AABB& box = trList->at(i)->getBoundingBox();
00158
00159
00160 float pos = trList->at(i)->getCentroid()[sp.axis];
00161 float minB = box.getMin(sp.axis);
00162 float maxB = box.getMax(sp.axis);
00163 if(pos <= sp.split){
00164
00165 minL = std::min(minB, minL);
00166 maxL = std::max(maxB, maxL);
00167 i++;
00168 } else {
00169 minR = std::min(minB, minR);
00170 maxR = std::max(maxB, maxR);
00171 if(i != j){
00172 T* currL = trList->at(i);
00173 (*trList)[i] = trList->at(j);
00174 (*trList)[j] = currL;
00175 }
00176 j--;
00177 }
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 Point3D minRP = bbox.getMinP();
00191 minRP[sp.axis] = sp.split;
00192 Point3D maxRP = bbox.getMaxP();
00193
00194 Point3D minLP = bbox.getMinP();
00195 Point3D maxLP = bbox.getMaxP();
00196 maxLP[sp.axis] = sp.split;
00197
00198 AABB leftB(minLP,maxLP);
00199 AABB rightB(minRP,maxRP);
00200
00201
00202 splitAxis = sp.axis;
00203 leftIndex = left;
00204 rightIndex = right;
00205
00206 if(i > right){
00207
00208 clip[0] = minL;
00209 clip[1] = maxL;
00210 children[0] = new BIHNode(leftB,trList,left,right,depth+1, singleDepth + 1);
00211 children[1] = 0;
00212 }
00213 else if(i <= left){
00214
00215 clip[0] = minR;
00216 clip[1] = maxR;
00217 children[0] = new BIHNode(rightB,trList,left,right,depth+1, singleDepth +1);
00218 children[1] = 0;
00219
00220 } else {
00221 clip[0] = maxL;
00222 clip[1] = minR;
00223 children[0] = new BIHNode(leftB,trList,left,i-1,depth+1);
00224 children[1] = new BIHNode(rightB,trList,i,right,depth+1);
00225 }
00226 }
00227 }
00228
00229 public:
00230 BIHNode<T>()
00231 {
00232 children[0] = children[1] = 0;
00233 splitAxis = X_AXIS;
00234 clip[0] = clip[1] = 0;
00235 leftIndex = -1; rightIndex = -2;
00236 }
00237
00248 BIHNode<T>(const AABB& bbox, std::vector<T*>* trList, int left, int right, int depth = 0, int singleD = 0)
00249 {
00250 initNode(bbox, trList, left, right, depth, singleD);
00251 }
00252
00253 virtual ~BIHNode()
00254 {
00255 if(children[0] != 0) delete children[0];
00256 if(children[1] != 0) delete children[1];
00257 }
00258
00259
00260 virtual Intersection intersect(Ray& r, const float& tMin, const float& tMax) const
00261 {
00262 #if 0
00263 r.bihnodes++;
00264 #endif
00265
00266 if(isLeaf()){
00267 return leafIntersect(r, tMin, tMax);
00268 }
00269
00270 float dir = r.dir()[splitAxis];
00271 float org = r.org()[splitAxis];
00272 float t[2];
00273 float invdir = r.invDir()[splitAxis];
00274 int near = r.dirSign()[splitAxis];
00275 int far = 1 - near;
00276 t[0] = (clip[0]-org)*invdir;
00277 t[1] = (clip[1]-org)*invdir;
00278
00279
00280 if(dir != 0) {
00281 if(isSingle()){
00282 if(t[near] > tMax || t[far] < tMin)
00283 return Intersection();
00284 else {
00285 return children[0]->intersect(
00286 r, std::max(t[near], tMin), std::min(t[far], tMax));
00287 }
00288 }
00289 if(t[near] < tMin && t[far] > tMax){
00290
00291 return Intersection();
00292 }
00293 if(t[near] < tMin){
00294
00295 if(t[far] > tMin){
00296 Intersection is(children[far]->intersect(r, t[far], tMax));
00297 if(is.isValid() && is.getDistance() < r.maxDist())
00298 r.setMaxDist(is.getDistance());
00299 return is;
00300 } else {
00301 return children[far]->intersect(r, tMin, tMax);
00302 }
00303 }
00304 if(t[far] > tMax){
00305
00306 if(t[near] < tMax){
00307 Intersection is(children[near]->intersect(r, tMin, t[near]));
00308 if(is.isValid() && is.getDistance() < r.maxDist())
00309 r.setMaxDist(is.getDistance());
00310 return is;
00311 } else {
00312 return children[near]->intersect(r, tMin, tMax);
00313 }
00314 }
00315 }
00316
00317
00318 if(isSingle()){
00319 return children[0]->intersect(
00320 r, std::max(t[near], tMin), std::min(t[far], tMax));
00321 }
00322
00323 Intersection isN, isF;
00324
00325 isN = children[near]->intersect(r, tMin, tMax);
00326
00327 if(isN.isValid() && isN.getDistance() < r.maxDist())
00328 r.setMaxDist(isN.getDistance());
00329
00330
00331 isF = children[far]->intersect(r, tMin, tMax);
00332
00333 const bool valN = isN.isValid();
00334 const bool valF = isF.isValid();
00335
00336
00337 if(valN && valF){
00338 if(isN.getDistance() < isF.getDistance()){
00339 return isN;
00340 }
00341 return isF;
00342 }
00343 if(!(valN || valF)){
00344 return Intersection();
00345 }
00346 if(!valN)
00347 return isF;
00348 else
00349 return isN;
00350 }
00351
00352 bool isLeaf() const
00353 {
00354 return children[0] == 0 && children[1] == 0;
00355 }
00356
00357 bool isSingle() const
00358 {
00359 return children[0] != 0 && children[1] == 0;
00360 }
00361
00362 bool isEmpty() const
00363 {
00364 return traceables == 0 || traceables.empty();
00365 }
00366
00367 std::vector<T*>* getTraceables()
00368 {
00369 return traceables;
00370 }
00371
00372 static BIHSplit getSplitPlane(const AABB& box)
00373 {
00374 Axis a = box.getMainAxis();
00375 return BIHSplit(box.getCentroid()[a], a);
00376 }
00377
00378 };
00379
00380 }
00381
00382 #endif
00383