Added several comments to BLI_kdopbvh
Changed BENCH to print both wall-clock/real time and cpu time
This commit is contained in:
@@ -63,43 +63,26 @@
|
||||
#if 1
|
||||
|
||||
|
||||
#if 0
|
||||
#define BENCH(a) \
|
||||
do { \
|
||||
clock_t _clock_init = clock(); \
|
||||
(a); \
|
||||
printf("%s: %fms\n", #a, (float)(clock()-_clock_init)*1000/CLOCKS_PER_SEC); \
|
||||
} while(0)
|
||||
|
||||
#define BENCH_VAR(name) clock_t JOIN(_bench_step,name) = 0, JOIN(_bench_total,name) = 0
|
||||
#define BENCH_BEGIN(name) JOIN(_bench_step, name) = clock()
|
||||
#define BENCH_END(name) JOIN(_bench_total,name) += clock() - JOIN(_bench_step,name)
|
||||
#define BENCH_RESET(name) JOIN(_bench_total, name) = 0
|
||||
#define BENCH_REPORT(name) printf("%s: %fms\n", TO_STR(name), JOIN(_bench_total,name)*1000.0f/CLOCKS_PER_SEC)
|
||||
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
|
||||
#define BENCH(a) \
|
||||
do { \
|
||||
double _t1, _t2; \
|
||||
struct timeval _tstart, _tend; \
|
||||
clock_t _clock_init = clock(); \
|
||||
gettimeofday ( &_tstart, NULL); \
|
||||
(a); \
|
||||
gettimeofday ( &_tend, NULL); \
|
||||
_t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 ); \
|
||||
_t2 = ( double ) _tend.tv_sec + ( double ) _tend.tv_usec/ ( 1000*1000 ); \
|
||||
printf("%s: %fms\n", #a, _t2-_t1);\
|
||||
printf("%s: %fs (real) %fs (cpu)\n", #a, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\
|
||||
} while(0)
|
||||
|
||||
#define BENCH_VAR(name) clock_t JOIN(_bench_step,name) = 0, JOIN(_bench_total,name) = 0
|
||||
#define BENCH_BEGIN(name) JOIN(_bench_step, name) = clock()
|
||||
#define BENCH_END(name) JOIN(_bench_total,name) += clock() - JOIN(_bench_step,name)
|
||||
#define BENCH_RESET(name) JOIN(_bench_total, name) = 0
|
||||
#define BENCH_REPORT(name) printf("%s: %fms\n", TO_STR(name), JOIN(_bench_total,name)*1000.0f/CLOCKS_PER_SEC)
|
||||
|
||||
|
||||
#endif
|
||||
#define BENCH_REPORT(name) printf("%s: %fms (cpu) \n", TO_STR(name), JOIN(_bench_total,name)*1000.0f/CLOCKS_PER_SEC)
|
||||
|
||||
#else
|
||||
|
||||
@@ -1109,12 +1092,11 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
|
||||
|
||||
if(index != -1)
|
||||
{
|
||||
float dist;
|
||||
float dist = nearest.dist;
|
||||
if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist;
|
||||
|
||||
VECCOPY(tmp_co, nearest.co);
|
||||
space_transform_invert(&calc->local2target, tmp_co);
|
||||
|
||||
dist = VecLenf(co, tmp_co);
|
||||
if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist;
|
||||
VecLerpf(co, co, tmp_co, weight); //linear interpolation
|
||||
}
|
||||
}
|
||||
@@ -1349,7 +1331,7 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
|
||||
}
|
||||
else
|
||||
{
|
||||
float dist = VecLenf(tmp_co, nearest.co);
|
||||
float dist = sasqrt( nearest.dist );
|
||||
VecLerpf(tmp_co, tmp_co, nearest.co, (dist - calc->keptDist)/dist); //linear interpolation
|
||||
}
|
||||
space_transform_invert(&calc->local2target, tmp_co);
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
|
||||
typedef struct BVHNode
|
||||
{
|
||||
struct BVHNode **children; // max 8 children
|
||||
struct BVHNode **children;
|
||||
float *bv; // Bounding volume of all nodes, max 13 axis
|
||||
int index; // face, edge, vertex index
|
||||
char totnode; // how many nodes are used, used for speedup
|
||||
char main_axis;
|
||||
char main_axis; // Axis used to split this node
|
||||
} BVHNode;
|
||||
|
||||
struct BVHTree
|
||||
@@ -281,139 +281,9 @@ int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis){
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BLI_bvhtree_free(BVHTree *tree)
|
||||
{
|
||||
if(tree)
|
||||
{
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree->nodearray);
|
||||
MEM_freeN(tree->nodebv);
|
||||
MEM_freeN(tree->nodechild);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate max number of branches
|
||||
int needed_branches(int tree_type, int leafs)
|
||||
{
|
||||
#if 1
|
||||
//Worst case scenary ( return max(0, leafs-tree_type)+1 )
|
||||
if(leafs <= tree_type)
|
||||
return 1;
|
||||
else
|
||||
return leafs-tree_type+1;
|
||||
|
||||
#else
|
||||
//If our bvh kdop is "almost perfect"
|
||||
//TODO i dont trust the float arithmetic in here (and I am not sure this formula is according to our splitting method)
|
||||
int i, numbranches = 0;
|
||||
for(i = 1; i <= (int)ceil((float)((float)log(leafs)/(float)log(tree_type))); i++)
|
||||
numbranches += (pow(tree_type, i) / tree_type);
|
||||
|
||||
return numbranches;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
{
|
||||
BVHTree *tree;
|
||||
int numnodes, i;
|
||||
|
||||
// theres not support for trees below binary-trees :P
|
||||
if(tree_type < 2)
|
||||
return NULL;
|
||||
|
||||
tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree");
|
||||
|
||||
if(tree)
|
||||
{
|
||||
tree->epsilon = epsilon;
|
||||
tree->tree_type = tree_type;
|
||||
tree->axis = axis;
|
||||
|
||||
if(axis == 26)
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 13;
|
||||
}
|
||||
else if(axis == 18)
|
||||
{
|
||||
tree->start_axis = 7;
|
||||
tree->stop_axis = 13;
|
||||
}
|
||||
else if(axis == 14)
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 7;
|
||||
}
|
||||
else if(axis == 8) // AABB
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 4;
|
||||
}
|
||||
else if(axis == 6) // OBB
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//Allocate arrays
|
||||
numnodes = maxsize + needed_branches(tree_type, maxsize) + tree_type;
|
||||
|
||||
tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*numnodes, "BVHNodes");
|
||||
|
||||
if(!tree->nodes)
|
||||
{
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * numnodes, "BVHNodeBV");
|
||||
if(!tree->nodebv)
|
||||
{
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
tree->nodechild = (BVHNode**)MEM_callocN(sizeof(BVHNode*) * tree_type * numnodes, "BVHNodeBV");
|
||||
if(!tree->nodechild)
|
||||
{
|
||||
MEM_freeN(tree->nodebv);
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)* numnodes, "BVHNodeArray");
|
||||
|
||||
if(!tree->nodearray)
|
||||
{
|
||||
MEM_freeN(tree->nodechild);
|
||||
MEM_freeN(tree->nodebv);
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//link the dynamic bv and child links
|
||||
for(i=0; i< numnodes; i++)
|
||||
{
|
||||
tree->nodearray[i].bv = tree->nodebv + i * axis;
|
||||
tree->nodearray[i].children = tree->nodechild + i * tree_type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BVHTree bounding volumes functions
|
||||
*/
|
||||
static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoints, int moving)
|
||||
{
|
||||
float newminmax;
|
||||
@@ -475,36 +345,6 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end)
|
||||
|
||||
}
|
||||
|
||||
int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints)
|
||||
{
|
||||
int i;
|
||||
BVHNode *node = NULL;
|
||||
|
||||
// insert should only possible as long as tree->totbranch is 0
|
||||
if(tree->totbranch > 0)
|
||||
return 0;
|
||||
|
||||
if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)/sizeof(*(tree->nodes)))
|
||||
return 0;
|
||||
|
||||
// TODO check if have enough nodes in array
|
||||
|
||||
node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||
tree->totleaf++;
|
||||
|
||||
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||
node->index= index;
|
||||
|
||||
// inflate the bv with some epsilon
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// only supports x,y,z axis in the moment
|
||||
// but we should use a plain and simple function here for speed sake
|
||||
static char get_largest_axis(float *bv)
|
||||
@@ -530,109 +370,42 @@ static char get_largest_axis(float *bv)
|
||||
}
|
||||
}
|
||||
|
||||
static void bvh_div_nodes(BVHTree *tree, BVHNode *node, int start, int end, int free_node_index)
|
||||
// bottom-up update of bvh node BV
|
||||
// join the children on the parent BV
|
||||
static void node_join(BVHTree *tree, BVHNode *node)
|
||||
{
|
||||
int i;
|
||||
|
||||
const char laxis = get_largest_axis(node->bv); //determine longest axis to split along
|
||||
const int slice = (end-start)/tree->tree_type; //division rounded down
|
||||
const int rest = (end-start)%tree->tree_type; //remainder of division
|
||||
int i, j;
|
||||
|
||||
assert( node->totnode == 0 );
|
||||
|
||||
node->main_axis = laxis/2;
|
||||
|
||||
// split nodes along longest axis
|
||||
for (i=0; start < end; node->totnode = ++i) //i counts the current child
|
||||
{
|
||||
int tend = start + slice + (i < rest ? 1 : 0);
|
||||
|
||||
assert( tend <= end);
|
||||
|
||||
if(tend-start == 1) // ok, we have 1 left for this node
|
||||
{
|
||||
node->children[i] = tree->nodes[start];
|
||||
}
|
||||
else
|
||||
{
|
||||
BVHNode *tnode = node->children[i] = tree->nodes[free_node_index] = &(tree->nodearray[free_node_index]);
|
||||
|
||||
if(tend != end)
|
||||
partition_nth_element(tree->nodes, start, end, tend, laxis);
|
||||
|
||||
refit_kdop_hull(tree, tnode, start, tend);
|
||||
|
||||
bvh_div_nodes(tree, tnode, start, tend, free_node_index+1);
|
||||
free_node_index += needed_branches(tree->tree_type, tend-start);
|
||||
}
|
||||
start = tend;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void omp_bvh_div_nodes(BVHTree *tree, BVHNode *node, int start, int end, int free_node_index)
|
||||
{
|
||||
int i;
|
||||
|
||||
const char laxis = get_largest_axis(node->bv); //determine longest axis to split along
|
||||
const int slice = (end-start)/tree->tree_type; //division rounded down
|
||||
const int rest = (end-start)%tree->tree_type; //remainder of division
|
||||
|
||||
int omp_data_start[tree->tree_type];
|
||||
int omp_data_end [tree->tree_type];
|
||||
int omp_data_index[tree->tree_type];
|
||||
|
||||
assert( node->totnode == 0 );
|
||||
|
||||
node->main_axis = laxis/2;
|
||||
|
||||
// split nodes along longest axis
|
||||
for (i=0; start < end; node->totnode = ++i) //i counts the current child
|
||||
{
|
||||
//Split the rest from left to right (TODO: this doenst makes an optimal tree)
|
||||
int tend = start + slice + (i < rest ? 1 : 0);
|
||||
|
||||
assert( tend <= end);
|
||||
|
||||
//save data for later OMP
|
||||
omp_data_start[i] = start;
|
||||
omp_data_end [i] = tend;
|
||||
omp_data_index[i] = free_node_index;
|
||||
|
||||
if(tend-start == 1)
|
||||
{
|
||||
node->children[i] = tree->nodes[start];
|
||||
}
|
||||
else
|
||||
{
|
||||
node->children[i] = tree->nodes[free_node_index] = &(tree->nodearray[free_node_index]);
|
||||
|
||||
if(tend != end)
|
||||
partition_nth_element(tree->nodes, start, end, tend, laxis);
|
||||
|
||||
free_node_index += needed_branches(tree->tree_type, tend-start);
|
||||
}
|
||||
|
||||
start = tend;
|
||||
}
|
||||
|
||||
#pragma omp parallel for private(i) schedule(static)
|
||||
for( i = 0; i < node->totnode; i++)
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
if(omp_data_end[i]-omp_data_start[i] > 1)
|
||||
{
|
||||
BVHNode *tnode = node->children[i];
|
||||
refit_kdop_hull(tree, tnode, omp_data_start[i], omp_data_end[i]);
|
||||
bvh_div_nodes (tree, tnode, omp_data_start[i], omp_data_end[i], omp_data_index[i]+1);
|
||||
}
|
||||
node->bv[2*i] = FLT_MAX;
|
||||
node->bv[2*i + 1] = -FLT_MAX;
|
||||
}
|
||||
|
||||
return;
|
||||
for (i = 0; i < tree->tree_type; i++)
|
||||
{
|
||||
if (node->children[i])
|
||||
{
|
||||
for (j = tree->start_axis; j < tree->stop_axis; j++)
|
||||
{
|
||||
// update minimum
|
||||
if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)])
|
||||
node->bv[(2 * j)] = node->children[i]->bv[(2 * j)];
|
||||
|
||||
// update maximum
|
||||
if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1])
|
||||
node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void print_tree(BVHTree *tree, BVHNode *node, int depth)
|
||||
/*
|
||||
* Debug and information functions
|
||||
*/
|
||||
static void bvhtree_print_tree(BVHTree *tree, BVHNode *node, int depth)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<depth; i++) printf(" ");
|
||||
@@ -643,11 +416,30 @@ static void print_tree(BVHTree *tree, BVHNode *node, int depth)
|
||||
|
||||
for(i=0; i<tree->tree_type; i++)
|
||||
if(node->children[i])
|
||||
print_tree(tree, node->children[i], depth+1);
|
||||
bvhtree_print_tree(tree, node->children[i], depth+1);
|
||||
}
|
||||
|
||||
static void bvhtree_info(BVHTree *tree)
|
||||
{
|
||||
printf("BVHTree info\n");
|
||||
printf("tree_type = %d, axis = %d, epsilon = %f\n", tree->tree_type, tree->axis, tree->epsilon);
|
||||
printf("nodes = %d, branches = %d, leafs = %d\n", tree->totbranch + tree->totleaf, tree->totbranch, tree->totleaf);
|
||||
printf("Memory per node = %dbytes\n", sizeof(BVHNode) + sizeof(BVHNode*)*tree->tree_type + sizeof(float)*tree->axis);
|
||||
printf("BV memory = %dbytes\n", MEM_allocN_len(tree->nodebv));
|
||||
|
||||
printf("Total memory = %dbytes\n", sizeof(BVHTree)
|
||||
+ MEM_allocN_len(tree->nodes)
|
||||
+ MEM_allocN_len(tree->nodearray)
|
||||
+ MEM_allocN_len(tree->nodechild)
|
||||
+ MEM_allocN_len(tree->nodebv)
|
||||
);
|
||||
|
||||
// bvhtree_print_tree(tree, tree->nodes[tree->totleaf], 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
static void verify_tree(BVHTree *tree)
|
||||
{
|
||||
int i, j, check = 0;
|
||||
@@ -696,8 +488,8 @@ static void verify_tree(BVHTree *tree)
|
||||
}
|
||||
#endif
|
||||
|
||||
//Helper data and structures to build generalized implicit trees
|
||||
//This code can be easily reduced
|
||||
//Helper data and structures to build a min-leaf generalized implicit tree
|
||||
//This code can be easily reduced (basicly this is only method to calculate pow(k, n) in O(1).. and sutff like that)
|
||||
typedef struct BVHBuildHelper
|
||||
{
|
||||
int tree_type; //
|
||||
@@ -752,52 +544,141 @@ static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index
|
||||
return data->remain_leafs;
|
||||
}
|
||||
|
||||
//WARNING: Beautiful/tricky code starts here :P
|
||||
//Generalized implicit trees
|
||||
static void non_recursive_bvh_div_nodes(BVHTree *tree)
|
||||
/**
|
||||
* Generalized implicit tree build
|
||||
*
|
||||
* An implicit tree is a tree where its structure is implied, thus there is no need to store child pointers or indexs.
|
||||
* Its possible to find the position of the child or the parent with simple maths (multiplication and adittion). This type
|
||||
* of tree is for example used on heaps.. where node N has its childs at indexs N*2 and N*2+1.
|
||||
*
|
||||
* Altought in this case the tree type is general.. and not know until runtime.
|
||||
* tree_type stands for the maximum number of childs that a tree node can have.
|
||||
* All tree types >= 2 are supported.
|
||||
*
|
||||
* Advantages of the used trees include:
|
||||
* - No need to store child/parent relations (they are implicit);
|
||||
* - Any node child always has an index greater than the parent;
|
||||
* - Brother nodes are sequencial in memory;
|
||||
*
|
||||
*
|
||||
* Some math relations derived for general implicit trees:
|
||||
*
|
||||
* K = tree_type, ( 2 <= K )
|
||||
* ROOT = 1
|
||||
* N child of node A = A * K + (2 - K) + N, (0 <= N < K)
|
||||
*
|
||||
* Util methods:
|
||||
* TODO...
|
||||
* (looping elements, knowing if its a leaf or not.. etc...)
|
||||
*/
|
||||
|
||||
// This functions returns the number of branches needed to have the requested number of leafs.
|
||||
static int implicit_needed_branches(int tree_type, int leafs)
|
||||
{
|
||||
return MAX2(1, (leafs + tree_type - 3) / (tree_type-1) );
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the problem of "sorting" the leafs (along the split_axis).
|
||||
*
|
||||
* It arranges the elements in the given partitions such that:
|
||||
* - any element in partition N is less or equal to any element in partition N+1.
|
||||
* - if all elements are diferent all partition will get the same subset of elements
|
||||
* as if the array was sorted.
|
||||
*
|
||||
* partition P is described as the elements in the range ( nth[P] , nth[P+1] ]
|
||||
*
|
||||
* TODO: This can be optimized a bit by doing a specialized nth_element instead of K nth_elements
|
||||
*/
|
||||
static void split_leafs(BVHNode **leafs_array, int *nth, int partitions, int split_axis)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i < partitions-1; i++)
|
||||
{
|
||||
if(nth[i] >= nth[partitions])
|
||||
break;
|
||||
|
||||
partition_nth_element(leafs_array, nth[i], nth[partitions], nth[i+1], split_axis);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions builds an optimal implicit tree from the given leafs.
|
||||
* Where optimal stands for:
|
||||
* - The resulting tree will have the smallest number of branches;
|
||||
* - At most only one branch will have NULL childs;
|
||||
* - All leafs will be stored at level N or N+1.
|
||||
*
|
||||
* This function creates an implicit tree on branches_array, the leafs are given on the leafs_array.
|
||||
*
|
||||
* The tree is built per depth levels. First branchs at depth 1.. then branches at depth 2.. etc..
|
||||
* The reason is that we can build level N+1 from level N witouth any data dependencies.. thus it allows
|
||||
* to use multithread building.
|
||||
*
|
||||
* To archieve this is necessary to find how much leafs are accessible from a certain branch, BVHBuildHelper
|
||||
* implicit_needed_branches and implicit_leafs_index are auxiliar functions to solve that "optimal-split".
|
||||
*/
|
||||
static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs)
|
||||
{
|
||||
int i;
|
||||
|
||||
const int tree_type = tree->tree_type;
|
||||
const int tree_offset = 2 - tree->tree_type; //this value is 0 (on binary trees) and negative on the others
|
||||
const int num_leafs = tree->totleaf;
|
||||
const int num_branches= MAX2(1, (num_leafs + tree_type - 3) / (tree_type-1) );
|
||||
|
||||
BVHNode* branches_array = tree->nodearray + tree->totleaf - 1; // This code uses 1 index arrays
|
||||
BVHNode** leafs_array = tree->nodes;
|
||||
const int num_branches= implicit_needed_branches(tree_type, num_leafs);
|
||||
|
||||
BVHBuildHelper data;
|
||||
int depth = 0;
|
||||
int depth;
|
||||
|
||||
branches_array--; //Implicit trees use 1-based indexs
|
||||
|
||||
build_implicit_tree_helper(tree, &data);
|
||||
|
||||
//YAY this could be 1 loop.. but had to split in 2 to remove OMP dependencies
|
||||
for(i=1; i <= num_branches; i = i*tree_type + tree_offset)
|
||||
//Loop tree levels (log N) loops
|
||||
for(i=1, depth = 1; i <= num_branches; i = i*tree_type + tree_offset, depth++)
|
||||
{
|
||||
const int first_of_next_level = i*tree_type + tree_offset;
|
||||
const int end_j = MIN2(first_of_next_level, num_branches + 1); //index of last branch on this level
|
||||
int j;
|
||||
|
||||
depth++;
|
||||
|
||||
//Loop all branches on this level
|
||||
#pragma omp parallel for private(j) schedule(static)
|
||||
for(j = i; j < end_j; j++)
|
||||
{
|
||||
int k;
|
||||
const int parent_level_index= j-i;
|
||||
BVHNode* parent = branches_array + j;
|
||||
int nth_positions[ tree_type + 1 ];
|
||||
char split_axis;
|
||||
|
||||
int parent_leafs_begin = implicit_leafs_index(&data, depth, parent_level_index);
|
||||
int parent_leafs_end = implicit_leafs_index(&data, depth, parent_level_index+1);
|
||||
|
||||
//split_axis = (depth*2 % 6); //use this instead of the 2 following lines for XYZ splitting
|
||||
|
||||
//This calculates the bounding box of this branch
|
||||
//and chooses the largest axis as the axis to divide leafs
|
||||
refit_kdop_hull(tree, parent, parent_leafs_begin, parent_leafs_end);
|
||||
split_axis = get_largest_axis(parent->bv);
|
||||
|
||||
//Save split axis (this can be used on raytracing to speedup the query time)
|
||||
parent->main_axis = split_axis / 2;
|
||||
|
||||
//Split the childs along the split_axis, note: its not needed to sort the whole leafs array
|
||||
//Only to assure that the elements are partioned on a way that each child takes the elements
|
||||
//it would take in case the whole array was sorted.
|
||||
//Split_leafs takes care of that "sort" problem.
|
||||
nth_positions[ 0] = parent_leafs_begin;
|
||||
nth_positions[tree_type] = parent_leafs_end;
|
||||
for(k = 1; k < tree_type; k++)
|
||||
{
|
||||
int child_index = j * tree_type + tree_offset + k;
|
||||
int child_level_index = child_index - first_of_next_level; //child level index
|
||||
nth_positions[k] = implicit_leafs_index(&data, depth+1, child_level_index);
|
||||
}
|
||||
|
||||
split_leafs(leafs_array, nth_positions, tree_type, split_axis);
|
||||
|
||||
|
||||
//Setup children and totnode counters
|
||||
//Not really needed but currently most of BVH code relies on having an explicit children structure
|
||||
for(k = 0; k < tree_type; k++)
|
||||
{
|
||||
int child_index = j * tree_type + tree_offset + k;
|
||||
@@ -806,78 +687,236 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree)
|
||||
int child_leafs_begin = implicit_leafs_index(&data, depth+1, child_level_index);
|
||||
int child_leafs_end = implicit_leafs_index(&data, depth+1, child_level_index+1);
|
||||
|
||||
assert( k != 0 || child_leafs_begin == parent_leafs_begin);
|
||||
|
||||
if(child_leafs_end - child_leafs_begin > 1)
|
||||
{
|
||||
parent->children[k] = branches_array + child_index;
|
||||
|
||||
/*
|
||||
printf("Add child %d (%d) to branch %d\n",
|
||||
branches_array + child_index - tree->nodearray,
|
||||
branches_array[ child_index ].index,
|
||||
parent - tree->nodearray
|
||||
);
|
||||
*/
|
||||
|
||||
partition_nth_element(leafs_array, child_leafs_begin, parent_leafs_end, child_leafs_end, split_axis);
|
||||
}
|
||||
else if(child_leafs_end - child_leafs_begin == 1)
|
||||
{
|
||||
/*
|
||||
printf("Add child %d (%d) to branch %d\n",
|
||||
leafs_array[ child_leafs_begin ] - tree->nodearray,
|
||||
leafs_array[ child_leafs_begin ]->index,
|
||||
parent - tree->nodearray
|
||||
);
|
||||
*/
|
||||
parent->children[k] = leafs_array[ child_leafs_begin ];
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->children[k] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
parent->totnode = k+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i<num_branches; i++)
|
||||
tree->nodes[tree->totleaf + i] = branches_array + 1 + i;
|
||||
/*
|
||||
* BLI_bvhtree api
|
||||
*/
|
||||
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
{
|
||||
BVHTree *tree;
|
||||
int numnodes, i;
|
||||
|
||||
// theres not support for trees below binary-trees :P
|
||||
if(tree_type < 2)
|
||||
return NULL;
|
||||
|
||||
tree->totbranch = num_branches;
|
||||
tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree");
|
||||
|
||||
if(tree)
|
||||
{
|
||||
tree->epsilon = epsilon;
|
||||
tree->tree_type = tree_type;
|
||||
tree->axis = axis;
|
||||
|
||||
if(axis == 26)
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 13;
|
||||
}
|
||||
else if(axis == 18)
|
||||
{
|
||||
tree->start_axis = 7;
|
||||
tree->stop_axis = 13;
|
||||
}
|
||||
else if(axis == 14)
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 7;
|
||||
}
|
||||
else if(axis == 8) // AABB
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 4;
|
||||
}
|
||||
else if(axis == 6) // OBB
|
||||
{
|
||||
tree->start_axis = 0;
|
||||
tree->stop_axis = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// BLI_bvhtree_update_tree(tree); //Uncoment this for XYZ splitting
|
||||
|
||||
//Allocate arrays
|
||||
numnodes = maxsize + implicit_needed_branches(tree_type, maxsize) + tree_type;
|
||||
|
||||
tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*numnodes, "BVHNodes");
|
||||
|
||||
if(!tree->nodes)
|
||||
{
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * numnodes, "BVHNodeBV");
|
||||
if(!tree->nodebv)
|
||||
{
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
tree->nodechild = (BVHNode**)MEM_callocN(sizeof(BVHNode*) * tree_type * numnodes, "BVHNodeBV");
|
||||
if(!tree->nodechild)
|
||||
{
|
||||
MEM_freeN(tree->nodebv);
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)* numnodes, "BVHNodeArray");
|
||||
|
||||
if(!tree->nodearray)
|
||||
{
|
||||
MEM_freeN(tree->nodechild);
|
||||
MEM_freeN(tree->nodebv);
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//link the dynamic bv and child links
|
||||
for(i=0; i< numnodes; i++)
|
||||
{
|
||||
tree->nodearray[i].bv = tree->nodebv + i * axis;
|
||||
tree->nodearray[i].children = tree->nodechild + i * tree_type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void BLI_bvhtree_free(BVHTree *tree)
|
||||
{
|
||||
if(tree)
|
||||
{
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree->nodearray);
|
||||
MEM_freeN(tree->nodebv);
|
||||
MEM_freeN(tree->nodechild);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
}
|
||||
|
||||
void BLI_bvhtree_balance(BVHTree *tree)
|
||||
{
|
||||
if(tree->totleaf == 0) return;
|
||||
int i;
|
||||
|
||||
BVHNode* branches_array = tree->nodearray + tree->totleaf;
|
||||
BVHNode** leafs_array = tree->nodes;
|
||||
|
||||
//This function should only be called once (some big bug goes here if its being called more than once per tree)
|
||||
assert(tree->totbranch == 0);
|
||||
non_recursive_bvh_div_nodes(tree);
|
||||
|
||||
/*
|
||||
if(tree->totleaf != 0)
|
||||
{
|
||||
// create root node
|
||||
BVHNode *node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||
tree->totbranch++;
|
||||
<
|
||||
// refit root bvh node
|
||||
refit_kdop_hull(tree, node, 0, tree->totleaf);
|
||||
//Build the implicit tree
|
||||
non_recursive_bvh_div_nodes(tree, branches_array, leafs_array, tree->totleaf);
|
||||
|
||||
// create + balance tree
|
||||
omp_bvh_div_nodes(tree, node, 0, tree->totleaf, tree->totleaf+1);
|
||||
tree->totbranch = needed_branches( tree->tree_type, tree->totleaf );
|
||||
// verify_tree(tree);
|
||||
}
|
||||
*/
|
||||
//current code expects the branches to be linked to the nodes array
|
||||
//we perform that linkage here
|
||||
tree->totbranch = implicit_needed_branches(tree->tree_type, tree->totleaf);
|
||||
for(i = 0; i < tree->totbranch; i++)
|
||||
tree->nodes[tree->totleaf + i] = branches_array + i;
|
||||
|
||||
//bvhtree_info(tree);
|
||||
}
|
||||
|
||||
int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints)
|
||||
{
|
||||
int i;
|
||||
BVHNode *node = NULL;
|
||||
|
||||
// insert should only possible as long as tree->totbranch is 0
|
||||
if(tree->totbranch > 0)
|
||||
return 0;
|
||||
|
||||
if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)/sizeof(*(tree->nodes)))
|
||||
return 0;
|
||||
|
||||
// TODO check if have enough nodes in array
|
||||
|
||||
node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||
tree->totleaf++;
|
||||
|
||||
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||
node->index= index;
|
||||
|
||||
// inflate the bv with some epsilon
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// call before BLI_bvhtree_update_tree()
|
||||
int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints)
|
||||
{
|
||||
int i;
|
||||
BVHNode *node= NULL;
|
||||
|
||||
// check if index exists
|
||||
if(index > tree->totleaf)
|
||||
return 0;
|
||||
|
||||
node = tree->nodearray + index;
|
||||
|
||||
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||
|
||||
if(co_moving)
|
||||
create_kdop_hull(tree, node, co_moving, numpoints, 1);
|
||||
|
||||
// inflate the bv with some epsilon
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// call BLI_bvhtree_update_node() first for every node/point/triangle
|
||||
void BLI_bvhtree_update_tree(BVHTree *tree)
|
||||
{
|
||||
//Update bottom=>top
|
||||
//TRICKY: the way we build the tree all the childs have an index greater than the parent
|
||||
//This allows us todo a bottom up update by starting on the biger numbered branch
|
||||
|
||||
BVHNode** root = tree->nodes + tree->totleaf;
|
||||
BVHNode** index = tree->nodes + tree->totleaf + tree->totbranch-1;
|
||||
|
||||
for (; index != root; index--)
|
||||
node_join(tree, *index);
|
||||
}
|
||||
|
||||
float BLI_bvhtree_getepsilon(BVHTree *tree)
|
||||
{
|
||||
return tree->epsilon;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BLI_bvhtree_overlap
|
||||
*/
|
||||
// overlap - is it possbile for 2 bv's to collide ?
|
||||
static int tree_overlap(BVHNode *node1, BVHNode *node2, int start_axis, int stop_axis)
|
||||
{
|
||||
@@ -1015,86 +1054,8 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result)
|
||||
}
|
||||
|
||||
|
||||
// bottom up update of bvh tree:
|
||||
// join the 4 children here
|
||||
static void node_join(BVHTree *tree, BVHNode *node)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[2*i] = FLT_MAX;
|
||||
node->bv[2*i + 1] = -FLT_MAX;
|
||||
}
|
||||
|
||||
for (i = 0; i < tree->tree_type; i++)
|
||||
{
|
||||
if (node->children[i])
|
||||
{
|
||||
for (j = tree->start_axis; j < tree->stop_axis; j++)
|
||||
{
|
||||
// update minimum
|
||||
if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)])
|
||||
node->bv[(2 * j)] = node->children[i]->bv[(2 * j)];
|
||||
|
||||
// update maximum
|
||||
if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1])
|
||||
node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// call before BLI_bvhtree_update_tree()
|
||||
int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints)
|
||||
{
|
||||
int i;
|
||||
BVHNode *node= NULL;
|
||||
|
||||
// check if index exists
|
||||
if(index > tree->totleaf)
|
||||
return 0;
|
||||
|
||||
node = tree->nodearray + index;
|
||||
|
||||
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||
|
||||
if(co_moving)
|
||||
create_kdop_hull(tree, node, co_moving, numpoints, 1);
|
||||
|
||||
// inflate the bv with some epsilon
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
node->bv[(2 * i)] -= tree->epsilon; // minimum
|
||||
node->bv[(2 * i) + 1] += tree->epsilon; // maximum
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// call BLI_bvhtree_update_node() first for every node/point/triangle
|
||||
void BLI_bvhtree_update_tree(BVHTree *tree)
|
||||
{
|
||||
BVHNode** root = tree->nodes + tree->totleaf;
|
||||
BVHNode** index = tree->nodes + tree->totleaf + tree->totbranch-1;
|
||||
|
||||
//Update bottom=>top
|
||||
//TRICKY: the way we build the tree the parent of a child has an index < then the child index
|
||||
for (; index != root; index--)
|
||||
node_join(tree, *index);
|
||||
}
|
||||
|
||||
float BLI_bvhtree_getepsilon(BVHTree *tree)
|
||||
{
|
||||
return tree->epsilon;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Nearest neighbour
|
||||
* Nearest neighbour - BLI_bvhtree_find_nearest
|
||||
*/
|
||||
static float squared_dist(const float *a, const float *b)
|
||||
{
|
||||
@@ -1103,6 +1064,7 @@ static float squared_dist(const float *a, const float *b)
|
||||
return INPR(tmp, tmp);
|
||||
}
|
||||
|
||||
//Determines the nearest point of the given node BV. Returns the squared distance to that point.
|
||||
static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *nearest)
|
||||
{
|
||||
int i;
|
||||
@@ -1174,6 +1136,7 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nea
|
||||
int i;
|
||||
|
||||
BVHNearestData data;
|
||||
BVHNode* root = tree->nodes[tree->totleaf];
|
||||
|
||||
//init data to search
|
||||
data.tree = tree;
|
||||
@@ -1198,7 +1161,8 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nea
|
||||
}
|
||||
|
||||
//dfs search
|
||||
dfs_find_nearest(&data, tree->nodes[tree->totleaf] );
|
||||
if(root)
|
||||
dfs_find_nearest(&data, root);
|
||||
|
||||
//copy back results
|
||||
if(nearest)
|
||||
@@ -1210,11 +1174,13 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nea
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Ray cast
|
||||
* Raycast - BLI_bvhtree_ray_cast
|
||||
*
|
||||
* raycast is done by performing a DFS on the BVHTree and saving the closest hit
|
||||
*/
|
||||
|
||||
//Determines the distance that the ray must travel to hit the bounding volume of the given node
|
||||
static float ray_nearest_hit(BVHRayCastData *data, BVHNode *node)
|
||||
{
|
||||
int i;
|
||||
@@ -1293,12 +1259,11 @@ static void dfs_raycast(BVHRayCastData *data, BVHNode *node)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
|
||||
{
|
||||
int i;
|
||||
BVHRayCastData data;
|
||||
BVHNode * root = tree->nodes[tree->totleaf];
|
||||
|
||||
data.tree = tree;
|
||||
|
||||
@@ -1327,7 +1292,8 @@ int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, BVHTr
|
||||
data.hit.dist = FLT_MAX;
|
||||
}
|
||||
|
||||
dfs_raycast(&data, tree->nodes[tree->totleaf]);
|
||||
if(root)
|
||||
dfs_raycast(&data, root);
|
||||
|
||||
|
||||
if(hit)
|
||||
|
||||
Reference in New Issue
Block a user