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:
Matthew Endsley
2017-08-30 01:12:45 -07:00
parent 22658da02a
commit 4c00b674b3
2 changed files with 141 additions and 79 deletions

View File

@@ -227,26 +227,59 @@ static void b3FetchLeaves(b3DynamicBvh* pdbvt,
} }
} }
// static bool b3LeftOfAxis( const b3DbvtNode* node,
static void b3Split( const b3NodeArray& leaves, const b3Vector3& org,
b3NodeArray& left, const b3Vector3& axis)
b3NodeArray& right, {
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& org,
const b3Vector3& axis) const b3Vector3& axis)
{ {
left.resize(0); int begin=0;
right.resize(0); int end=count;
for(int i=0,ni=leaves.size();i<ni;++i) for(;;)
{ {
if(b3Dot(axis,leaves[i]->volume.Center()-org)<0) while(begin!=end && b3LeftOfAxis(leaves[begin],org,axis))
left.push_back(leaves[i]); {
else ++begin;
right.push_back(leaves[i]); }
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 #if B3_DBVT_MERGE_IMPL==B3_DBVT_IMPL_SSE
B3_ATTRIBUTE_ALIGNED16(char locals[sizeof(b3DbvtVolume)]); B3_ATTRIBUTE_ALIGNED16(char locals[sizeof(b3DbvtVolume)]);
@@ -255,7 +288,7 @@ static b3DbvtVolume b3Bounds( const b3NodeArray& leaves)
#else #else
b3DbvtVolume volume=leaves[0]->volume; b3DbvtVolume volume=leaves[0]->volume;
#endif #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); b3Merge(volume,leaves[i]->volume,volume);
} }
@@ -264,15 +297,16 @@ static b3DbvtVolume b3Bounds( const b3NodeArray& leaves)
// //
static void b3BottomUp( b3DynamicBvh* pdbvt, static void b3BottomUp( b3DynamicBvh* pdbvt,
b3NodeArray& leaves) b3DbvtNode** leaves,
int count)
{ {
while(leaves.size()>1) while(count>1)
{ {
b3Scalar minsize=B3_INFINITY; b3Scalar minsize=B3_INFINITY;
int minidx[2]={-1,-1}; 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)); const b3Scalar sz=b3Size(b3Merge(leaves[i]->volume,leaves[j]->volume));
if(sz<minsize) if(sz<minsize)
@@ -290,31 +324,33 @@ static void b3BottomUp( b3DynamicBvh* pdbvt,
n[0]->parent = p; n[0]->parent = p;
n[1]->parent = p; n[1]->parent = p;
leaves[minidx[0]] = p; leaves[minidx[0]] = p;
leaves.swap(minidx[1],leaves.size()-1); leaves[minidx[1]] = leaves[count-1];
leaves.pop_back(); --count;
} }
} }
// //
static b3DbvtNode* b3TopDown(b3DynamicBvh* pdbvt, static b3DbvtNode* b3TopDown(b3DynamicBvh* pdbvt,
b3NodeArray& leaves, b3DbvtNode** leaves,
int count,
int bu_treshold) int bu_treshold)
{ {
static const b3Vector3 axis[]={b3MakeVector3(1,0,0), static const b3Vector3 axis[]={b3MakeVector3(1,0,0),
b3MakeVector3(0,1,0), b3MakeVector3(0,1,0),
b3MakeVector3(0,0,1)}; 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(); const b3Vector3 org=vol.Center();
b3NodeArray sets[2]; int partition;
int bestaxis=-1; int bestaxis=-1;
int bestmidp=leaves.size(); int bestmidp=count;
int splitcount[3][2]={{0,0},{0,0},{0,0}}; int splitcount[3][2]={{0,0},{0,0},{0,0}};
int i; int i;
for( i=0;i<leaves.size();++i) for( i=0;i<count;++i)
{ {
const b3Vector3 x=leaves[i]->volume.Center()-org; const b3Vector3 x=leaves[i]->volume.Center()-org;
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@@ -336,29 +372,23 @@ static b3DbvtNode* b3TopDown(b3DynamicBvh* pdbvt,
} }
if(bestaxis>=0) if(bestaxis>=0)
{ {
sets[0].reserve(splitcount[bestaxis][0]); partition=b3Split(leaves,count,org,axis[bestaxis]);
sets[1].reserve(splitcount[bestaxis][1]); b3Assert(partition!=0 && partition!=count);
b3Split(leaves,sets[0],sets[1],org,axis[bestaxis]);
} }
else else
{ {
sets[0].reserve(leaves.size()/2+1); partition=count/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]);
}
} }
b3DbvtNode* node=b3CreateNode(pdbvt,0,vol,0); b3DbvtNode* node=b3CreateNode(pdbvt,0,vol,0);
node->childs[0]=b3TopDown(pdbvt,sets[0],bu_treshold); node->childs[0]=b3TopDown(pdbvt,&leaves[0],partition,bu_treshold);
node->childs[1]=b3TopDown(pdbvt,sets[1],bu_treshold); node->childs[1]=b3TopDown(pdbvt,&leaves[partition],count-partition,bu_treshold);
node->childs[0]->parent=node; node->childs[0]->parent=node;
node->childs[1]->parent=node; node->childs[1]->parent=node;
return(node); return(node);
} }
else else
{ {
b3BottomUp(pdbvt,leaves); b3BottomUp(pdbvt,leaves,count);
return(leaves[0]); return(leaves[0]);
} }
} }
@@ -442,7 +472,7 @@ void b3DynamicBvh::optimizeBottomUp()
b3NodeArray leaves; b3NodeArray leaves;
leaves.reserve(m_leaves); leaves.reserve(m_leaves);
b3FetchLeaves(this,m_root,leaves); b3FetchLeaves(this,m_root,leaves);
b3BottomUp(this,leaves); b3BottomUp(this,&leaves[0],leaves.size());
m_root=leaves[0]; m_root=leaves[0];
} }
} }
@@ -455,7 +485,7 @@ void b3DynamicBvh::optimizeTopDown(int bu_treshold)
b3NodeArray leaves; b3NodeArray leaves;
leaves.reserve(m_leaves); leaves.reserve(m_leaves);
b3FetchLeaves(this,m_root,leaves); b3FetchLeaves(this,m_root,leaves);
m_root=b3TopDown(this,leaves,bu_treshold); m_root=b3TopDown(this,&leaves[0],leaves.size(),bu_treshold);
} }
} }

View File

@@ -229,25 +229,60 @@ static void fetchleaves(btDbvt* pdbvt,
} }
// //
static void split( const tNodeArray& leaves, static bool leftOfAxis( const btDbvtNode* node,
tNodeArray& left, const btVector3& org,
tNodeArray& right, const btVector3& axis)
{
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& org,
const btVector3& axis) const btVector3& axis)
{ {
left.resize(0); int begin=0;
right.resize(0); int end=count;
for(int i=0,ni=leaves.size();i<ni;++i) for(;;)
{ {
if(btDot(axis,leaves[i]->volume.Center()-org)<0) while(begin!=end && leftOfAxis(leaves[begin],org,axis))
left.push_back(leaves[i]); {
else ++begin;
right.push_back(leaves[i]); }
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 #if DBVT_MERGE_IMPL==DBVT_IMPL_SSE
ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]); ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]);
@@ -257,7 +292,7 @@ static btDbvtVolume bounds( const tNodeArray& leaves)
#else #else
btDbvtVolume volume=leaves[0]->volume; btDbvtVolume volume=leaves[0]->volume;
#endif #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); Merge(volume,leaves[i]->volume,volume);
} }
@@ -266,15 +301,16 @@ static btDbvtVolume bounds( const tNodeArray& leaves)
// //
static void bottomup( btDbvt* pdbvt, static void bottomup( btDbvt* pdbvt,
tNodeArray& leaves) btDbvtNode** leaves,
int count)
{ {
while(leaves.size()>1) while(count>1)
{ {
btScalar minsize=SIMD_INFINITY; btScalar minsize=SIMD_INFINITY;
int minidx[2]={-1,-1}; 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)); const btScalar sz=size(merge(leaves[i]->volume,leaves[j]->volume));
if(sz<minsize) if(sz<minsize)
@@ -292,31 +328,33 @@ static void bottomup( btDbvt* pdbvt,
n[0]->parent = p; n[0]->parent = p;
n[1]->parent = p; n[1]->parent = p;
leaves[minidx[0]] = p; leaves[minidx[0]] = p;
leaves.swap(minidx[1],leaves.size()-1); leaves[minidx[1]] = leaves[count-1];
leaves.pop_back(); --count;
} }
} }
// //
static btDbvtNode* topdown(btDbvt* pdbvt, static btDbvtNode* topdown(btDbvt* pdbvt,
tNodeArray& leaves, btDbvtNode** leaves,
int count,
int bu_treshold) int bu_treshold)
{ {
static const btVector3 axis[]={btVector3(1,0,0), static const btVector3 axis[]={btVector3(1,0,0),
btVector3(0,1,0), btVector3(0,1,0),
btVector3(0,0,1)}; 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(); const btVector3 org=vol.Center();
tNodeArray sets[2]; int partition;
int bestaxis=-1; int bestaxis=-1;
int bestmidp=leaves.size(); int bestmidp=count;
int splitcount[3][2]={{0,0},{0,0},{0,0}}; int splitcount[3][2]={{0,0},{0,0},{0,0}};
int i; int i;
for( i=0;i<leaves.size();++i) for( i=0;i<count;++i)
{ {
const btVector3 x=leaves[i]->volume.Center()-org; const btVector3 x=leaves[i]->volume.Center()-org;
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@@ -338,29 +376,23 @@ static btDbvtNode* topdown(btDbvt* pdbvt,
} }
if(bestaxis>=0) if(bestaxis>=0)
{ {
sets[0].reserve(splitcount[bestaxis][0]); partition=split(leaves,count,org,axis[bestaxis]);
sets[1].reserve(splitcount[bestaxis][1]); btAssert(partition!=0 && partition!=count);
split(leaves,sets[0],sets[1],org,axis[bestaxis]);
} }
else else
{ {
sets[0].reserve(leaves.size()/2+1); partition=count/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]);
}
} }
btDbvtNode* node=createnode(pdbvt,0,vol,0); btDbvtNode* node=createnode(pdbvt,0,vol,0);
node->childs[0]=topdown(pdbvt,sets[0],bu_treshold); node->childs[0]=topdown(pdbvt,&leaves[0],partition,bu_treshold);
node->childs[1]=topdown(pdbvt,sets[1],bu_treshold); node->childs[1]=topdown(pdbvt,&leaves[partition],count-partition,bu_treshold);
node->childs[0]->parent=node; node->childs[0]->parent=node;
node->childs[1]->parent=node; node->childs[1]->parent=node;
return(node); return(node);
} }
else else
{ {
bottomup(pdbvt,leaves); bottomup(pdbvt,leaves,count);
return(leaves[0]); return(leaves[0]);
} }
} }
@@ -444,7 +476,7 @@ void btDbvt::optimizeBottomUp()
tNodeArray leaves; tNodeArray leaves;
leaves.reserve(m_leaves); leaves.reserve(m_leaves);
fetchleaves(this,m_root,leaves); fetchleaves(this,m_root,leaves);
bottomup(this,leaves); bottomup(this,&leaves[0],leaves.size());
m_root=leaves[0]; m_root=leaves[0];
} }
} }
@@ -457,7 +489,7 @@ void btDbvt::optimizeTopDown(int bu_treshold)
tNodeArray leaves; tNodeArray leaves;
leaves.reserve(m_leaves); leaves.reserve(m_leaves);
fetchleaves(this,m_root,leaves); fetchleaves(this,m_root,leaves);
m_root=topdown(this,leaves,bu_treshold); m_root=topdown(this,&leaves[0],leaves.size(),bu_treshold);
} }
} }