improve static tree construction

This commit is contained in:
Irlan 2017-06-06 16:02:48 -03:00
parent 4ff1e7947f
commit 8503c356a6
7 changed files with 144 additions and 139 deletions

View File

@ -1,2 +1,2 @@
cd ..\ cd ..\
premake5 solution premake5 solution_vs2015

2
bat/premake_vs2017.bat Normal file
View File

@ -0,0 +1,2 @@
cd ..\
premake5 solution_vs2017

View File

@ -10,6 +10,14 @@ Open build/vs2015/bounce.sln.
Set testbed as the startup project. Set testbed as the startup project.
Press F5 to run. Press F5 to run.
Visual Studio 2017
Ensure you have installed the Visual Studio 2015 libraries
Say { premake5 vs2017 } on a command line.
Open build/vs2017/bounce.sln.
Set testbed as the startup project.
Press F5 to run.
Linux Linux
On a clean Ubuntu 16.04 install these packages first: On a clean Ubuntu 16.04 install these packages first:

View File

@ -1 +0,0 @@

View File

@ -77,6 +77,9 @@ private :
} }
}; };
//
void Build(const b3AABB3* set, b3Node* node, u32* indices, u32 numObjects, u32 minObjectsPerLeaf, u32 nodeCapacity, u32& leafCount, u32& internalCount);
// The nodes of this tree stored in an array. // The nodes of this tree stored in an array.
u32 m_nodeCount; u32 m_nodeCount;
b3Node* m_nodes; b3Node* m_nodes;

View File

@ -226,7 +226,7 @@ if os.is "windows" then
newaction newaction
{ {
trigger = "solution", trigger = "solution_vs2015",
description = "Generate solution", description = "Generate solution",
execute = function () execute = function ()
os.execute ( "premake5 clean" ) os.execute ( "premake5 clean" )
@ -234,6 +234,16 @@ if os.is "windows" then
end end
} }
newaction
{
trigger = "solution_vs2017",
description = "Generate solution",
execute = function ()
os.execute ( "premake5 clean" )
os.execute ( "premake5 vs2017" )
end
}
newaction newaction
{ {
trigger = "doc", trigger = "doc",

View File

@ -18,7 +18,6 @@
#include <bounce/collision/trees/static_tree.h> #include <bounce/collision/trees/static_tree.h>
#include <bounce/common/template/stack.h> #include <bounce/common/template/stack.h>
#include <algorithm>
b3StaticTree::b3StaticTree() b3StaticTree::b3StaticTree()
{ {
@ -31,118 +30,59 @@ b3StaticTree::~b3StaticTree()
b3Free(m_nodes); b3Free(m_nodes);
} }
struct b3Params static B3_FORCE_INLINE bool b3SortPredicate(const b3AABB3* set, u32 axis, u32 a, u32 b)
{ {
u32 node; const b3AABB3* b1 = set + a;
u32* indices; const b3AABB3* b2 = set + b;
u32 numObjects;
};
struct b3SortPredicate
{
const b3AABB3* bs;
u32 axis;
bool operator()(const u32& i, const u32& j) const
{
const b3AABB3* b1 = bs + i;
const b3AABB3* b2 = bs + j;
b3Vec3 c1 = b1->Centroid(); b3Vec3 c1 = b1->Centroid();
b3Vec3 c2 = b2->Centroid(); b3Vec3 c2 = b2->Centroid();
if (c1[axis] < c2[axis]) return c1[axis] < c2[axis];
{ }
return true;
}
return false; static void b3Sort(const b3AABB3* set, u32 axis, u32* ids, u32 count)
}
};
void b3StaticTree::Build(const b3AABB3* set, u32 n)
{ {
B3_ASSERT(n > 0); if (count <= 1)
u32* ids = (u32*)b3Alloc(n * sizeof(u32));
for (u32 i = 0; i < n; ++i)
{ {
ids[i] = i; return;
} }
// Leafs = n, Internals = n - 1, Total = 2n - 1, if we assume u32 pivot = ids[count - 1];
// each leaf node contains exactly 1 object. u32 low = 0;
const u32 kMinObjectsPerLeaf = 1; for (u32 i = 0; i < count - 1; ++i)
u32 internalCapacity = n - 1;
u32 leafCapacity = n;
u32 nodeCapacity = 2 * n - 1;
u32 internalCount = 0;
u32 leafCount = 0;
m_nodes = (b3Node*)b3Alloc(nodeCapacity * sizeof(b3Node));
m_nodeCount = 1;
b3Stack<b3Params, 256> stack;
{ {
b3Params params; if (b3SortPredicate(set, axis, ids[i], pivot))
params.node = 0; {
params.indices = ids; u32 tmp = ids[i];
params.numObjects = n; ids[i] = ids[low];
stack.Push(params); ids[low] = tmp;
low++;
}
} }
while (stack.Count() > 0) ids[count - 1] = ids[low];
{ ids[low] = pivot;
b3Params params = stack.Top();
stack.Pop();
u32 nodeIndex = params.node; b3Sort(set, axis, ids, low);
u32* indices = params.indices; b3Sort(set, axis, ids + low + 1, count - 1 - low);
u32 numObjects = params.numObjects; }
B3_ASSERT(numObjects > 0);
// "Allocate" node
b3Node* node = m_nodes + nodeIndex;
// Enclose set
b3AABB3 setAABB = set[indices[0]];
for (u32 i = 1; i < numObjects; ++i)
{
setAABB = b3Combine(setAABB, set[indices[i]]);
}
node->aabb = setAABB;
if (numObjects <= kMinObjectsPerLeaf)
{
++leafCount;
node->child1 = NULL_NODE_S;
node->index = indices[0];
}
else
{
++internalCount;
static u32 b3Partition(const b3AABB3& setAABB, const b3AABB3* set, u32* ids, u32 count)
{
u32 splitAxis = setAABB.GetLongestAxisIndex(); u32 splitAxis = setAABB.GetLongestAxisIndex();
float32 splitPos = setAABB.Centroid()[splitAxis]; float32 splitPos = setAABB.Centroid()[splitAxis];
// Sort along longest axis // Sort along longest axis
b3SortPredicate pred; b3Sort(set, splitAxis, ids, count);
pred.axis = splitAxis;
pred.bs = set;
std::sort(indices, indices + numObjects, pred);
// Find the object that splits the set in two subsets. // Find the object that splits the set in two subsets.
u32 left = 0; u32 left = 0;
u32 right = numObjects - 1; u32 right = count - 1;
u32 middle = left; u32 middle = left;
while (middle < right) while (middle < right)
{ {
b3Vec3 center = set[indices[middle]].Centroid(); b3Vec3 center = set[ids[middle]].Centroid();
if (center[splitAxis] > splitPos) if (center[splitAxis] > splitPos)
{ {
// Found median. // Found median.
@ -154,42 +94,85 @@ void b3StaticTree::Build(const b3AABB3* set, u32 n)
B3_ASSERT(middle >= left); B3_ASSERT(middle >= left);
B3_ASSERT(middle <= right); B3_ASSERT(middle <= right);
// Ensure we don't have empty subsets. // Ensure nonempty subsets.
u32 count1 = middle; u32 count1 = middle;
u32 count2 = numObjects - middle; u32 count2 = count - middle;
if (count1 == 0 || count2 == 0) if (count1 == 0 || count2 == 0)
{ {
// Split at object median.
middle = (left + right) / 2; middle = (left + right) / 2;
count1 = middle;
count2 = numObjects - middle;
} }
B3_ASSERT(count1 > 0 && count2 > 0); return middle;
}
void b3StaticTree::Build(const b3AABB3* set, b3Node* node, u32* ids, u32 count, u32 minObjectsPerLeaf, u32 nodeCapacity, u32& leafCount, u32& internalCount)
{
B3_ASSERT(count > 0);
// Enclose set
b3AABB3 setAABB = set[ids[0]];
for (u32 i = 1; i < count; ++i)
{
setAABB = b3Combine(setAABB, set[ids[i]]);
}
node->aabb = setAABB;
if (count <= minObjectsPerLeaf)
{
++leafCount;
node->child1 = NULL_NODE_S;
node->index = ids[0];
}
else
{
++internalCount;
// Partition current set
u32 middle = b3Partition(setAABB, set, ids, count);
// Allocate left subtree
B3_ASSERT(m_nodeCount < nodeCapacity); B3_ASSERT(m_nodeCount < nodeCapacity);
node->child1 = m_nodeCount; node->child1 = m_nodeCount;
++m_nodeCount; ++m_nodeCount;
// Allocate right subtree
B3_ASSERT(m_nodeCount < nodeCapacity); B3_ASSERT(m_nodeCount < nodeCapacity);
node->child2 = m_nodeCount; node->child2 = m_nodeCount;
++m_nodeCount; ++m_nodeCount;
// Repeat for childs // Build left and right subtrees
b3Params params1; Build(set, m_nodes + node->child1, ids, middle, minObjectsPerLeaf, nodeCapacity, leafCount, internalCount);
params1.node = node->child1; Build(set, m_nodes + node->child2, ids + middle, count - middle, minObjectsPerLeaf, nodeCapacity, leafCount, internalCount);
params1.indices = indices; }
params1.numObjects = count1; }
stack.Push(params1);
b3Params params2; void b3StaticTree::Build(const b3AABB3* set, u32 count)
params2.node = node->child2; {
params2.indices = indices + middle; B3_ASSERT(count > 0);
params2.numObjects = count2;
stack.Push(params2); u32* ids = (u32*)b3Alloc(count * sizeof(u32));
} for (u32 i = 0; i < count; ++i)
{
ids[i] = i;
} }
// Leafs = n, Internals = n - 1, Total = 2n - 1, if we assume
// each leaf node contains exactly 1 object.
const u32 kMinObjectsPerLeaf = 1;
u32 internalCapacity = count - 1;
u32 leafCapacity = count;
u32 nodeCapacity = 2 * count - 1;
u32 internalCount = 0;
u32 leafCount = 0;
m_nodes = (b3Node*)b3Alloc(nodeCapacity * sizeof(b3Node));
m_nodeCount = 1;
Build(set, m_nodes, ids, count, kMinObjectsPerLeaf, nodeCapacity, leafCount, internalCount);
b3Free(ids); b3Free(ids);
B3_ASSERT(leafCount == leafCapacity); B3_ASSERT(leafCount == leafCapacity);