Optimize Dbvt trees in place
Instead of allocating new vectors for each partition, simply partion the nodes in place and pass the corresponding ranges to the next phase.
This commit is contained in:
@@ -227,26 +227,59 @@ static void b3FetchLeaves(b3DynamicBvh* pdbvt,
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
static void b3Split( const b3NodeArray& leaves,
|
||||
b3NodeArray& left,
|
||||
b3NodeArray& right,
|
||||
static bool b3LeftOfAxis( const b3DbvtNode* node,
|
||||
const b3Vector3& org,
|
||||
const b3Vector3& axis)
|
||||
{
|
||||
left.resize(0);
|
||||
right.resize(0);
|
||||
for(int i=0,ni=leaves.size();i<ni;++i)
|
||||
return b3Dot(axis,node->volume.Center()-org) <= 0;
|
||||
}
|
||||
|
||||
// Partitions leaves such that leaves[0, n) are on the
|
||||
// left of axis, and leaves[n, count) are on the right
|
||||
// of axis. returns N.
|
||||
static int b3Split( b3DbvtNode** leaves,
|
||||
int count,
|
||||
const b3Vector3& org,
|
||||
const b3Vector3& axis)
|
||||
{
|
||||
int begin=0;
|
||||
int end=count;
|
||||
for(;;)
|
||||
{
|
||||
if(b3Dot(axis,leaves[i]->volume.Center()-org)<0)
|
||||
left.push_back(leaves[i]);
|
||||
else
|
||||
right.push_back(leaves[i]);
|
||||
while(begin!=end && b3LeftOfAxis(leaves[begin],org,axis))
|
||||
{
|
||||
++begin;
|
||||
}
|
||||
|
||||
if(begin==end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while(begin!=end && !b3LeftOfAxis(leaves[end-1],org,axis))
|
||||
{
|
||||
--end;
|
||||
}
|
||||
|
||||
if(begin==end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// swap out of place nodes
|
||||
--end;
|
||||
b3DbvtNode* temp=leaves[begin];
|
||||
leaves[begin]=leaves[end];
|
||||
leaves[end]=temp;
|
||||
++begin;
|
||||
}
|
||||
|
||||
return begin;
|
||||
}
|
||||
|
||||
//
|
||||
static b3DbvtVolume b3Bounds( const b3NodeArray& leaves)
|
||||
static b3DbvtVolume b3Bounds( b3DbvtNode** leaves,
|
||||
int count)
|
||||
{
|
||||
#if B3_DBVT_MERGE_IMPL==B3_DBVT_IMPL_SSE
|
||||
B3_ATTRIBUTE_ALIGNED16(char locals[sizeof(b3DbvtVolume)]);
|
||||
@@ -255,7 +288,7 @@ static b3DbvtVolume b3Bounds( const b3NodeArray& leaves)
|
||||
#else
|
||||
b3DbvtVolume volume=leaves[0]->volume;
|
||||
#endif
|
||||
for(int i=1,ni=leaves.size();i<ni;++i)
|
||||
for(int i=1,ni=count;i<ni;++i)
|
||||
{
|
||||
b3Merge(volume,leaves[i]->volume,volume);
|
||||
}
|
||||
@@ -264,15 +297,16 @@ static b3DbvtVolume b3Bounds( const b3NodeArray& leaves)
|
||||
|
||||
//
|
||||
static void b3BottomUp( b3DynamicBvh* pdbvt,
|
||||
b3NodeArray& leaves)
|
||||
b3DbvtNode** leaves,
|
||||
int count)
|
||||
{
|
||||
while(leaves.size()>1)
|
||||
while(count>1)
|
||||
{
|
||||
b3Scalar minsize=B3_INFINITY;
|
||||
int minidx[2]={-1,-1};
|
||||
for(int i=0;i<leaves.size();++i)
|
||||
for(int i=0;i<count;++i)
|
||||
{
|
||||
for(int j=i+1;j<leaves.size();++j)
|
||||
for(int j=i+1;j<count;++j)
|
||||
{
|
||||
const b3Scalar sz=b3Size(b3Merge(leaves[i]->volume,leaves[j]->volume));
|
||||
if(sz<minsize)
|
||||
@@ -290,31 +324,33 @@ static void b3BottomUp( b3DynamicBvh* pdbvt,
|
||||
n[0]->parent = p;
|
||||
n[1]->parent = p;
|
||||
leaves[minidx[0]] = p;
|
||||
leaves.swap(minidx[1],leaves.size()-1);
|
||||
leaves.pop_back();
|
||||
leaves[minidx[1]] = leaves[count-1];
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
static b3DbvtNode* b3TopDown(b3DynamicBvh* pdbvt,
|
||||
b3NodeArray& leaves,
|
||||
b3DbvtNode** leaves,
|
||||
int count,
|
||||
int bu_treshold)
|
||||
{
|
||||
static const b3Vector3 axis[]={b3MakeVector3(1,0,0),
|
||||
b3MakeVector3(0,1,0),
|
||||
b3MakeVector3(0,0,1)};
|
||||
if(leaves.size()>1)
|
||||
b3Assert(bu_treshold>1);
|
||||
if(count>1)
|
||||
{
|
||||
if(leaves.size()>bu_treshold)
|
||||
if(count>bu_treshold)
|
||||
{
|
||||
const b3DbvtVolume vol=b3Bounds(leaves);
|
||||
const b3DbvtVolume vol=b3Bounds(leaves,count);
|
||||
const b3Vector3 org=vol.Center();
|
||||
b3NodeArray sets[2];
|
||||
int partition;
|
||||
int bestaxis=-1;
|
||||
int bestmidp=leaves.size();
|
||||
int bestmidp=count;
|
||||
int splitcount[3][2]={{0,0},{0,0},{0,0}};
|
||||
int i;
|
||||
for( i=0;i<leaves.size();++i)
|
||||
for( i=0;i<count;++i)
|
||||
{
|
||||
const b3Vector3 x=leaves[i]->volume.Center()-org;
|
||||
for(int j=0;j<3;++j)
|
||||
@@ -336,29 +372,23 @@ static b3DbvtNode* b3TopDown(b3DynamicBvh* pdbvt,
|
||||
}
|
||||
if(bestaxis>=0)
|
||||
{
|
||||
sets[0].reserve(splitcount[bestaxis][0]);
|
||||
sets[1].reserve(splitcount[bestaxis][1]);
|
||||
b3Split(leaves,sets[0],sets[1],org,axis[bestaxis]);
|
||||
partition=b3Split(leaves,count,org,axis[bestaxis]);
|
||||
b3Assert(partition!=0 && partition!=count);
|
||||
}
|
||||
else
|
||||
{
|
||||
sets[0].reserve(leaves.size()/2+1);
|
||||
sets[1].reserve(leaves.size()/2);
|
||||
for(int i=0,ni=leaves.size();i<ni;++i)
|
||||
{
|
||||
sets[i&1].push_back(leaves[i]);
|
||||
}
|
||||
partition=count/2+1;
|
||||
}
|
||||
b3DbvtNode* node=b3CreateNode(pdbvt,0,vol,0);
|
||||
node->childs[0]=b3TopDown(pdbvt,sets[0],bu_treshold);
|
||||
node->childs[1]=b3TopDown(pdbvt,sets[1],bu_treshold);
|
||||
node->childs[0]=b3TopDown(pdbvt,&leaves[0],partition,bu_treshold);
|
||||
node->childs[1]=b3TopDown(pdbvt,&leaves[partition],count-partition,bu_treshold);
|
||||
node->childs[0]->parent=node;
|
||||
node->childs[1]->parent=node;
|
||||
return(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
b3BottomUp(pdbvt,leaves);
|
||||
b3BottomUp(pdbvt,leaves,count);
|
||||
return(leaves[0]);
|
||||
}
|
||||
}
|
||||
@@ -442,7 +472,7 @@ void b3DynamicBvh::optimizeBottomUp()
|
||||
b3NodeArray leaves;
|
||||
leaves.reserve(m_leaves);
|
||||
b3FetchLeaves(this,m_root,leaves);
|
||||
b3BottomUp(this,leaves);
|
||||
b3BottomUp(this,&leaves[0],leaves.size());
|
||||
m_root=leaves[0];
|
||||
}
|
||||
}
|
||||
@@ -455,7 +485,7 @@ void b3DynamicBvh::optimizeTopDown(int bu_treshold)
|
||||
b3NodeArray leaves;
|
||||
leaves.reserve(m_leaves);
|
||||
b3FetchLeaves(this,m_root,leaves);
|
||||
m_root=b3TopDown(this,leaves,bu_treshold);
|
||||
m_root=b3TopDown(this,&leaves[0],leaves.size(),bu_treshold);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -229,25 +229,60 @@ static void fetchleaves(btDbvt* pdbvt,
|
||||
}
|
||||
|
||||
//
|
||||
static void split( const tNodeArray& leaves,
|
||||
tNodeArray& left,
|
||||
tNodeArray& right,
|
||||
static bool leftOfAxis( const btDbvtNode* node,
|
||||
const btVector3& org,
|
||||
const btVector3& axis)
|
||||
{
|
||||
left.resize(0);
|
||||
right.resize(0);
|
||||
for(int i=0,ni=leaves.size();i<ni;++i)
|
||||
return btDot(axis, node->volume.Center() - org) <= 0;
|
||||
}
|
||||
|
||||
|
||||
// Partitions leaves such that leaves[0, n) are on the
|
||||
// left of axis, and leaves[n, count) are on the right
|
||||
// of axis. returns N.
|
||||
static int split( btDbvtNode** leaves,
|
||||
int count,
|
||||
const btVector3& org,
|
||||
const btVector3& axis)
|
||||
{
|
||||
int begin=0;
|
||||
int end=count;
|
||||
for(;;)
|
||||
{
|
||||
if(btDot(axis,leaves[i]->volume.Center()-org)<0)
|
||||
left.push_back(leaves[i]);
|
||||
else
|
||||
right.push_back(leaves[i]);
|
||||
while(begin!=end && leftOfAxis(leaves[begin],org,axis))
|
||||
{
|
||||
++begin;
|
||||
}
|
||||
|
||||
if(begin==end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while(begin!=end && !leftOfAxis(leaves[end-1],org,axis))
|
||||
{
|
||||
--end;
|
||||
}
|
||||
|
||||
if(begin==end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// swap out of place nodes
|
||||
--end;
|
||||
btDbvtNode* temp=leaves[begin];
|
||||
leaves[begin]=leaves[end];
|
||||
leaves[end]=temp;
|
||||
++begin;
|
||||
}
|
||||
|
||||
return begin;
|
||||
}
|
||||
|
||||
//
|
||||
static btDbvtVolume bounds( const tNodeArray& leaves)
|
||||
static btDbvtVolume bounds( btDbvtNode** leaves,
|
||||
int count)
|
||||
{
|
||||
#if DBVT_MERGE_IMPL==DBVT_IMPL_SSE
|
||||
ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]);
|
||||
@@ -257,7 +292,7 @@ static btDbvtVolume bounds( const tNodeArray& leaves)
|
||||
#else
|
||||
btDbvtVolume volume=leaves[0]->volume;
|
||||
#endif
|
||||
for(int i=1,ni=leaves.size();i<ni;++i)
|
||||
for(int i=1,ni=count;i<ni;++i)
|
||||
{
|
||||
Merge(volume,leaves[i]->volume,volume);
|
||||
}
|
||||
@@ -266,15 +301,16 @@ static btDbvtVolume bounds( const tNodeArray& leaves)
|
||||
|
||||
//
|
||||
static void bottomup( btDbvt* pdbvt,
|
||||
tNodeArray& leaves)
|
||||
btDbvtNode** leaves,
|
||||
int count)
|
||||
{
|
||||
while(leaves.size()>1)
|
||||
while(count>1)
|
||||
{
|
||||
btScalar minsize=SIMD_INFINITY;
|
||||
int minidx[2]={-1,-1};
|
||||
for(int i=0;i<leaves.size();++i)
|
||||
for(int i=0;i<count;++i)
|
||||
{
|
||||
for(int j=i+1;j<leaves.size();++j)
|
||||
for(int j=i+1;j<count;++j)
|
||||
{
|
||||
const btScalar sz=size(merge(leaves[i]->volume,leaves[j]->volume));
|
||||
if(sz<minsize)
|
||||
@@ -292,31 +328,33 @@ static void bottomup( btDbvt* pdbvt,
|
||||
n[0]->parent = p;
|
||||
n[1]->parent = p;
|
||||
leaves[minidx[0]] = p;
|
||||
leaves.swap(minidx[1],leaves.size()-1);
|
||||
leaves.pop_back();
|
||||
leaves[minidx[1]] = leaves[count-1];
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
static btDbvtNode* topdown(btDbvt* pdbvt,
|
||||
tNodeArray& leaves,
|
||||
btDbvtNode** leaves,
|
||||
int count,
|
||||
int bu_treshold)
|
||||
{
|
||||
static const btVector3 axis[]={btVector3(1,0,0),
|
||||
btVector3(0,1,0),
|
||||
btVector3(0,0,1)};
|
||||
if(leaves.size()>1)
|
||||
btAssert(bu_treshold>2);
|
||||
if(count>1)
|
||||
{
|
||||
if(leaves.size()>bu_treshold)
|
||||
if(count>bu_treshold)
|
||||
{
|
||||
const btDbvtVolume vol=bounds(leaves);
|
||||
const btDbvtVolume vol=bounds(leaves,count);
|
||||
const btVector3 org=vol.Center();
|
||||
tNodeArray sets[2];
|
||||
int partition;
|
||||
int bestaxis=-1;
|
||||
int bestmidp=leaves.size();
|
||||
int bestmidp=count;
|
||||
int splitcount[3][2]={{0,0},{0,0},{0,0}};
|
||||
int i;
|
||||
for( i=0;i<leaves.size();++i)
|
||||
for( i=0;i<count;++i)
|
||||
{
|
||||
const btVector3 x=leaves[i]->volume.Center()-org;
|
||||
for(int j=0;j<3;++j)
|
||||
@@ -338,29 +376,23 @@ static btDbvtNode* topdown(btDbvt* pdbvt,
|
||||
}
|
||||
if(bestaxis>=0)
|
||||
{
|
||||
sets[0].reserve(splitcount[bestaxis][0]);
|
||||
sets[1].reserve(splitcount[bestaxis][1]);
|
||||
split(leaves,sets[0],sets[1],org,axis[bestaxis]);
|
||||
partition=split(leaves,count,org,axis[bestaxis]);
|
||||
btAssert(partition!=0 && partition!=count);
|
||||
}
|
||||
else
|
||||
{
|
||||
sets[0].reserve(leaves.size()/2+1);
|
||||
sets[1].reserve(leaves.size()/2);
|
||||
for(int i=0,ni=leaves.size();i<ni;++i)
|
||||
{
|
||||
sets[i&1].push_back(leaves[i]);
|
||||
}
|
||||
partition=count/2+1;
|
||||
}
|
||||
btDbvtNode* node=createnode(pdbvt,0,vol,0);
|
||||
node->childs[0]=topdown(pdbvt,sets[0],bu_treshold);
|
||||
node->childs[1]=topdown(pdbvt,sets[1],bu_treshold);
|
||||
node->childs[0]=topdown(pdbvt,&leaves[0],partition,bu_treshold);
|
||||
node->childs[1]=topdown(pdbvt,&leaves[partition],count-partition,bu_treshold);
|
||||
node->childs[0]->parent=node;
|
||||
node->childs[1]->parent=node;
|
||||
return(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomup(pdbvt,leaves);
|
||||
bottomup(pdbvt,leaves,count);
|
||||
return(leaves[0]);
|
||||
}
|
||||
}
|
||||
@@ -444,7 +476,7 @@ void btDbvt::optimizeBottomUp()
|
||||
tNodeArray leaves;
|
||||
leaves.reserve(m_leaves);
|
||||
fetchleaves(this,m_root,leaves);
|
||||
bottomup(this,leaves);
|
||||
bottomup(this,&leaves[0],leaves.size());
|
||||
m_root=leaves[0];
|
||||
}
|
||||
}
|
||||
@@ -457,7 +489,7 @@ void btDbvt::optimizeTopDown(int bu_treshold)
|
||||
tNodeArray leaves;
|
||||
leaves.reserve(m_leaves);
|
||||
fetchleaves(this,m_root,leaves);
|
||||
m_root=topdown(this,leaves,bu_treshold);
|
||||
m_root=topdown(this,&leaves[0],leaves.size(),bu_treshold);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user