00001
00002
00003 #include <yafraycore/ray_kdtree.h>
00004 #include <core_api/material.h>
00005 #include <core_api/scene.h>
00006 #include <stdexcept>
00007
00008 #include <limits>
00009 #include <set>
00010 #if ( HAVE_PTHREAD && defined (__GNUC__) )
00011 #include <ext/mt_allocator.h>
00012 #endif
00013 #include <time.h>
00014
00015 __BEGIN_YAFRAY
00016
00017 #define LOWER_B 0
00018 #define UPPER_B 2
00019 #define BOTH_B 1
00020
00021 #define _TRI_CLIP 1 //tempoarily disabled
00022 #define TRI_CLIP_THRESH 32
00023 #define CLIP_DATA_SIZE (3*12*sizeof(double))
00024 #define KD_BINS 1024
00025
00026 #define KD_MAX_STACK 64
00027
00028
00029
00030
00031 #if (defined(_M_IX86) || defined(i386) || defined(_X86_))
00032 #define Y_FAST_INT 1
00033 #else
00034 #define Y_FAST_INT 0
00035 #endif
00036
00037 #define _doublemagicroundeps (0.5 - 1.4e-11)
00038
00039 inline int Y_Round2Int(double val) {
00040 #if Y_FAST_INT > 0
00041 union { double f; int i[2]; } u;
00042 u.f = val + 6755399441055744.0;
00043 return u.i[0];
00044 #else
00045 return int(val);
00046 #endif
00047 }
00048
00049 inline int Y_Float2Int(double val) {
00050 #if Y_FAST_INT > 0
00051 return (val<0) ? Y_Round2Int( val+_doublemagicroundeps ) :
00052 Y_Round2Int(val-_doublemagicroundeps);
00053 #else
00054 return (int)val;
00055 #endif
00056 }
00057
00058
00059
00060
00061
00062
00063
00064
00065 template<class T>
00066 kdTree_t<T>::kdTree_t(const T **v, int np, int depth, int leafSize,
00067 float cost_ratio, float emptyBonus)
00068 : costRatio(cost_ratio), eBonus(emptyBonus), maxDepth(depth)
00069 {
00070 std::cout << "starting build of kd-tree ("<<np<<" prims, cr:"<<costRatio<<" eb:"<<eBonus<<")\n";
00071 clock_t c_start, c_end;
00072 c_start = clock();
00073 Kd_inodes=0, Kd_leaves=0, _emptyKd_leaves=0, Kd_prims=0, depthLimitReached=0, NumBadSplits=0,
00074 _clip=0, _bad_clip=0, _null_clip=0, _early_out=0;
00075 totalPrims = np;
00076 nextFreeNode = 0;
00077 allocatedNodesCount = 256;
00078 nodes = (rkdTreeNode<T>*)y_memalign(64, 256 * sizeof(rkdTreeNode<T>));
00079 if(maxDepth <= 0) maxDepth = int( 7.0f + 1.66f * log(float(totalPrims)) );
00080 double logLeaves = 1.442695f * log(double(totalPrims));
00081 if(leafSize <= 0)
00082 {
00083
00084 int mls = int( logLeaves - 16.0 );
00085 if(mls <= 0) mls = 1;
00086 maxLeafSize = (unsigned int) mls;
00087 }
00088 else maxLeafSize = (unsigned int) leafSize;
00089 if(maxDepth>KD_MAX_STACK) maxDepth = KD_MAX_STACK;
00090
00091 if( logLeaves > 16.0 ) costRatio += 0.25*( logLeaves - 16.0 );
00092 allBounds = new bound_t[totalPrims + TRI_CLIP_THRESH+1];
00093 std::cout << "getting triangle bounds...";
00094 for(u_int32 i=0; i<totalPrims; i++)
00095 {
00096 allBounds[i] = v[i]->getBound();
00097
00098 if(i) treeBound = bound_t(treeBound, allBounds[i]);
00099 else treeBound = allBounds[i];
00100 }
00101
00102
00103 for(int i=0;i<3;i++)
00104 {
00105 double foo = (treeBound.g[i] - treeBound.a[i])*0.001;
00106 treeBound.a[i] -= foo, treeBound.g[i] += foo;
00107 }
00108 std::cout << "done!\n";
00109
00110 boundEdge *edges[3];
00111 u_int32 rMemSize = 3*totalPrims;
00112 u_int32 *leftPrims = new u_int32[std::max( (u_int32)2*TRI_CLIP_THRESH, totalPrims )];
00113 u_int32 *rightPrims = new u_int32[rMemSize];
00114
00115 for (int i = 0; i < 3; ++i) edges[i] = new boundEdge[514];
00116 clip = new int[maxDepth+2];
00117 cdata = (char*)y_memalign(64, (maxDepth+2)*TRI_CLIP_THRESH*CLIP_DATA_SIZE);
00118
00119
00120 for (u_int32 i = 0; i < totalPrims; i++) leftPrims[i] = i;
00121 for (int i = 0; i < maxDepth+2; i++) clip[i] = -1;
00122
00123
00124 prims = v;
00125 std::cout << "starting recursive build...\n";
00126 buildTree(totalPrims, treeBound, leftPrims,
00127 leftPrims, rightPrims, edges,
00128 rMemSize, 0, 0 );
00129
00130
00131 delete[] leftPrims;
00132 delete[] rightPrims;
00133 delete[] allBounds;
00134 for (int i = 0; i < 3; ++i) delete[] edges[i];
00135 delete[] clip;
00136 y_free(cdata);
00137
00138 c_end = clock() - c_start;
00139 std::cout << "\n=== kd-tree stats ("<< float(c_end) / (float)CLOCKS_PER_SEC <<"s) ===\n";
00140 std::cout << "used/allocated kd-tree nodes: " << nextFreeNode << "/" << allocatedNodesCount
00141 << " (" << 100.f * float(nextFreeNode)/allocatedNodesCount << "%)\n";
00142 std::cout << "primitives in tree: " << totalPrims << std::endl;
00143 std::cout << "interior nodes: " << Kd_inodes << " / " << "leaf nodes: " << Kd_leaves
00144 << " (empty: " << _emptyKd_leaves << " = " << 100.f * float(_emptyKd_leaves)/Kd_leaves << "%)\n";
00145 std::cout << "leaf prims: " << Kd_prims << " (" << float(Kd_prims)/totalPrims << "x prims in tree, leaf size:"<< maxLeafSize<<")\n";
00146 std::cout << " => " << float(Kd_prims)/ (Kd_leaves-_emptyKd_leaves) << " prims per non-empty leaf\n";
00147 std::cout << "leaves due to depth limit/bad splits: " << depthLimitReached << "/" << NumBadSplits << "\n";
00148 std::cout << "clipped triangles: " << _clip << " (" <<_bad_clip << " bad clips, "<<_null_clip
00149 <<" null clips)\n";
00150
00151 }
00152
00153 template<class T>
00154 kdTree_t<T>::~kdTree_t()
00155 {
00156
00157 y_free(nodes);
00158
00159
00160 }
00161
00162
00168 template<class T>
00169 void kdTree_t<T>::pigeonMinCost(u_int32 nPrims, bound_t &nodeBound, u_int32 *primIdx, splitCost_t &split)
00170 {
00171 bin_t bin[ KD_BINS+1 ];
00172 PFLOAT d[3];
00173 d[0] = nodeBound.longX();
00174 d[1] = nodeBound.longY();
00175 d[2] = nodeBound.longZ();
00176 split.oldCost = float(nPrims);
00177 split.bestCost = std::numeric_limits<PFLOAT>::infinity();
00178 float invTotalSA = 1.0f / (d[0]*d[1] + d[0]*d[2] + d[1]*d[2]);
00179 PFLOAT t_low, t_up;
00180 int b_left, b_right;
00181
00182 for(int axis=0;axis<3;axis++)
00183 {
00184 PFLOAT s = KD_BINS/d[axis];
00185 PFLOAT min = nodeBound.a[axis];
00186
00187 for(unsigned int i=0; i<nPrims; ++i)
00188 {
00189 const bound_t &bbox = allBounds[ primIdx[i] ];
00190 t_low = bbox.a[axis];
00191 t_up = bbox.g[axis];
00192 b_left = (int)((t_low - min)*s);
00193 b_right = (int)((t_up - min)*s);
00194
00195
00196 if(b_left<0) b_left=0; else if(b_left > KD_BINS) b_left = KD_BINS;
00197 if(b_right<0) b_right=0; else if(b_right > KD_BINS) b_right = KD_BINS;
00198
00199 if(t_low == t_up)
00200 {
00201 if(bin[b_left].empty() || (t_low >= bin[b_left].t && !bin[b_left].empty() ) )
00202 {
00203 bin[b_left].t = t_low;
00204 bin[b_left].c_both++;
00205 }
00206 else
00207 {
00208 bin[b_left].c_left++;
00209 bin[b_left].c_right++;
00210 }
00211 bin[b_left].n += 2;
00212 }
00213 else
00214 {
00215 if(bin[b_left].empty() || (t_low > bin[b_left].t && !bin[b_left].empty() ) )
00216 {
00217 bin[b_left].t = t_low;
00218 bin[b_left].c_left += bin[b_left].c_both + bin[b_left].c_bleft;
00219 bin[b_left].c_right += bin[b_left].c_both;
00220 bin[b_left].c_both = bin[b_left].c_bleft = 0;
00221 bin[b_left].c_bleft++;
00222 }
00223 else if(t_low == bin[b_left].t)
00224 {
00225 bin[b_left].c_bleft++;
00226 }
00227 else bin[b_left].c_left++;
00228 bin[b_left].n++;
00229
00230 bin[b_right].c_right++;
00231 if(bin[b_right].empty() || t_up > bin[b_right].t)
00232 {
00233 bin[b_right].t = t_up;
00234 bin[b_right].c_left += bin[b_right].c_both + bin[b_right].c_bleft;
00235 bin[b_right].c_right += bin[b_right].c_both;
00236 bin[b_right].c_both = bin[b_right].c_bleft = 0;
00237 }
00238 bin[b_right].n++;
00239 }
00240
00241 }
00242
00243 const int axisLUT[3][3] = { {0,1,2}, {1,2,0}, {2,0,1} };
00244 float capArea = d[ axisLUT[1][axis] ] * d[ axisLUT[2][axis] ];
00245 float capPerim = d[ axisLUT[1][axis] ] + d[ axisLUT[2][axis] ];
00246
00247 unsigned int nBelow=0, nAbove=nPrims;
00248
00249 for(int i=0; i<KD_BINS+1; ++i)
00250 {
00251 if(!bin[i].empty())
00252 {
00253 nBelow += bin[i].c_left;
00254 nAbove -= bin[i].c_right;
00255
00256 PFLOAT edget = bin[i].t;
00257 if (edget > nodeBound.a[axis] &&
00258 edget < nodeBound.g[axis]) {
00259
00260 float l1 = edget - nodeBound.a[axis];
00261 float l2 = nodeBound.g[axis] - edget;
00262 float belowSA = capArea + l1*capPerim;
00263 float aboveSA = capArea + l2*capPerim;
00264 float rawCosts = (belowSA * nBelow + aboveSA * nAbove);
00265
00266 float eb;
00267 if(nAbove == 0) eb = (0.1f + l2/d[axis])*eBonus*rawCosts;
00268 else if(nBelow == 0) eb = (0.1f + l1/d[axis])*eBonus*rawCosts;
00269 else eb = 0.0f;
00270 float cost = costRatio + invTotalSA * (rawCosts - eb);
00271
00272 if (cost < split.bestCost) {
00273 split.t = edget;
00274 split.bestCost = cost;
00275 split.bestAxis = axis;
00276 split.bestOffset = i;
00277 split.nBelow = nBelow;
00278 split.nAbove = nAbove;
00279 }
00280 }
00281 nBelow += bin[i].c_both + bin[i].c_bleft;
00282 nAbove -= bin[i].c_both;
00283 }
00284 }
00285 if(nBelow != nPrims || nAbove != 0)
00286 {
00287 int c1=0, c2=0, c3=0, c4=0, c5=0;
00288 std::cout << "SCREWED!!\n";
00289 for(int i=0;i<KD_BINS+1;i++){ c1+= bin[i].n; std::cout << bin[i].n << " ";}
00290 std::cout << "\nn total: "<< c1 << "\n";
00291 for(int i=0;i<KD_BINS+1;i++){ c2+= bin[i].c_left; std::cout << bin[i].c_left << " ";}
00292 std::cout << "\nc_left total: "<< c2 << "\n";
00293 for(int i=0;i<KD_BINS+1;i++){ c3+= bin[i].c_bleft; std::cout << bin[i].c_bleft << " ";}
00294 std::cout << "\nc_bleft total: "<< c3 << "\n";
00295 for(int i=0;i<KD_BINS+1;i++){ c4+= bin[i].c_both; std::cout << bin[i].c_both << " ";}
00296 std::cout << "\nc_both total: "<< c4 << "\n";
00297 for(int i=0;i<KD_BINS+1;i++){ c5+= bin[i].c_right; std::cout << bin[i].c_right << " ";}
00298 std::cout << "\nc_right total: "<< c5 << "\n";
00299 std::cout << "\nnPrims: "<<nPrims<<" nBelow: "<<nBelow<<" nAbove: "<<nAbove<<"\n";
00300 std::cout << "total left: " << c2 + c3 + c4 << "\ntotal right: " << c4 + c5 << "\n";
00301 std::cout << "n/2: " << c1/2 << "\n";
00302 throw std::logic_error("cost function mismatch");
00303 }
00304 for(int i=0;i<KD_BINS+1;i++) bin[i].reset();
00305 }
00306 }
00307
00308
00313 template<class T>
00314 void kdTree_t<T>::minimalCost(u_int32 nPrims, bound_t &nodeBound, u_int32 *primIdx,
00315 const bound_t *pBounds, boundEdge *edges[3], splitCost_t &split)
00316 {
00317 PFLOAT d[3];
00318 d[0] = nodeBound.longX();
00319 d[1] = nodeBound.longY();
00320 d[2] = nodeBound.longZ();
00321 split.oldCost = float(nPrims);
00322 split.bestCost = std::numeric_limits<PFLOAT>::infinity();
00323 float invTotalSA = 1.0f / (d[0]*d[1] + d[0]*d[2] + d[1]*d[2]);
00324 int nEdge;
00325
00326 for(int axis=0;axis<3;axis++)
00327 {
00328
00329 int pn;
00330 nEdge=0;
00331
00332 if(pBounds!=allBounds) for (unsigned int i=0; i < nPrims; i++)
00333 {
00334 pn = primIdx[i];
00335 const bound_t &bbox = pBounds[i];
00336 if(bbox.a[axis] == bbox.g[axis])
00337 {
00338 edges[axis][nEdge] = boundEdge(bbox.a[axis], i , BOTH_B);
00339 ++nEdge;
00340 }
00341 else
00342 {
00343 edges[axis][nEdge] = boundEdge(bbox.a[axis], i , LOWER_B);
00344 edges[axis][nEdge+1] = boundEdge(bbox.g[axis], i , UPPER_B);
00345 nEdge += 2;
00346 }
00347 }
00348 else for (unsigned int i=0; i < nPrims; i++)
00349 {
00350 pn = primIdx[i];
00351 const bound_t &bbox = pBounds[pn];
00352 if(bbox.a[axis] == bbox.g[axis])
00353 {
00354 edges[axis][nEdge] = boundEdge(bbox.a[axis], pn, BOTH_B);
00355 ++nEdge;
00356 }
00357 else
00358 {
00359 edges[axis][nEdge] = boundEdge(bbox.a[axis], pn, LOWER_B);
00360 edges[axis][nEdge+1] = boundEdge(bbox.g[axis], pn, UPPER_B);
00361 nEdge += 2;
00362 }
00363 }
00364 std::sort(&edges[axis][0], &edges[axis][nEdge]);
00365
00366 const int axisLUT[3][3] = { {0,1,2}, {1,2,0}, {2,0,1} };
00367 float capArea = d[ axisLUT[1][axis] ] * d[ axisLUT[2][axis] ];
00368 float capPerim = d[ axisLUT[1][axis] ] + d[ axisLUT[2][axis] ];
00369 unsigned int nBelow = 0, nAbove = nPrims;
00370
00371 if(nPrims>5)
00372 {
00373 PFLOAT edget = edges[axis][0].pos;
00374 float l1 = edget - nodeBound.a[axis];
00375 float l2 = nodeBound.g[axis] - edget;
00376 if(l1 > l2*float(nPrims) && l2 > 0.f)
00377 {
00378 float rawCosts = (capArea + l2*capPerim) * nPrims;
00379 float cost = costRatio + invTotalSA * (rawCosts - eBonus);
00380
00381 if (cost < split.bestCost) {
00382 split.bestCost = cost;
00383 split.bestAxis = axis;
00384 split.bestOffset = 0;
00385 split.nEdge = nEdge;
00386 ++_early_out;
00387 }
00388 continue;
00389 }
00390 edget = edges[axis][nEdge-1].pos;
00391 l1 = edget - nodeBound.a[axis];
00392 l2 = nodeBound.g[axis] - edget;
00393 if(l2 > l1*float(nPrims) && l1 > 0.f)
00394 {
00395 float rawCosts = (capArea + l1*capPerim) * nPrims;
00396 float cost = costRatio + invTotalSA * (rawCosts - eBonus);
00397 if (cost < split.bestCost) {
00398 split.bestCost = cost;
00399 split.bestAxis = axis;
00400 split.bestOffset = nEdge-1;
00401 split.nEdge = nEdge;
00402 ++_early_out;
00403 }
00404 continue;
00405 }
00406 }
00407
00408 for (int i = 0; i < nEdge; ++i) {
00409 if (edges[axis][i].end == UPPER_B) --nAbove;
00410 PFLOAT edget = edges[axis][i].pos;
00411 if (edget > nodeBound.a[axis] &&
00412 edget < nodeBound.g[axis]) {
00413
00414 float l1 = edget - nodeBound.a[axis];
00415 float l2 = nodeBound.g[axis] - edget;
00416 float belowSA = capArea + (l1)*capPerim;
00417 float aboveSA = capArea + (l2)*capPerim;
00418 float rawCosts = (belowSA * nBelow + aboveSA * nAbove);
00419
00420 float eb;
00421 if(nAbove == 0) eb = (0.1f + l2/d[axis])*eBonus*rawCosts;
00422 else if(nBelow == 0) eb = (0.1f + l1/d[axis])*eBonus*rawCosts;
00423 else eb = 0.0f;
00424 float cost = costRatio + invTotalSA * (rawCosts - eb);
00425
00426 if (cost < split.bestCost) {
00427 split.bestCost = cost;
00428 split.bestAxis = axis;
00429 split.bestOffset = i;
00430 split.nEdge = nEdge;
00431
00432 split.nBelow = nBelow;
00433 split.nAbove = nAbove;
00434 }
00435 }
00436 if (edges[axis][i].end != UPPER_B)
00437 {
00438 ++nBelow;
00439 if (edges[axis][i].end == BOTH_B) --nAbove;
00440 }
00441 }
00442 if(nBelow != nPrims || nAbove != 0) std::cout << "you screwed your new idea!\n";
00443
00444 }
00445 }
00446
00447
00454 template<class T>
00455 int kdTree_t<T>::buildTree(u_int32 nPrims, bound_t &nodeBound, u_int32 *primNums,
00456 u_int32 *leftPrims, u_int32 *rightPrims, boundEdge *edges[3],
00457 u_int32 rightMemSize, int depth, int badRefines )
00458 {
00459
00460 if (nextFreeNode == allocatedNodesCount) {
00461 int newCount = 2*allocatedNodesCount;
00462 newCount = (newCount > 0x100000) ? allocatedNodesCount+0x80000 : newCount;
00463 rkdTreeNode<T> *n = (rkdTreeNode<T> *) y_memalign(64, newCount * sizeof(rkdTreeNode<T>));
00464 memcpy(n, nodes, allocatedNodesCount * sizeof(rkdTreeNode<T>));
00465 y_free(nodes);
00466 nodes = n;
00467 allocatedNodesCount = newCount;
00468 }
00469
00470 #if _TRI_CLIP > 0
00471 if(nPrims <= TRI_CLIP_THRESH)
00472 {
00473
00474 int oPrims[TRI_CLIP_THRESH], nOverl=0;
00475 double bHalfSize[3];
00476 double b_ext[2][3];
00477 for(int i=0; i<3; ++i)
00478 {
00479
00480 bHalfSize[i] = ((double)nodeBound.g[i] - (double)nodeBound.a[i]);
00481 double temp = ((double)treeBound.g[i] - (double)treeBound.a[i]);
00482 b_ext[0][i] = nodeBound.a[i] - 0.021*bHalfSize[i] - 0.00001*temp;
00483 b_ext[1][i] = nodeBound.g[i] + 0.021*bHalfSize[i] + 0.00001*temp;
00484
00485 }
00486 char *c_old = cdata + (TRI_CLIP_THRESH * CLIP_DATA_SIZE * depth);
00487 char *c_new = cdata + (TRI_CLIP_THRESH * CLIP_DATA_SIZE * (depth+1));
00488 for(unsigned int i=0; i<nPrims; ++i)
00489 {
00490 const T *ct = prims[ primNums[i] ];
00491 u_int32 old_idx=0;
00492 if(clip[depth] >= 0) old_idx = primNums[i+nPrims];
00493
00494
00495 if(ct->clippingSupport())
00496 {
00497 if( ct->clipToBound(b_ext, clip[depth], allBounds[totalPrims+nOverl],
00498 c_old + old_idx*CLIP_DATA_SIZE, c_new + nOverl*CLIP_DATA_SIZE) )
00499 {
00500 ++_clip;
00501 oPrims[nOverl] = primNums[i]; nOverl++;
00502 }
00503 else ++_null_clip;
00504 }
00505 else
00506 {
00507
00508 allBounds[totalPrims+nOverl] = allBounds[ primNums[i] ];
00509 oPrims[nOverl] = primNums[i]; nOverl++;
00510 }
00511 }
00512
00513 memcpy(primNums, oPrims, nOverl*sizeof(u_int32));
00514 nPrims = nOverl;
00515 }
00516 #endif
00517
00518 if(nPrims <= maxLeafSize || depth >= maxDepth)
00519 {
00520
00521 nodes[nextFreeNode].createLeaf(primNums, nPrims, prims, primsArena);
00522 nextFreeNode++;
00523 if( depth >= maxDepth ) depthLimitReached++;
00524 return 0;
00525 }
00526
00527
00528 splitCost_t split;
00529 float baseBonus=eBonus;
00530 eBonus *= 1.1 - (float)depth/(float)maxDepth;
00531 if(nPrims > 128) pigeonMinCost(nPrims, nodeBound, primNums, split);
00532 #if _TRI_CLIP > 0
00533 else if (nPrims > TRI_CLIP_THRESH) minimalCost(nPrims, nodeBound, primNums, allBounds, edges, split);
00534 else minimalCost(nPrims, nodeBound, primNums, allBounds+totalPrims, edges, split);
00535 #else
00536 else minimalCost(nPrims, nodeBound, primNums, allBounds, edges, split);
00537 #endif
00538 eBonus=baseBonus;
00539
00540 if (split.bestCost > split.oldCost) ++badRefines;
00541 if ((split.bestCost > 1.6f * split.oldCost && nPrims < 16) ||
00542 split.bestAxis == -1 || badRefines == 2) {
00543 nodes[nextFreeNode].createLeaf(primNums, nPrims, prims, primsArena);
00544 nextFreeNode++;
00545 if( badRefines == 2) ++NumBadSplits;
00546 return 0;
00547 }
00548
00549
00550 u_int32 remainingMem, *morePrims = 0, *nRightPrims;
00551 u_int32 *oldRightPrims = rightPrims;
00552 if(nPrims > rightMemSize || 2*TRI_CLIP_THRESH > rightMemSize )
00553 {
00554
00555 remainingMem = nPrims * 3;
00556 morePrims = new u_int32[remainingMem];
00557 nRightPrims = morePrims;
00558 }
00559 else
00560 {
00561 nRightPrims = oldRightPrims;
00562 remainingMem = rightMemSize;
00563 }
00564
00565
00566 PFLOAT splitPos;
00567 int n0 = 0, n1 = 0;
00568 if(nPrims > 128)
00569 {
00570 int pn;
00571 for (unsigned int i=0; i<nPrims; i++)
00572 {
00573 pn = primNums[i];
00574 if(allBounds[ pn ].a[split.bestAxis] >= split.t) nRightPrims[n1++] = pn;
00575 else
00576 {
00577 leftPrims[n0++] = pn;
00578 if(allBounds[ pn ].g[split.bestAxis] > split.t) nRightPrims[n1++] = pn;
00579 }
00580 }
00581 splitPos = split.t;
00582 if (n0!= split.nBelow || n1 != split.nAbove) std::cout << "oops!\n";
00583
00584
00585
00586
00587
00588
00589
00590 }
00591 else if(nPrims <= TRI_CLIP_THRESH)
00592 {
00593 int cindizes[TRI_CLIP_THRESH];
00594 u_int32 oldPrims[TRI_CLIP_THRESH];
00595
00596 memcpy(oldPrims, primNums, nPrims*sizeof(int));
00597
00598 for (int i=0; i<split.bestOffset; ++i)
00599 if (edges[split.bestAxis][i].end != UPPER_B)
00600 {
00601 cindizes[n0] = edges[split.bestAxis][i].primNum;
00602
00603 leftPrims[n0] = oldPrims[cindizes[n0]];
00604 ++n0;
00605 }
00606
00607 for(int i=0; i<n0; ++i){ leftPrims[n0+i] = cindizes[i]; }
00608 if (edges[split.bestAxis][split.bestOffset].end == BOTH_B)
00609 {
00610 cindizes[n1] = edges[split.bestAxis][split.bestOffset].primNum;
00611
00612 nRightPrims[n1] = oldPrims[cindizes[n1]];
00613 ++n1;
00614 }
00615 for (int i=split.bestOffset+1; i<split.nEdge; ++i)
00616 if (edges[split.bestAxis][i].end != LOWER_B)
00617 {
00618 cindizes[n1] = edges[split.bestAxis][i].primNum;
00619
00620 nRightPrims[n1] = oldPrims[cindizes[n1]];
00621 ++n1;
00622 }
00623
00624 for(int i=0; i<n1; ++i){ nRightPrims[n1+i] = cindizes[i]; }
00625 splitPos = edges[split.bestAxis][split.bestOffset].pos;
00626
00627 }
00628 else
00629 {
00630 for (int i=0; i<split.bestOffset; ++i)
00631 if (edges[split.bestAxis][i].end != UPPER_B)
00632 leftPrims[n0++] = edges[split.bestAxis][i].primNum;
00633 if (edges[split.bestAxis][split.bestOffset].end == BOTH_B)
00634 nRightPrims[n1++] = edges[split.bestAxis][split.bestOffset].primNum;
00635 for (int i=split.bestOffset+1; i<split.nEdge; ++i)
00636 if (edges[split.bestAxis][i].end != LOWER_B)
00637 nRightPrims[n1++] = edges[split.bestAxis][i].primNum;
00638 splitPos = edges[split.bestAxis][split.bestOffset].pos;
00639 }
00640
00641
00642 remainingMem -= n1;
00643
00644
00645 u_int32 curNode = nextFreeNode;
00646 nodes[curNode].createInterior(split.bestAxis, splitPos);
00647 ++nextFreeNode;
00648 bound_t boundL = nodeBound, boundR = nodeBound;
00649 switch(split.bestAxis){
00650 case 0: boundL.setMaxX(splitPos); boundR.setMinX(splitPos); break;
00651 case 1: boundL.setMaxY(splitPos); boundR.setMinY(splitPos); break;
00652 case 2: boundL.setMaxZ(splitPos); boundR.setMinZ(splitPos); break;
00653 }
00654
00655 #if _TRI_CLIP > 0
00656 if(nPrims <= TRI_CLIP_THRESH)
00657 {
00658 remainingMem -= n1;
00659
00660 clip[depth+1] = split.bestAxis;
00661 buildTree(n0, boundL, leftPrims, leftPrims, nRightPrims+2*n1, edges, remainingMem, depth+1, badRefines);
00662 clip[depth+1] |= 1<<2;
00663
00664 nodes[curNode].setRightChild (nextFreeNode);
00665 buildTree(n1, boundR, nRightPrims, leftPrims, nRightPrims+2*n1, edges, remainingMem, depth+1, badRefines);
00666 clip[depth+1] = -1;
00667 }
00668 else
00669 {
00670 #endif
00671
00672 buildTree(n0, boundL, leftPrims, leftPrims, nRightPrims+n1, edges, remainingMem, depth+1, badRefines);
00673
00674 nodes[curNode].setRightChild (nextFreeNode);
00675 buildTree(n1, boundR, nRightPrims, leftPrims, nRightPrims+n1, edges, remainingMem, depth+1, badRefines);
00676 #if _TRI_CLIP > 0
00677 }
00678 #endif
00679
00680 if(morePrims) delete[] morePrims;
00681 return 1;
00682 }
00683
00684
00685
00686
00690 template<class T>
00691 bool kdTree_t<T>::Intersect(const ray_t &ray, PFLOAT dist, T **tr, PFLOAT &Z, void *udat) const
00692 {
00693 Z=dist;
00694
00695 PFLOAT a, b, t;
00696 PFLOAT t_hit;
00697
00698 if (!treeBound.cross(ray, a, b, dist))
00699 { return false; }
00700
00701 unsigned char udat1[PRIM_DAT_SIZE], udat2[PRIM_DAT_SIZE];
00702 void *c_udat=(void*)&udat1[0], *t_udat=(void*)&udat2[0];
00703 vector3d_t invDir(1.0/ray.dir.x, 1.0/ray.dir.y, 1.0/ray.dir.z);
00704
00705 bool hit = false;
00706
00707 rKdStack<T> stack[KD_MAX_STACK];
00708 const rkdTreeNode<T> *farChild, *currNode;
00709 currNode = nodes;
00710
00711 int enPt = 0;
00712 stack[enPt].t = a;
00713
00714
00715 if(a >= 0.0)
00716 stack[enPt].pb = ray.from + ray.dir * a;
00717 else
00718 stack[enPt].pb = ray.from;
00719
00720
00721 int exPt = 1;
00722 stack[exPt].t = b;
00723 stack[exPt].pb = ray.from + ray.dir * b;
00724 stack[exPt].node = 0;
00725
00726
00727 while (currNode != NULL)
00728 {
00729 if (dist < stack[enPt].t) break;
00730
00731 while( !currNode->IsLeaf() )
00732 {
00733 int axis = currNode->SplitAxis();
00734 PFLOAT splitVal = currNode->SplitPos();
00735
00736 if(stack[enPt].pb[axis] <= splitVal){
00737 if(stack[exPt].pb[axis] <= splitVal)
00738 {
00739 currNode++;
00740 continue;
00741 }
00742 if(stack[exPt].pb[axis] == splitVal)
00743 {
00744 currNode = &nodes[currNode->getRightChild()];
00745 continue;
00746 }
00747
00748 farChild = &nodes[currNode->getRightChild()];
00749 currNode ++;
00750 }
00751 else
00752 {
00753 if(splitVal < stack[exPt].pb[axis])
00754 {
00755 currNode = &nodes[currNode->getRightChild()];
00756 continue;
00757 }
00758 farChild = currNode+1;
00759 currNode = &nodes[currNode->getRightChild()];
00760 }
00761
00762
00763 t = (splitVal - ray.from[axis]) * invDir[axis];
00764
00765
00766 int tmp = exPt;
00767 exPt++;
00768
00769
00770 if (exPt == enPt) exPt++;
00771
00772 static const int npAxis[2][3] = { {1, 2, 0}, {2, 0, 1} };
00773 int nextAxis = npAxis[0][axis];
00774 int prevAxis = npAxis[1][axis];
00775 stack[exPt].prev = tmp;
00776 stack[exPt].t = t;
00777 stack[exPt].node = farChild;
00778 stack[exPt].pb[axis] = splitVal;
00779 stack[exPt].pb[nextAxis] = ray.from[nextAxis] + t * ray.dir[nextAxis];
00780 stack[exPt].pb[prevAxis] = ray.from[prevAxis] + t * ray.dir[prevAxis];
00781 }
00782
00783
00784 u_int32 nPrimitives = currNode->nPrimitives();
00785 if (nPrimitives == 1) {
00786 T *mp = currNode->onePrimitive;
00787
00788
00789 if (mp->intersect(ray, &t_hit, t_udat))
00790 {
00791
00792 if(t_hit < Z && t_hit >= ray.tmin )
00793 {
00794 Z = t_hit;
00795 *tr = mp;
00796 std::swap(t_udat, c_udat);
00797 hit = true;
00798 }
00799 }
00800
00801 }
00802 else {
00803 T **prims = currNode->primitives;
00804 for (u_int32 i = 0; i < nPrimitives; ++i) {
00805 T *mp = prims[i];
00806
00807
00808 if (mp->intersect(ray, &t_hit, t_udat))
00809 {
00810
00811 if(t_hit < Z && t_hit >= ray.tmin )
00812 {
00813 Z = t_hit;
00814 *tr = mp;
00815 std::swap(t_udat, c_udat);
00816 hit = true;
00817 }
00818 }
00819
00820 }
00821 }
00822
00823 if(hit && Z <= stack[exPt].t){ memcpy(udat, c_udat, PRIM_DAT_SIZE); return true;}
00824
00825 enPt = exPt;
00826 currNode = stack[exPt].node;
00827 exPt = stack[enPt].prev;
00828
00829 }
00830
00831 memcpy(udat, c_udat, PRIM_DAT_SIZE);
00832 return hit;
00833 }
00834
00835 template<class T>
00836 bool kdTree_t<T>::IntersectS(const ray_t &ray, PFLOAT dist, T **tr) const
00837 {
00838 PFLOAT a, b, t;
00839 PFLOAT t_hit;
00840
00841 if (!treeBound.cross(ray, a, b, dist))
00842 return false;
00843
00844 unsigned char udat[PRIM_DAT_SIZE];
00845 vector3d_t invDir(1.f/ray.dir.x, 1.f/ray.dir.y, 1.f/ray.dir.z);
00846
00847
00848
00849 rKdStack<T> stack[KD_MAX_STACK];
00850 const rkdTreeNode<T> *farChild, *currNode;
00851 currNode = nodes;
00852
00853 int enPt = 0;
00854 stack[enPt].t = a;
00855
00856
00857 if(a >= 0.0)
00858 stack[enPt].pb = ray.from + ray.dir * a;
00859 else
00860 stack[enPt].pb = ray.from;
00861
00862
00863 int exPt = 1;
00864 stack[exPt].t = b;
00865 stack[exPt].pb = ray.from + ray.dir * b;
00866 stack[exPt].node = 0;
00867
00868
00869 while (currNode != NULL)
00870 {
00871 if (dist < stack[enPt].t ) break;
00872
00873 while( !currNode->IsLeaf() )
00874 {
00875 int axis = currNode->SplitAxis();
00876 PFLOAT splitVal = currNode->SplitPos();
00877
00878 if(stack[enPt].pb[axis] <= splitVal){
00879 if(stack[exPt].pb[axis] <= splitVal)
00880 {
00881 currNode++;
00882 continue;
00883 }
00884 if(stack[exPt].pb[axis] == splitVal)
00885 {
00886 currNode = &nodes[currNode->getRightChild()];
00887 continue;
00888 }
00889
00890 farChild = &nodes[currNode->getRightChild()];
00891 currNode ++;
00892 }
00893 else
00894 {
00895 if(splitVal < stack[exPt].pb[axis])
00896 {
00897 currNode = &nodes[currNode->getRightChild()];
00898 continue;
00899 }
00900 farChild = currNode+1;
00901 currNode = &nodes[currNode->getRightChild()];
00902 }
00903
00904
00905 t = (splitVal - ray.from[axis]) * invDir[axis];
00906
00907
00908 int tmp = exPt;
00909 exPt++;
00910
00911
00912 if (exPt == enPt) exPt++;
00913
00914 static const int npAxis[2][3] = { {1, 2, 0}, {2, 0, 1} };
00915 int nextAxis = npAxis[0][axis];
00916 int prevAxis = npAxis[1][axis];
00917 stack[exPt].prev = tmp;
00918 stack[exPt].t = t;
00919 stack[exPt].node = farChild;
00920 stack[exPt].pb[axis] = splitVal;
00921 stack[exPt].pb[nextAxis] = ray.from[nextAxis] + t * ray.dir[nextAxis];
00922 stack[exPt].pb[prevAxis] = ray.from[prevAxis] + t * ray.dir[prevAxis];
00923 }
00924
00925
00926 u_int32 nPrimitives = currNode->nPrimitives();
00927 if (nPrimitives == 1) {
00928 T *mp = currNode->onePrimitive;
00929
00930
00931 if (mp->intersect(ray, &t_hit, (void*)&udat[0]))
00932 {
00933
00934 if(t_hit < dist && t_hit > 0.f )
00935 {
00936 *tr = mp;
00937 return true;
00938 }
00939 }
00940
00941 }
00942 else {
00943 T **prims = currNode->primitives;
00944 for (u_int32 i = 0; i < nPrimitives; ++i) {
00945 T *mp = prims[i];
00946
00947
00948 if (mp->intersect(ray, &t_hit, (void*)&udat[0]))
00949 {
00950 if(t_hit < dist && t_hit > 0.f )
00951 {
00952
00953 *tr = mp;
00954 return true;
00955 }
00956 }
00957
00958 }
00959 }
00960
00961
00962
00963 enPt = exPt;
00964 currNode = stack[exPt].node;
00965 exPt = stack[enPt].prev;
00966
00967 }
00968
00969 return false;
00970 }
00971
00972
00973
00974
00975
00976 template<class T>
00977 bool kdTree_t<T>::IntersectTS(renderState_t &state, const ray_t &ray, int maxDepth, PFLOAT dist, T **tr, color_t &filt) const
00978 {
00979 PFLOAT a, b, t;
00980 PFLOAT t_hit;
00981
00982 if (!treeBound.cross(ray, a, b, dist))
00983 return false;
00984
00985 double udat[PRIM_DAT_SIZE];
00986 vector3d_t invDir(1.f/ray.dir.x, 1.f/ray.dir.y, 1.f/ray.dir.z);
00987
00988
00989 int depth=0;
00990
00991 #if ( HAVE_PTHREAD && defined (__GNUC__) )
00992 std::set<const T *, std::less<const T *>, __gnu_cxx::__mt_alloc<const T *> > filtered;
00993 #else
00994 std::set<const T *> filtered;
00995 #endif
00996 rKdStack<T> stack[KD_MAX_STACK];
00997 const rkdTreeNode<T> *farChild, *currNode;
00998 currNode = nodes;
00999
01000 int enPt = 0;
01001 stack[enPt].t = a;
01002
01003
01004 if(a >= 0.0)
01005 stack[enPt].pb = ray.from + ray.dir * a;
01006 else
01007 stack[enPt].pb = ray.from;
01008
01009
01010 int exPt = 1;
01011 stack[exPt].t = b;
01012 stack[exPt].pb = ray.from + ray.dir * b;
01013 stack[exPt].node = 0;
01014
01015
01016 while (currNode != NULL)
01017 {
01018 if (dist < stack[enPt].t ) break;
01019
01020 while( !currNode->IsLeaf() )
01021 {
01022 int axis = currNode->SplitAxis();
01023 PFLOAT splitVal = currNode->SplitPos();
01024
01025 if(stack[enPt].pb[axis] <= splitVal){
01026 if(stack[exPt].pb[axis] <= splitVal)
01027 {
01028 currNode++;
01029 continue;
01030 }
01031 if(stack[exPt].pb[axis] == splitVal)
01032 {
01033 currNode = &nodes[currNode->getRightChild()];
01034 continue;
01035 }
01036
01037 farChild = &nodes[currNode->getRightChild()];
01038 currNode ++;
01039 }
01040 else
01041 {
01042 if(splitVal < stack[exPt].pb[axis])
01043 {
01044 currNode = &nodes[currNode->getRightChild()];
01045 continue;
01046 }
01047 farChild = currNode+1;
01048 currNode = &nodes[currNode->getRightChild()];
01049 }
01050
01051
01052 t = (splitVal - ray.from[axis]) * invDir[axis];
01053
01054
01055 int tmp = exPt;
01056 exPt++;
01057
01058
01059 if (exPt == enPt) exPt++;
01060
01061 static const int npAxis[2][3] = { {1, 2, 0}, {2, 0, 1} };
01062 int nextAxis = npAxis[0][axis];
01063 int prevAxis = npAxis[1][axis];
01064 stack[exPt].prev = tmp;
01065 stack[exPt].t = t;
01066 stack[exPt].node = farChild;
01067 stack[exPt].pb[axis] = splitVal;
01068 stack[exPt].pb[nextAxis] = ray.from[nextAxis] + t * ray.dir[nextAxis];
01069 stack[exPt].pb[prevAxis] = ray.from[prevAxis] + t * ray.dir[prevAxis];
01070 }
01071
01072
01073 u_int32 nPrimitives = currNode->nPrimitives();
01074
01075
01076 if (nPrimitives == 1) {
01077 T *mp = currNode->onePrimitive;
01078 if (mp->intersect(ray, &t_hit, (void*)&udat[0]))
01079 {
01080 if(t_hit < /* tmax */ dist && t_hit >= ray.tmin )
01081 {
01082
01083 const material_t *mat = mp->getMaterial();
01084 if(!mat->isTransparent() ) return true;
01085 if(filtered.insert(mp).second)
01086 {
01087 if(depth>=maxDepth) return true;
01088 point3d_t h=ray.from + t_hit*ray.dir;
01089 surfacePoint_t sp;
01090 mp->getSurface(sp, h, (void*)&udat[0]);
01091 filt *= mat->getTransparency(state, sp, ray.dir);
01092 ++depth;
01093 }
01094 }
01095 }
01096 }
01097 else {
01098 T **prims = currNode->primitives;
01099 for (u_int32 i = 0; i < nPrimitives; ++i) {
01100 T *mp = prims[i];
01101 if (mp->intersect(ray, &t_hit, (void*)&udat[0]))
01102 {
01103 if(t_hit < /* tmax */ dist && t_hit >= ray.tmin )
01104 {
01105
01106 const material_t *mat = mp->getMaterial();
01107 if(!mat->isTransparent() ) return true;
01108 if(filtered.insert(mp).second)
01109 {
01110 if(depth>=maxDepth) return true;
01111 point3d_t h=ray.from + t_hit*ray.dir;
01112 surfacePoint_t sp;
01113 mp->getSurface(sp, h, (void*)&udat[0]);
01114 filt *= mat->getTransparency(state, sp, ray.dir);
01115 ++depth;
01116 }
01117 }
01118 }
01119 }
01120 }
01121
01122
01123
01124 enPt = exPt;
01125 currNode = stack[exPt].node;
01126 exPt = stack[enPt].prev;
01127
01128 }
01129
01130 return false;
01131 }
01132
01133
01134 template class kdTree_t<triangle_t>;
01135 template class kdTree_t<primitive_t>;
01136
01137 __END_YAFRAY