I'm considering using bvhtree for shrinkwrap but the build was considerable slower than kdtree
as so i've made some improvements So basicly theres no shrinkwrap improvements for now...
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
|
||||
#include "RE_raytrace.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
@@ -785,29 +786,45 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
|
||||
KDTreeNearest nearest;
|
||||
float tmp_co[3];
|
||||
|
||||
BVHTree *tree = NULL;
|
||||
|
||||
BENCH_VAR(build);
|
||||
BENCH_VAR(query);
|
||||
|
||||
int numVerts;
|
||||
MVert *vert = NULL;
|
||||
MVert *vert = NULL, *tvert = NULL;
|
||||
MDeformVert *dvert = NULL;
|
||||
|
||||
//Generate kd-tree with target vertexs
|
||||
numVerts= calc->target->getNumVerts(calc->target);
|
||||
vert = tvert = calc->target->getVertDataArray(calc->target, CD_MVERT);
|
||||
|
||||
BENCH_RESET(build);
|
||||
BENCH_BEGIN(build);
|
||||
|
||||
target = BLI_kdtree_new(calc->target->getNumVerts(calc->target));
|
||||
tree = BLI_bvhtree_new(numVerts, 0, 8, 6);
|
||||
if(tree == NULL) return OUT_OF_MEMORY();
|
||||
|
||||
for(i = 0; i < numVerts; i++)
|
||||
BLI_bvhtree_insert(tree, i, vert[i].co, 1);
|
||||
BLI_bvhtree_balance(tree);
|
||||
BENCH_END(build);
|
||||
BENCH_REPORT(build);
|
||||
|
||||
|
||||
//Generate kd-tree with target vertexs
|
||||
BENCH_RESET(build);
|
||||
BENCH_BEGIN(build);
|
||||
|
||||
target = BLI_kdtree_new(numVerts);
|
||||
if(target == NULL) return OUT_OF_MEMORY();
|
||||
|
||||
numVerts= calc->target->getNumVerts(calc->target);
|
||||
vert = calc->target->getVertDataArray(calc->target, CD_MVERT);
|
||||
|
||||
|
||||
for( ;numVerts--; vert++)
|
||||
BLI_kdtree_insert(target, 0, vert->co, NULL);
|
||||
for(i = 0; i < numVerts; i++)
|
||||
BLI_kdtree_insert(target, 0, vert[i].co, NULL);
|
||||
|
||||
BLI_kdtree_balance(target);
|
||||
|
||||
BENCH_END(build);
|
||||
BENCH_REPORT(build);
|
||||
|
||||
|
||||
//Find the nearest vertex
|
||||
@@ -815,17 +832,27 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
|
||||
vert = calc->final->getVertDataArray(calc->final, CD_MVERT);
|
||||
dvert = calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT);
|
||||
|
||||
BENCH_BEGIN(query);
|
||||
for(i=0; i<numVerts; i++)
|
||||
{
|
||||
int t;
|
||||
int t, index;
|
||||
float weight = vertexgroup_get_weight(dvert, i, vgroup);
|
||||
if(weight == 0.0f) continue;
|
||||
|
||||
VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co);
|
||||
/* VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co);
|
||||
|
||||
BENCH_BEGIN(query);
|
||||
index = BLI_bvhtree_find_nearest(tree, tmp_co);
|
||||
if(index != -1)
|
||||
{
|
||||
float dist;
|
||||
VecMat4MulVecfl(tmp_co, calc->target2local, tvert[index].co);
|
||||
dist = VecLenf(vert[i].co, tmp_co);
|
||||
if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist;
|
||||
VecLerpf(vert[i].co, vert[i].co, nearest.co, weight); //linear interpolation
|
||||
}
|
||||
|
||||
*/
|
||||
t = BLI_kdtree_find_nearest(target, tmp_co, 0, &nearest);
|
||||
BENCH_END(query);
|
||||
|
||||
if(t != -1)
|
||||
{
|
||||
@@ -836,15 +863,13 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
|
||||
if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist;
|
||||
VecLerpf(vert[i].co, vert[i].co, nearest.co, weight); //linear interpolation
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BENCH_BEGIN(build);
|
||||
BLI_kdtree_free(target);
|
||||
BENCH_END(build);
|
||||
|
||||
|
||||
BENCH_REPORT(build);
|
||||
BENCH_END(query);
|
||||
BENCH_REPORT(query);
|
||||
|
||||
BLI_kdtree_free(target);
|
||||
BLI_bvhtree_free(tree);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
63
source/blender/blenlib/BLI_kdopbvh.h
Normal file
63
source/blender/blenlib/BLI_kdopbvh.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
*
|
||||
* ***** 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) 2006 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Daniel Genrich, Andre Pinto
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BLI_KDOPBVH_H
|
||||
#define BLI_KDOPBVH_H
|
||||
|
||||
#include <float.h>
|
||||
|
||||
struct BVHTree;
|
||||
typedef struct BVHTree BVHTree;
|
||||
|
||||
typedef struct BVHTreeOverlap {
|
||||
int indexA;
|
||||
int indexB;
|
||||
} BVHTreeOverlap;
|
||||
|
||||
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
|
||||
void BLI_bvhtree_free(BVHTree *tree);
|
||||
|
||||
/* construct: first insert points, then call balance */
|
||||
int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints);
|
||||
void BLI_bvhtree_balance(BVHTree *tree);
|
||||
|
||||
/* update: first update points/nodes, then call update_tree to refit the bounding volumes */
|
||||
int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints);
|
||||
void BLI_bvhtree_update_tree(BVHTree *tree);
|
||||
|
||||
/* collision/overlap: check two trees if they overlap, alloc's *overlap with length of the int return value */
|
||||
BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result);
|
||||
|
||||
float BLI_bvhtree_getepsilon(BVHTree *tree);
|
||||
|
||||
#endif // BLI_KDOPBVH_H
|
||||
|
||||
|
||||
|
||||
|
||||
725
source/blender/blenlib/intern/BLI_kdopbvh.c
Normal file
725
source/blender/blenlib/intern/BLI_kdopbvh.c
Normal file
@@ -0,0 +1,725 @@
|
||||
/* kdop.c
|
||||
*
|
||||
*
|
||||
* ***** BEGIN GPL/BL DUAL 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. The Blender
|
||||
* Foundation also sells licenses for use in proprietary software under
|
||||
* the Blender License. See http://www.blender.org/BL/ for information
|
||||
* about this.
|
||||
*
|
||||
* 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) Blender Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Daniel Genrich, Andre Pinto
|
||||
*
|
||||
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "math.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
#include "BLI_kdopbvh.h"
|
||||
#include "BLI_arithb.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#define node_get_bv(tree, node) ((node)->bv)
|
||||
#define node_get_child(tree,node,i) ((node)->children[i])
|
||||
|
||||
typedef struct BVHNode
|
||||
{
|
||||
struct BVHNode **children;// max 8 children
|
||||
struct BVHNode *parent; // needed for bottom - top update
|
||||
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 traversed; // how many nodes already traversed until this level?
|
||||
char main_axis; // axis that was used to split childs
|
||||
} BVHNode;
|
||||
|
||||
struct BVHTree
|
||||
{
|
||||
BVHNode **nodes;
|
||||
float *nodebv; // pre-alloc bounding-volumes for nodes
|
||||
BVHNode **nodechild; // pre-alloc childs for nodes
|
||||
BVHNode *nodearray; // pre-alloc branchs
|
||||
float epsilon; // epslion is used for inflation of the k-dop
|
||||
int totleaf; // leafs
|
||||
int totbranch;
|
||||
char tree_type; // type of tree (4 => quadtree)
|
||||
char axis; // kdop type (6 => OBB, 7 => AABB, ...)
|
||||
char start_axis, stop_axis; // KDOP_AXES array indices according to axis
|
||||
};
|
||||
|
||||
typedef struct BVHOverlapData
|
||||
{
|
||||
BVHTree *tree1, *tree2;
|
||||
BVHTreeOverlap *overlap;
|
||||
int i, max_overlap; /* i is number of overlaps */
|
||||
} BVHOverlapData;
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Bounding Volume Hierarchy Definition
|
||||
//
|
||||
// Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below
|
||||
// Notes: You have to choose the type at compile time ITM
|
||||
// Notes: You can choose the tree type --> binary, quad, octree, choose below
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static float KDOP_AXES[13][3] =
|
||||
{ {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0},
|
||||
{1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0},
|
||||
{0, 1.0, -1.0}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Introsort
|
||||
// with permission deriven from the following Java code:
|
||||
// http://ralphunden.net/content/tutorials/a-guide-to-introsort/
|
||||
// and he derived it from the SUN STL
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int bvh_partition(BVHNode **a, int lo, int hi, BVHNode * x, int axis)
|
||||
{
|
||||
int i=lo, j=hi;
|
||||
while (1)
|
||||
{
|
||||
while ((a[i])->bv[axis] < x->bv[axis]) i++;
|
||||
j--;
|
||||
while (x->bv[axis] < (a[j])->bv[axis]) j--;
|
||||
if(!(i < j))
|
||||
return i;
|
||||
SWAP( BVHNode* , a[i], a[j]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static BVHNode *bvh_medianof3(BVHNode **a, int lo, int mid, int hi, int axis) // returns Sortable
|
||||
{
|
||||
if ((a[mid])->bv[axis] < (a[lo])->bv[axis])
|
||||
{
|
||||
if ((a[hi])->bv[axis] < (a[mid])->bv[axis])
|
||||
return a[mid];
|
||||
else
|
||||
{
|
||||
if ((a[hi])->bv[axis] < (a[lo])->bv[axis])
|
||||
return a[hi];
|
||||
else
|
||||
return a[lo];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((a[hi])->bv[axis] < (a[mid])->bv[axis])
|
||||
{
|
||||
if ((a[hi])->bv[axis] < (a[lo])->bv[axis])
|
||||
return a[lo];
|
||||
else
|
||||
return a[hi];
|
||||
}
|
||||
else
|
||||
return a[mid];
|
||||
}
|
||||
}
|
||||
|
||||
//after a call to this function you can expect one of:
|
||||
// every node to left of a[n] are smaller than it
|
||||
// every node to the right of a[n-1] are greater than it
|
||||
void partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis)
|
||||
{
|
||||
int begin = _begin, end = _end;
|
||||
while(begin < n && end >= n)
|
||||
{
|
||||
int mid = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin+end-1)/2, end-1, axis), axis );
|
||||
|
||||
if(mid >= n)
|
||||
end = n-1;
|
||||
else
|
||||
begin = n+1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
|
||||
{
|
||||
BVHTree *tree;
|
||||
int numbranches=0, i;
|
||||
|
||||
// only support up to octree
|
||||
if(tree_type > 8)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// calculate max number of branches, our bvh kdop is "almost perfect"
|
||||
for(i = 1; i <= (int)ceil((float)((float)log(maxsize)/(float)log(tree_type))); i++)
|
||||
numbranches += (pow(tree_type, i) / tree_type);
|
||||
|
||||
tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*(numbranches+maxsize + tree_type), "BVHNodes");
|
||||
|
||||
if(!tree->nodes)
|
||||
{
|
||||
MEM_freeN(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * (numbranches+maxsize + tree_type), "BVHNodeBV");
|
||||
if(!tree->nodebv)
|
||||
{
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
tree->nodechild = (BVHNode**)MEM_callocN(sizeof(BVHNode*) * tree_type * (numbranches+maxsize + tree_type), "BVHNodeBV");
|
||||
if(!tree->nodechild)
|
||||
{
|
||||
MEM_freeN(tree->nodebv);
|
||||
MEM_freeN(tree->nodes);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)*(numbranches+maxsize + tree_type), "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< numbranches+maxsize + tree_type; i++)
|
||||
{
|
||||
tree->nodearray[i].bv = tree->nodebv + i * axis;
|
||||
tree->nodearray[i].children = tree->nodechild + i * tree_type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoints, int moving)
|
||||
{
|
||||
float newminmax;
|
||||
float *bv = node_get_bv(tree, node);
|
||||
int i, k;
|
||||
|
||||
// don't init boudings for the moving case
|
||||
if(!moving)
|
||||
{
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
bv[2*i] = FLT_MAX;
|
||||
bv[2*i + 1] = -FLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
for(k = 0; k < numpoints; k++)
|
||||
{
|
||||
// for all Axes.
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
newminmax = INPR(&co[k * 3], KDOP_AXES[i]);
|
||||
if (newminmax < bv[2 * i])
|
||||
bv[2 * i] = newminmax;
|
||||
if (newminmax > bv[(2 * i) + 1])
|
||||
bv[(2 * i) + 1] = newminmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// depends on the fact that the BVH's for each face is already build
|
||||
static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end)
|
||||
{
|
||||
float newmin,newmax;
|
||||
int i, j;
|
||||
float *bv = node_get_bv(tree, node);
|
||||
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
bv[2*i] = FLT_MAX;
|
||||
bv[2*i + 1] = -FLT_MAX;
|
||||
}
|
||||
|
||||
for (j = start; j < end; j++)
|
||||
{
|
||||
// for all Axes.
|
||||
for (i = tree->start_axis; i < tree->stop_axis; i++)
|
||||
{
|
||||
newmin = tree->nodes[j]->bv[(2 * i)];
|
||||
if ((newmin < bv[(2 * i)]))
|
||||
bv[(2 * i)] = newmin;
|
||||
|
||||
newmax = tree->nodes[j]->bv[(2 * i) + 1];
|
||||
if ((newmax > bv[(2 * i) + 1]))
|
||||
bv[(2 * i) + 1] = newmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void inflate_kdop_hull(BVHTree *tree, BVHNode *node)
|
||||
{
|
||||
int i;
|
||||
float *bv = node_get_bv(tree, node);
|
||||
|
||||
for(i= tree->axis; i; i--)
|
||||
{
|
||||
*bv++ -= tree->epsilon; // minimum
|
||||
*bv++ += tree->epsilon; // maximum
|
||||
}
|
||||
}
|
||||
|
||||
// only supports x,y,z axis in the moment
|
||||
// but we should use a plain and simple function here for speed sake
|
||||
static char kdop_hull_get_largest_axis(BVHTree *tree, BVHNode *node)
|
||||
{
|
||||
float *bv = node_get_bv(tree, node);
|
||||
float middle_point[3];
|
||||
|
||||
middle_point[0] = (bv[1]) - (bv[0]); // x axis
|
||||
middle_point[1] = (bv[3]) - (bv[2]); // y axis
|
||||
middle_point[2] = (bv[5]) - (bv[4]); // z axis
|
||||
if (middle_point[0] > middle_point[1])
|
||||
{
|
||||
if (middle_point[0] > middle_point[2])
|
||||
return 1; // max x axis
|
||||
else
|
||||
return 5; // max z axis
|
||||
}
|
||||
else
|
||||
{
|
||||
if (middle_point[1] > middle_point[2])
|
||||
return 3; // max y axis
|
||||
else
|
||||
return 5; // max z axis
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints)
|
||||
{
|
||||
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))
|
||||
return 0;
|
||||
|
||||
// TODO check if have enough nodes in array
|
||||
|
||||
node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||
tree->totleaf++;
|
||||
|
||||
//create and inflate hull
|
||||
create_kdop_hull(tree, node, co, numpoints, 0);
|
||||
inflate_kdop_hull(tree, node);
|
||||
|
||||
node->index= index;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void bvh_div_nodes(BVHTree *tree, BVHNode *node, int start, int end, char lastaxis)
|
||||
{
|
||||
char laxis;
|
||||
int i, tend;
|
||||
BVHNode *tnode;
|
||||
int slice = (end-start+tree->tree_type-1)/tree->tree_type; //division rounded up
|
||||
|
||||
// Determine which axis to split along
|
||||
laxis = kdop_hull_get_largest_axis(tree, node);
|
||||
|
||||
// split nodes along longest axis
|
||||
for (i=0; start < end; start += slice, i++) //i counts the current child
|
||||
{
|
||||
tend = start + slice;
|
||||
|
||||
|
||||
if(tend > end) tend = end;
|
||||
|
||||
if(tend-start == 1) // ok, we have 1 left for this node
|
||||
{
|
||||
node->children[i] = tree->nodes[start];
|
||||
node->children[i]->parent = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
partition_nth_element(tree->nodes, start, end, tend, laxis);
|
||||
|
||||
tnode = node->children[i] = tree->nodes[tree->totleaf + tree->totbranch] = &(tree->nodearray[tree->totbranch + tree->totleaf]);
|
||||
tree->totbranch++;
|
||||
tnode->parent = node;
|
||||
|
||||
refit_kdop_hull(tree, tnode, start, tend);
|
||||
bvh_div_nodes(tree, tnode, start, tend, laxis);
|
||||
}
|
||||
node->totnode++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void verify_tree(BVHTree *tree)
|
||||
{
|
||||
int i, j, check = 0;
|
||||
|
||||
// check the pointer list
|
||||
for(i = 0; i < tree->totleaf; i++)
|
||||
{
|
||||
if(tree->nodes[i]->parent == NULL)
|
||||
printf("Leaf has no parent: %d\n", i);
|
||||
else
|
||||
{
|
||||
for(j = 0; j < tree->tree_type; j++)
|
||||
{
|
||||
if(tree->nodes[i]->parent->children[j] == tree->nodes[i])
|
||||
check = 1;
|
||||
}
|
||||
if(!check)
|
||||
{
|
||||
printf("Parent child relationship doesn't match: %d\n", i);
|
||||
}
|
||||
check = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check the leaf list
|
||||
for(i = 0; i < tree->totleaf; i++)
|
||||
{
|
||||
if(tree->nodearray[i].parent == NULL)
|
||||
printf("Leaf has no parent: %d\n", i);
|
||||
else
|
||||
{
|
||||
for(j = 0; j < tree->tree_type; j++)
|
||||
{
|
||||
if(tree->nodearray[i].parent->children[j] == &tree->nodearray[i])
|
||||
check = 1;
|
||||
}
|
||||
if(!check)
|
||||
{
|
||||
printf("Parent child relationship doesn't match: %d\n", i);
|
||||
}
|
||||
check = 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
|
||||
}
|
||||
|
||||
void BLI_bvhtree_balance(BVHTree *tree)
|
||||
{
|
||||
BVHNode *node;
|
||||
|
||||
if(tree->totleaf == 0)
|
||||
return;
|
||||
|
||||
// create root node
|
||||
node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
|
||||
tree->totbranch++;
|
||||
|
||||
// refit root bvh node
|
||||
refit_kdop_hull(tree, tree->nodes[tree->totleaf], 0, tree->totleaf);
|
||||
// create + balance tree
|
||||
bvh_div_nodes(tree, tree->nodes[tree->totleaf], 0, tree->totleaf, 0);
|
||||
|
||||
// verify_tree(tree);
|
||||
}
|
||||
|
||||
// overlap - is it possbile for 2 bv's to collide ?
|
||||
static int tree_overlap(BVHNode *node1, BVHNode *node2, int start_axis, int stop_axis)
|
||||
{
|
||||
float *bv1 = node1->bv;
|
||||
float *bv2 = node2->bv;
|
||||
|
||||
float *bv1_end = bv1 + (stop_axis<<1);
|
||||
|
||||
bv1 += start_axis<<1;
|
||||
bv2 += start_axis<<1;
|
||||
|
||||
// test all axis if min + max overlap
|
||||
for (; bv1 != bv1_end; bv1+=2, bv2+=2)
|
||||
{
|
||||
if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
|
||||
{
|
||||
int j;
|
||||
|
||||
if(tree_overlap(node1, node2, MIN2(data->tree1->start_axis, data->tree2->start_axis), MIN2(data->tree1->stop_axis, data->tree2->stop_axis)))
|
||||
{
|
||||
// check if node1 is a leaf
|
||||
if(node1->index)
|
||||
{
|
||||
// check if node2 is a leaf
|
||||
if(node2->index)
|
||||
{
|
||||
|
||||
if(node1 == node2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(data->i >= data->max_overlap)
|
||||
{
|
||||
// try to make alloc'ed memory bigger
|
||||
data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap)*data->max_overlap*2);
|
||||
|
||||
if(!data->overlap)
|
||||
{
|
||||
printf("Out of Memory in traverse\n");
|
||||
return;
|
||||
}
|
||||
data->max_overlap *= 2;
|
||||
}
|
||||
|
||||
// both leafs, insert overlap!
|
||||
data->overlap[data->i].indexA = node1->index;
|
||||
data->overlap[data->i].indexB = node2->index;
|
||||
|
||||
data->i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(j = 0; j < data->tree2->tree_type; j++)
|
||||
{
|
||||
if(node2->children[j])
|
||||
traverse(data, node1, node2->children[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for(j = 0; j < data->tree2->tree_type; j++)
|
||||
{
|
||||
if(node1->children[j])
|
||||
traverse(data, node1->children[j], node2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result)
|
||||
{
|
||||
int j, total = 0;
|
||||
BVHTreeOverlap *overlap = NULL, *to = NULL;
|
||||
BVHOverlapData *data[tree1->tree_type];
|
||||
|
||||
// check for compatibility of both trees (can't compare 14-DOP with 18-DOP)
|
||||
if((tree1->axis != tree2->axis) && ((tree1->axis == 14) || tree2->axis == 14))
|
||||
return 0;
|
||||
|
||||
// fast check root nodes for collision before doing big splitting + traversal
|
||||
if(!tree_overlap(tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis)))
|
||||
return 0;
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
{
|
||||
data[j] = (BVHOverlapData *)MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData");
|
||||
|
||||
// init BVHOverlapData
|
||||
data[j]->overlap = (BVHTreeOverlap *)malloc(sizeof(BVHTreeOverlap)*MAX2(tree1->totleaf, tree2->totleaf));
|
||||
data[j]->tree1 = tree1;
|
||||
data[j]->tree2 = tree2;
|
||||
data[j]->max_overlap = MAX2(tree1->totleaf, tree2->totleaf);
|
||||
data[j]->i = 0;
|
||||
}
|
||||
|
||||
#pragma omp parallel for private(j) schedule(static)
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
{
|
||||
traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]);
|
||||
}
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
total += data[j]->i;
|
||||
|
||||
to = overlap = (BVHTreeOverlap *)MEM_callocN(sizeof(BVHTreeOverlap)*total, "BVHTreeOverlap");
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
{
|
||||
memcpy(to, data[j]->overlap, data[j]->i*sizeof(BVHTreeOverlap));
|
||||
to+=data[j]->i;
|
||||
}
|
||||
|
||||
for(j = 0; j < tree1->tree_type; j++)
|
||||
{
|
||||
free(data[j]->overlap);
|
||||
MEM_freeN(data[j]);
|
||||
}
|
||||
|
||||
(*result) = total;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
inflate_kdop_hull(tree, node);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// call BLI_bvhtree_update_node() first for every node/point/triangle
|
||||
void BLI_bvhtree_update_tree(BVHTree *tree)
|
||||
{
|
||||
BVHNode *leaf, *parent;
|
||||
|
||||
// reset tree traversing flag
|
||||
for (leaf = tree->nodearray + tree->totleaf; leaf != tree->nodearray + tree->totleaf + tree->totbranch; leaf++)
|
||||
leaf->traversed = 0;
|
||||
|
||||
for (leaf = tree->nodearray; leaf != tree->nodearray + tree->totleaf; leaf++)
|
||||
{
|
||||
for (parent = leaf->parent; parent; parent = parent->parent)
|
||||
{
|
||||
parent->traversed++; // we tried to go up in hierarchy
|
||||
if (parent->traversed < parent->totnode)
|
||||
break; // we do not need to check further
|
||||
else
|
||||
node_join(tree, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float BLI_bvhtree_getepsilon(BVHTree *tree)
|
||||
{
|
||||
return tree->epsilon;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user