Merge pull request #1286 from mendsley/clean_vbt_allocations

Optimize Dbvt trees in place
This commit is contained in:
erwincoumans
2017-09-24 20:35:57 -07:00
committed by GitHub
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);
} }
} }