Blender V2.61 - r43446

rayobject_rtbuild.cpp

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