diff --git a/source/blender/render/extern/include/RE_raytrace.h b/source/blender/render/extern/include/RE_raytrace.h index b1d8abef766..0f92f54b396 100644 --- a/source/blender/render/extern/include/RE_raytrace.h +++ b/source/blender/render/extern/include/RE_raytrace.h @@ -47,7 +47,7 @@ void RE_rayobject_free(RayObject *r); /* RayObject constructors */ RayObject* RE_rayobject_octree_create(int ocres, int size); -RayObject* RE_rayobject_bvh_create(int size); +RayObject* RE_rayobject_blibvh_create(int size); RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob); //RayObject* RayObject_derivedmesh_create(struct DerivedMesh*, void *ob); @@ -59,8 +59,13 @@ struct Isect float start[3]; float vec[3]; float labda; + + /* length of vec, configured by RE_rayobject_raycast */ + int bv_index[6]; + float idot_axis[3]; + float dist; - float dist; /* length of vec, configured by RE_rayobject_raycast */ + /* float end[3]; - not used */ float u, v; diff --git a/source/blender/render/intern/include/rayobject_rtbuild.h b/source/blender/render/intern/include/rayobject_rtbuild.h new file mode 100644 index 00000000000..b1458a571dd --- /dev/null +++ b/source/blender/render/intern/include/rayobject_rtbuild.h @@ -0,0 +1,84 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef RE_RAYOBJECT_RTBUILD_H +#define RE_RAYOBJECT_RTBUILD_H + +#include "rayobject.h" + +/* + * Ray Tree Builder + * this structs helps building any type of tree + * it contains several methods to organiza/split nodes + * allowing to create a given tree on the fly. + * + * Idea is that other trees BVH, BIH can use this code to + * generate with simple calls, and then convert to the theirs + * specific structure on the fly. + */ +#define MAX_CHILDS 32 +typedef struct RTBuilder +{ + /* list to all primitives in this tree */ + RayObject **begin, **end; + + /* axis used (if any) on the split method */ + int split_axis; + + /* links to child partitions calculated during splitting */ + RayObject **child[MAX_CHILDS+1]; + +} RTBuilder; + +/* used during creation */ +RTBuilder* rtbuild_create(int size); +void rtbuild_free(RTBuilder *b); +void rtbuild_add(RTBuilder *b, RayObject *o); +int rtbuild_size(RTBuilder *b); + +/* used during tree reorganization */ +RTBuilder* rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp); +void rtbuild_mean_split(RTBuilder *b, int nchilds, int axis); +void rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds); + +/* +static BVHNode *bvh_rearrange(BVHTree *tree, RTBuilder *b) +{ + int i; + int nc = rtbuild_mean_split_largest_axis(b, BVH_NCHILDS); + RTBuilder tmp; + + BVHNode *bvh = tree->next_node++; + + bvh->split_axis = tmp->split_axis; + for(i=0; ichild[i] = bvh_rearrange( rtbuild_get_child(b, i, &tmp) ); +} + */ + +#endif diff --git a/source/blender/render/intern/source/rayobject_bvh.c b/source/blender/render/intern/source/rayobject_blibvh.c similarity index 78% rename from source/blender/render/intern/source/rayobject_bvh.c rename to source/blender/render/intern/source/rayobject_blibvh.c index 54fbc5ba0be..41da4679b6a 100644 --- a/source/blender/render/intern/source/rayobject_bvh.c +++ b/source/blender/render/intern/source/rayobject_blibvh.c @@ -36,19 +36,19 @@ #include "render_types.h" #include "rayobject.h" -static int RayObject_bvh_intersect(RayObject *o, Isect *isec); -static void RayObject_bvh_add(RayObject *o, RayObject *ob); -static void RayObject_bvh_done(RayObject *o); -static void RayObject_bvh_free(RayObject *o); -static void RayObject_bvh_bb(RayObject *o, float *min, float *max); +static int RayObject_blibvh_intersect(RayObject *o, Isect *isec); +static void RayObject_blibvh_add(RayObject *o, RayObject *ob); +static void RayObject_blibvh_done(RayObject *o); +static void RayObject_blibvh_free(RayObject *o); +static void RayObject_blibvh_bb(RayObject *o, float *min, float *max); static RayObjectAPI bvh_api = { - RayObject_bvh_intersect, - RayObject_bvh_add, - RayObject_bvh_done, - RayObject_bvh_free, - RayObject_bvh_bb + RayObject_blibvh_intersect, + RayObject_blibvh_add, + RayObject_blibvh_done, + RayObject_blibvh_free, + RayObject_blibvh_bb }; typedef struct BVHObject @@ -60,7 +60,7 @@ typedef struct BVHObject } BVHObject; -RayObject *RE_rayobject_bvh_create(int size) +RayObject *RE_rayobject_blibvh_create(int size) { BVHObject *obj= (BVHObject*)MEM_callocN(sizeof(BVHObject), "BVHObject"); assert( RayObject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */ @@ -88,7 +88,7 @@ static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTr } } -static int RayObject_bvh_intersect(RayObject *o, Isect *isec) +static int RayObject_blibvh_intersect(RayObject *o, Isect *isec) { BVHObject *obj = (BVHObject*)o; BVHTreeRayHit hit; @@ -103,7 +103,7 @@ static int RayObject_bvh_intersect(RayObject *o, Isect *isec) return BLI_bvhtree_ray_cast(obj->bvh, isec->start, dir, 0.0, &hit, bvh_callback, isec); } -static void RayObject_bvh_add(RayObject *o, RayObject *ob) +static void RayObject_blibvh_add(RayObject *o, RayObject *ob) { BVHObject *obj = (BVHObject*)o; float min_max[6]; @@ -116,13 +116,13 @@ static void RayObject_bvh_add(RayObject *o, RayObject *ob) BLI_bvhtree_insert(obj->bvh, (int)ob, min_max, 2 ); } -static void RayObject_bvh_done(RayObject *o) +static void RayObject_blibvh_done(RayObject *o) { BVHObject *obj = (BVHObject*)o; BLI_bvhtree_balance(obj->bvh); } -static void RayObject_bvh_free(RayObject *o) +static void RayObject_blibvh_free(RayObject *o) { BVHObject *obj = (BVHObject*)o; @@ -132,7 +132,7 @@ static void RayObject_bvh_free(RayObject *o) MEM_freeN(obj); } -static void RayObject_bvh_bb(RayObject *o, float *min, float *max) +static void RayObject_blibvh_bb(RayObject *o, float *min, float *max) { BVHObject *obj = (BVHObject*)o; DO_MINMAX( obj->bb[0], min, max ); diff --git a/source/blender/render/intern/source/rayobject_rtbuild.c b/source/blender/render/intern/source/rayobject_rtbuild.c new file mode 100644 index 00000000000..b89729e2b45 --- /dev/null +++ b/source/blender/render/intern/source/rayobject_rtbuild.c @@ -0,0 +1,222 @@ +#include "rayobject_rtbuild.h" +#include "MEM_guardedalloc.h" +#include "BLI_arithb.h" +#include "BKE_utildefines.h" + +static int partition_nth_element(RTBuilder *b, int _begin, int _end, int n); +static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis); + + +static void RayObject_rtbuild_init(RTBuilder *b, RayObject **begin, RayObject **end) +{ + int i; + + b->begin = begin; + b->end = end; + b->split_axis = 0; + + for(i=0; ichild[i] = 0; +} + +RTBuilder* RayObject_rtbuild_create(int size) +{ + RTBuilder *builder = (RTBuilder*) MEM_mallocN( sizeof(RTBuilder), "RTBuilder" ); + RayObject **memblock= (RayObject**)MEM_mallocN( sizeof(RayObject*),"RTBuilder.objects"); + RayObject_rtbuild_init(builder, memblock, memblock); + return builder; +} + +void RayObject_rtbuild_free(RTBuilder *b) +{ + MEM_freeN(b->begin); + MEM_freeN(b); +} + +void RayObject_rtbuild_add(RTBuilder *b, RayObject *o) +{ + *(b->end++) = o; +} + +RTBuilder* rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp) +{ + RayObject_rtbuild_init( tmp, b->child[child], b->child[child+1] ); + return tmp; +} + +int RayObject_rtbuild_size(RTBuilder *b) +{ + return b->end - b->begin; +} + +/* Split methods */ +static void merge_bb(RTBuilder *b, float *min, float *max) +{ + RayObject **index = b->begin; + + for(; index != b->end; index++) + RE_rayobject_merge_bb(*index, min, max); +} + +static int calc_largest_axis(RTBuilder *b) +{ + float min[3], max[3], sub[3]; + + INIT_MINMAX(min, max); + merge_bb( b, min, max); + + VECSUB(sub, max, min); + if(sub[0] > sub[1]) + { + if(sub[0] > sub[2]) + return 0; + else + return 2; + } + else + { + if(sub[1] > sub[2]) + return 1; + else + return 2; + } +} + + +//Unballanced mean +//TODO better balance nodes +//TODO suport for variable number of partitions (its hardcoded in 2) +void rtbuild_mean_split(RTBuilder *b, int nchilds, int axis) +{ + int nth[3] = {0, (b->end - b->begin)/2, b->end-b->begin}; + split_leafs(b, nth, 2, axis); +} + + +void rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds) +{ + int axis = calc_largest_axis(b); + rtbuild_mean_split(b, nchilds, axis); +} + + +/* + * Helper code + * PARTITION code / used on mean-split + * basicly this a std::nth_element (like on C++ STL algorithm) + */ +static void sort_swap(RTBuilder *b, int i, int j) +{ + SWAP(RayObject*, b->begin[i], b->begin[j]); +} + +static int sort_get_value(RTBuilder *b, int i) +{ + float min[3], max[3]; + RE_rayobject_merge_bb(b->begin[i], min, max); + return max[i]; +} + +static int medianof3(RTBuilder *d, int a, int b, int c) +{ + float fa = sort_get_value( d, a ); + float fb = sort_get_value( d, b ); + float fc = sort_get_value( d, c ); + + if(fb < fa) + { + if(fc < fb) + return b; + else + { + if(fc < fa) + return c; + else + return a; + } + } + else + { + if(fc > fb) + return b; + else + { + if(fc > fa) + return c; + else + return a; + } + } +} + +static void insertionsort(RTBuilder *b, int lo, int hi) +{ + int i; + for(i=lo; ibegin[i]; + float tv= sort_get_value(b, i); + int j=i; + + while( j != lo && tv < sort_get_value(b, j-1)) + { + b->begin[j] = b->begin[j-1]; + j--; + } + b->begin[j] = t; + } +} + +static int partition(RTBuilder *b, int lo, int mid, int hi) +{ + float x = sort_get_value( b, mid ); + + int i=lo, j=hi; + while (1) + { + while (sort_get_value(b,i) < x) i++; + j--; + while (x < sort_get_value(b,j)) j--; + if(!(i < j)) + return i; + + sort_swap(b, i, j); + i++; + } +} + +// +// PARTITION code / used on mean-split +// basicly this is an adapted std::nth_element (C++ STL ) +// +// after a call to this function you can expect one of: +// every node to left of a[n] are smaller or equal to it +// every node to the right of a[n] are greater or equal to it +static int partition_nth_element(RTBuilder *b, int _begin, int _end, int n) +{ + int begin = _begin, end = _end, cut; + while(end-begin > 3) + { + cut = partition(b, begin, medianof3(b, begin, begin+(end-begin)/2, end-1), end); + if(cut <= n) + begin = cut; + else + end = cut; + } + insertionsort(b, begin, end); + + return n; +} + +static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis) +{ + int i; + b->split_axis = split_axis; + for(i=0; i < partitions-1; i++) + { + if(nth[i] >= nth[partitions]) + break; + + partition_nth_element(b, nth[i], nth[i+1], nth[partitions] ); + } +} diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 975de3a5da3..75c93fc1c80 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -180,7 +180,7 @@ RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi) if(re->r.raystructure == R_RAYSTRUCTURE_HIER_BVH_OCTREE) raytree = obr->raytree = RE_rayobject_octree_create( re->r.ocres, faces ); else //if(re->r.raystructure == R_RAYSTRUCTURE_HIER_BVH_BVH) - raytree = obr->raytree = RE_rayobject_bvh_create( faces ); + raytree = obr->raytree = RE_rayobject_blibvh_create( faces ); face = obr->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "ObjectRen faces"); obr->rayobi = obi; @@ -240,7 +240,7 @@ static void makeraytree_hier(Render *re) num_objects++; //Create raytree - re->raytree = RE_rayobject_bvh_create( num_objects ); + re->raytree = RE_rayobject_blibvh_create( num_objects ); for(obi=re->instancetable.first; obi; obi=obi->next) if(is_raytraceable(re, obi)) @@ -292,7 +292,7 @@ static void makeraytree_single(Render *re) if(re->r.raystructure == R_RAYSTRUCTURE_SINGLE_OCTREE) raytree = re->raytree = RE_rayobject_octree_create( re->r.ocres, faces ); else //if(re->r.raystructure == R_RAYSTRUCTURE_SINGLE_BVH) - raytree = re->raytree = RE_rayobject_bvh_create( faces ); + raytree = re->raytree = RE_rayobject_blibvh_create( faces ); face = re->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "Render ray faces");