Blender  V2.59
rayobject_rtbuild.cpp
Go to the documentation of this file.
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 }