|
Blender
V2.59
|
00001 /* 00002 * $Id: rayobject_rtbuild.cpp 35478 2011-03-11 23:12:58Z blendix $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2009 Blender Foundation. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): André Pinto. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <assert.h> 00036 #include <math.h> 00037 #include <stdlib.h> 00038 #include <algorithm> 00039 00040 #include "rayobject_rtbuild.h" 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #include "BLI_math.h" 00045 #include "BLI_utildefines.h" 00046 00047 static bool selected_node(RTBuilder::Object *node) 00048 { 00049 return node->selected; 00050 } 00051 00052 static void rtbuild_init(RTBuilder *b) 00053 { 00054 b->split_axis = -1; 00055 b->primitives.begin = 0; 00056 b->primitives.end = 0; 00057 b->primitives.maxsize = 0; 00058 00059 for(int i=0; i<RTBUILD_MAX_CHILDS; i++) 00060 b->child_offset[i] = 0; 00061 00062 for(int i=0; i<3; i++) 00063 b->sorted_begin[i] = b->sorted_end[i] = 0; 00064 00065 INIT_MINMAX(b->bb, b->bb+3); 00066 } 00067 00068 RTBuilder* rtbuild_create(int size) 00069 { 00070 RTBuilder *builder = (RTBuilder*) MEM_mallocN( sizeof(RTBuilder), "RTBuilder" ); 00071 RTBuilder::Object *memblock= (RTBuilder::Object*)MEM_mallocN( sizeof(RTBuilder::Object)*size,"RTBuilder.objects"); 00072 00073 00074 rtbuild_init(builder); 00075 00076 builder->primitives.begin = builder->primitives.end = memblock; 00077 builder->primitives.maxsize = size; 00078 00079 for(int i=0; i<3; i++) 00080 { 00081 builder->sorted_begin[i] = (RTBuilder::Object**)MEM_mallocN( sizeof(RTBuilder::Object*)*size,"RTBuilder.sorted_objects"); 00082 builder->sorted_end[i] = builder->sorted_begin[i]; 00083 } 00084 00085 00086 return builder; 00087 } 00088 00089 void rtbuild_free(RTBuilder *b) 00090 { 00091 if(b->primitives.begin) MEM_freeN(b->primitives.begin); 00092 00093 for(int i=0; i<3; i++) 00094 if(b->sorted_begin[i]) 00095 MEM_freeN(b->sorted_begin[i]); 00096 00097 MEM_freeN(b); 00098 } 00099 00100 void rtbuild_add(RTBuilder *b, RayObject *o) 00101 { 00102 float bb[6]; 00103 00104 assert( b->primitives.begin + b->primitives.maxsize != b->primitives.end ); 00105 00106 INIT_MINMAX(bb, bb+3); 00107 RE_rayobject_merge_bb(o, bb, bb+3); 00108 00109 /* skip objects with invalid bounding boxes, nan causes DO_MINMAX 00110 to do nothing, so we get these invalid values. this shouldn't 00111 happen usually, but bugs earlier in the pipeline can cause it. */ 00112 if(bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5]) 00113 return; 00114 /* skip objects with inf bounding boxes */ 00115 if(!finite(bb[0]) || !finite(bb[1]) || !finite(bb[2])) 00116 return; 00117 if(!finite(bb[3]) || !finite(bb[4]) || !finite(bb[5])) 00118 return; 00119 /* skip objects with zero bounding box, they are of no use, and 00120 will give problems in rtbuild_heuristic_object_split later */ 00121 if(bb[0] == bb[3] && bb[1] == bb[4] && bb[2] == bb[5]) 00122 return; 00123 00124 copy_v3_v3(b->primitives.end->bb, bb); 00125 copy_v3_v3(b->primitives.end->bb+3, bb+3); 00126 b->primitives.end->obj = o; 00127 b->primitives.end->cost = RE_rayobject_cost(o); 00128 00129 for(int i=0; i<3; i++) 00130 { 00131 *(b->sorted_end[i]) = b->primitives.end; 00132 b->sorted_end[i]++; 00133 } 00134 b->primitives.end++; 00135 } 00136 00137 int rtbuild_size(RTBuilder *b) 00138 { 00139 return b->sorted_end[0] - b->sorted_begin[0]; 00140 } 00141 00142 00143 template<class Obj,int Axis> 00144 static bool obj_bb_compare(const Obj &a, const Obj &b) 00145 { 00146 if(a->bb[Axis] != b->bb[Axis]) 00147 return a->bb[Axis] < b->bb[Axis]; 00148 return a->obj < b->obj; 00149 } 00150 00151 template<class Item> 00152 static void object_sort(Item *begin, Item *end, int axis) 00153 { 00154 if(axis == 0) return std::sort(begin, end, obj_bb_compare<Item,0> ); 00155 if(axis == 1) return std::sort(begin, end, obj_bb_compare<Item,1> ); 00156 if(axis == 2) return std::sort(begin, end, obj_bb_compare<Item,2> ); 00157 assert(false); 00158 } 00159 00160 void rtbuild_done(RTBuilder *b, RayObjectControl* ctrl) 00161 { 00162 for(int i=0; i<3; i++) 00163 if(b->sorted_begin[i]) 00164 { 00165 if(RE_rayobjectcontrol_test_break(ctrl)) break; 00166 object_sort( b->sorted_begin[i], b->sorted_end[i], i ); 00167 } 00168 } 00169 00170 RayObject* rtbuild_get_primitive(RTBuilder *b, int index) 00171 { 00172 return b->sorted_begin[0][index]->obj; 00173 } 00174 00175 RTBuilder* rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp) 00176 { 00177 rtbuild_init( tmp ); 00178 00179 for(int i=0; i<3; i++) 00180 if(b->sorted_begin[i]) 00181 { 00182 tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child ]; 00183 tmp->sorted_end [i] = b->sorted_begin[i] + b->child_offset[child+1]; 00184 } 00185 else 00186 { 00187 tmp->sorted_begin[i] = 0; 00188 tmp->sorted_end [i] = 0; 00189 } 00190 00191 return tmp; 00192 } 00193 00194 void rtbuild_calc_bb(RTBuilder *b) 00195 { 00196 if(b->bb[0] == 1.0e30f) 00197 { 00198 for(RTBuilder::Object **index = b->sorted_begin[0]; index != b->sorted_end[0]; index++) 00199 RE_rayobject_merge_bb( (*index)->obj , b->bb, b->bb+3); 00200 } 00201 } 00202 00203 void rtbuild_merge_bb(RTBuilder *b, float *min, float *max) 00204 { 00205 rtbuild_calc_bb(b); 00206 DO_MIN(b->bb, min); 00207 DO_MAX(b->bb+3, max); 00208 } 00209 00210 /* 00211 int rtbuild_get_largest_axis(RTBuilder *b) 00212 { 00213 rtbuild_calc_bb(b); 00214 return bb_largest_axis(b->bb, b->bb+3); 00215 } 00216 00217 //Left balanced tree 00218 int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis) 00219 { 00220 int i; 00221 int mleafs_per_child, Mleafs_per_child; 00222 int tot_leafs = rtbuild_size(b); 00223 int missing_leafs; 00224 00225 long long s; 00226 00227 assert(nchilds <= RTBUILD_MAX_CHILDS); 00228 00229 //TODO optimize calc of leafs_per_child 00230 for(s=nchilds; s<tot_leafs; s*=nchilds); 00231 Mleafs_per_child = s/nchilds; 00232 mleafs_per_child = Mleafs_per_child/nchilds; 00233 00234 //split min leafs per child 00235 b->child_offset[0] = 0; 00236 for(i=1; i<=nchilds; i++) 00237 b->child_offset[i] = mleafs_per_child; 00238 00239 //split remaining leafs 00240 missing_leafs = tot_leafs - mleafs_per_child*nchilds; 00241 for(i=1; i<=nchilds; i++) 00242 { 00243 if(missing_leafs > Mleafs_per_child - mleafs_per_child) 00244 { 00245 b->child_offset[i] += Mleafs_per_child - mleafs_per_child; 00246 missing_leafs -= Mleafs_per_child - mleafs_per_child; 00247 } 00248 else 00249 { 00250 b->child_offset[i] += missing_leafs; 00251 missing_leafs = 0; 00252 break; 00253 } 00254 } 00255 00256 //adjust for accumulative offsets 00257 for(i=1; i<=nchilds; i++) 00258 b->child_offset[i] += b->child_offset[i-1]; 00259 00260 //Count created childs 00261 for(i=nchilds; b->child_offset[i] == b->child_offset[i-1]; i--); 00262 split_leafs(b, b->child_offset, i, axis); 00263 00264 assert( b->child_offset[0] == 0 && b->child_offset[i] == tot_leafs ); 00265 return i; 00266 } 00267 00268 00269 int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds) 00270 { 00271 int axis = rtbuild_get_largest_axis(b); 00272 return rtbuild_mean_split(b, nchilds, axis); 00273 } 00274 */ 00275 00276 /* 00277 * "separators" is an array of dim NCHILDS-1 00278 * and indicates where to cut the childs 00279 */ 00280 /* 00281 int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis) 00282 { 00283 int size = rtbuild_size(b); 00284 00285 assert(nchilds <= RTBUILD_MAX_CHILDS); 00286 if(size <= nchilds) 00287 { 00288 return rtbuild_mean_split(b, nchilds, axis); 00289 } 00290 else 00291 { 00292 int i; 00293 00294 b->split_axis = axis; 00295 00296 //Calculate child offsets 00297 b->child_offset[0] = 0; 00298 for(i=0; i<nchilds-1; i++) 00299 b->child_offset[i+1] = split_leafs_by_plane(b, b->child_offset[i], size, separators[i]); 00300 b->child_offset[nchilds] = size; 00301 00302 for(i=0; i<nchilds; i++) 00303 if(b->child_offset[i+1] - b->child_offset[i] == size) 00304 return rtbuild_mean_split(b, nchilds, axis); 00305 00306 return nchilds; 00307 } 00308 } 00309 00310 int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds) 00311 { 00312 int la, i; 00313 float separators[RTBUILD_MAX_CHILDS]; 00314 00315 rtbuild_calc_bb(b); 00316 00317 la = bb_largest_axis(b->bb,b->bb+3); 00318 for(i=1; i<nchilds; i++) 00319 separators[i-1] = (b->bb[la+3]-b->bb[la])*i / nchilds; 00320 00321 return rtbuild_median_split(b, separators, nchilds, la); 00322 } 00323 */ 00324 00325 //Heuristics Object Splitter 00326 00327 00328 struct SweepCost 00329 { 00330 float bb[6]; 00331 float cost; 00332 }; 00333 00334 /* Object Surface Area Heuristic splitter */ 00335 int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) 00336 { 00337 int size = rtbuild_size(b); 00338 assert(nchilds == 2); 00339 assert(size > 1); 00340 int baxis = -1, boffset = 0; 00341 00342 if(size > nchilds) 00343 { 00344 float bcost = FLT_MAX; 00345 baxis = -1, boffset = size/2; 00346 00347 SweepCost *sweep = (SweepCost*)MEM_mallocN( sizeof(SweepCost)*size, "RTBuilder.HeuristicSweep" ); 00348 00349 for(int axis=0; axis<3; axis++) 00350 { 00351 SweepCost sweep_left; 00352 00353 RTBuilder::Object **obj = b->sorted_begin[axis]; 00354 00355 // float right_cost = 0; 00356 for(int i=size-1; i>=0; i--) 00357 { 00358 if(i == size-1) 00359 { 00360 copy_v3_v3(sweep[i].bb, obj[i]->bb); 00361 copy_v3_v3(sweep[i].bb+3, obj[i]->bb+3); 00362 sweep[i].cost = obj[i]->cost; 00363 } 00364 else 00365 { 00366 sweep[i].bb[0] = MIN2(obj[i]->bb[0], sweep[i+1].bb[0]); 00367 sweep[i].bb[1] = MIN2(obj[i]->bb[1], sweep[i+1].bb[1]); 00368 sweep[i].bb[2] = MIN2(obj[i]->bb[2], sweep[i+1].bb[2]); 00369 sweep[i].bb[3] = MAX2(obj[i]->bb[3], sweep[i+1].bb[3]); 00370 sweep[i].bb[4] = MAX2(obj[i]->bb[4], sweep[i+1].bb[4]); 00371 sweep[i].bb[5] = MAX2(obj[i]->bb[5], sweep[i+1].bb[5]); 00372 sweep[i].cost = obj[i]->cost + sweep[i+1].cost; 00373 } 00374 // right_cost += obj[i]->cost; 00375 } 00376 00377 sweep_left.bb[0] = obj[0]->bb[0]; 00378 sweep_left.bb[1] = obj[0]->bb[1]; 00379 sweep_left.bb[2] = obj[0]->bb[2]; 00380 sweep_left.bb[3] = obj[0]->bb[3]; 00381 sweep_left.bb[4] = obj[0]->bb[4]; 00382 sweep_left.bb[5] = obj[0]->bb[5]; 00383 sweep_left.cost = obj[0]->cost; 00384 00385 // right_cost -= obj[0]->cost; if(right_cost < 0) right_cost = 0; 00386 00387 for(int i=1; i<size; i++) 00388 { 00389 //Worst case heuristic (cost of each child is linear) 00390 float hcost, left_side, right_side; 00391 00392 // not using log seems to have no impact on raytracing perf, but 00393 // makes tree construction quicker, left out for now to test (brecht) 00394 // left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost+logf((float)i)); 00395 // right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost+logf((float)size-i)); 00396 left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost); 00397 right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost); 00398 hcost = left_side+right_side; 00399 00400 assert(left_side >= 0); 00401 assert(right_side >= 0); 00402 00403 if(left_side > bcost) break; //No way we can find a better heuristic in this axis 00404 00405 assert(hcost >= 0); 00406 if( hcost < bcost 00407 || (hcost == bcost && axis < baxis)) //this makes sure the tree built is the same whatever is the order of the sorting axis 00408 { 00409 bcost = hcost; 00410 baxis = axis; 00411 boffset = i; 00412 } 00413 DO_MIN( obj[i]->bb, sweep_left.bb ); 00414 DO_MAX( obj[i]->bb+3, sweep_left.bb+3 ); 00415 00416 sweep_left.cost += obj[i]->cost; 00417 // right_cost -= obj[i]->cost; if(right_cost < 0) right_cost = 0; 00418 } 00419 00420 //assert(baxis >= 0 && baxis < 3); 00421 if (!(baxis >= 0 && baxis < 3)) 00422 baxis = 0; 00423 } 00424 00425 00426 MEM_freeN(sweep); 00427 } 00428 else if(size == 2) 00429 { 00430 baxis = 0; 00431 boffset = 1; 00432 } 00433 else if(size == 1) 00434 { 00435 b->child_offset[0] = 0; 00436 b->child_offset[1] = 1; 00437 return 1; 00438 } 00439 00440 b->child_offset[0] = 0; 00441 b->child_offset[1] = boffset; 00442 b->child_offset[2] = size; 00443 00444 00445 /* Adjust sorted arrays for childs */ 00446 for(int i=0; i<boffset; i++) b->sorted_begin[baxis][i]->selected = true; 00447 for(int i=boffset; i<size; i++) b->sorted_begin[baxis][i]->selected = false; 00448 for(int i=0; i<3; i++) 00449 std::stable_partition( b->sorted_begin[i], b->sorted_end[i], selected_node ); 00450 00451 return nchilds; 00452 } 00453 00454 /* 00455 * Helper code 00456 * PARTITION code / used on mean-split 00457 * basicly this a std::nth_element (like on C++ STL algorithm) 00458 */ 00459 /* 00460 static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis) 00461 { 00462 int i; 00463 b->split_axis = split_axis; 00464 00465 for(i=0; i < partitions-1; i++) 00466 { 00467 assert(nth[i] < nth[i+1] && nth[i+1] < nth[partitions]); 00468 00469 if(split_axis == 0) std::nth_element(b, nth[i], nth[i+1], nth[partitions], obj_bb_compare<RTBuilder::Object,0>); 00470 if(split_axis == 1) std::nth_element(b, nth[i], nth[i+1], nth[partitions], obj_bb_compare<RTBuilder::Object,1>); 00471 if(split_axis == 2) std::nth_element(b, nth[i], nth[i+1], nth[partitions], obj_bb_compare<RTBuilder::Object,2>); 00472 } 00473 } 00474 */ 00475 00476 /* 00477 * Bounding Box utils 00478 */ 00479 float bb_volume(float *min, float *max) 00480 { 00481 return (max[0]-min[0])*(max[1]-min[1])*(max[2]-min[2]); 00482 } 00483 00484 float bb_area(float *min, float *max) 00485 { 00486 float sub[3], a; 00487 sub[0] = max[0]-min[0]; 00488 sub[1] = max[1]-min[1]; 00489 sub[2] = max[2]-min[2]; 00490 00491 a = (sub[0]*sub[1] + sub[0]*sub[2] + sub[1]*sub[2])*2; 00492 /* used to have an assert() here on negative results 00493 * however, in this case its likely some overflow or ffast math error. 00494 * so just return 0.0f instead. */ 00495 return a < 0.0f ? 0.0f : a; 00496 } 00497 00498 int bb_largest_axis(float *min, float *max) 00499 { 00500 float sub[3]; 00501 00502 sub[0] = max[0]-min[0]; 00503 sub[1] = max[1]-min[1]; 00504 sub[2] = max[2]-min[2]; 00505 if(sub[0] > sub[1]) 00506 { 00507 if(sub[0] > sub[2]) 00508 return 0; 00509 else 00510 return 2; 00511 } 00512 else 00513 { 00514 if(sub[1] > sub[2]) 00515 return 1; 00516 else 00517 return 2; 00518 } 00519 } 00520 00521 int bb_fits_inside(float *outer_min, float *outer_max, float *inner_min, float *inner_max) 00522 { 00523 int i; 00524 for(i=0; i<3; i++) 00525 if(outer_min[i] > inner_min[i]) return 0; 00526 00527 for(i=0; i<3; i++) 00528 if(outer_max[i] < inner_max[i]) return 0; 00529 00530 return 1; 00531 }