improve static tree construction
This commit is contained in:
parent
4ff1e7947f
commit
8503c356a6
@ -1,2 +1,2 @@
|
||||
cd ..\
|
||||
premake5 solution
|
||||
premake5 solution_vs2015
|
2
bat/premake_vs2017.bat
Normal file
2
bat/premake_vs2017.bat
Normal file
@ -0,0 +1,2 @@
|
||||
cd ..\
|
||||
premake5 solution_vs2017
|
@ -10,6 +10,14 @@ Open build/vs2015/bounce.sln.
|
||||
Set testbed as the startup project.
|
||||
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
|
||||
|
||||
On a clean Ubuntu 16.04 install these packages first:
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -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.
|
||||
u32 m_nodeCount;
|
||||
b3Node* m_nodes;
|
||||
|
12
premake5.lua
12
premake5.lua
@ -226,7 +226,7 @@ if os.is "windows" then
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "solution",
|
||||
trigger = "solution_vs2015",
|
||||
description = "Generate solution",
|
||||
execute = function ()
|
||||
os.execute ( "premake5 clean" )
|
||||
@ -234,6 +234,16 @@ if os.is "windows" then
|
||||
end
|
||||
}
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "solution_vs2017",
|
||||
description = "Generate solution",
|
||||
execute = function ()
|
||||
os.execute ( "premake5 clean" )
|
||||
os.execute ( "premake5 vs2017" )
|
||||
end
|
||||
}
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "doc",
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
#include <bounce/collision/trees/static_tree.h>
|
||||
#include <bounce/common/template/stack.h>
|
||||
#include <algorithm>
|
||||
|
||||
b3StaticTree::b3StaticTree()
|
||||
{
|
||||
@ -31,118 +30,59 @@ b3StaticTree::~b3StaticTree()
|
||||
b3Free(m_nodes);
|
||||
}
|
||||
|
||||
struct b3Params
|
||||
static B3_FORCE_INLINE bool b3SortPredicate(const b3AABB3* set, u32 axis, u32 a, u32 b)
|
||||
{
|
||||
u32 node;
|
||||
u32* indices;
|
||||
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;
|
||||
const b3AABB3* b1 = set + a;
|
||||
const b3AABB3* b2 = set + b;
|
||||
|
||||
b3Vec3 c1 = b1->Centroid();
|
||||
b3Vec3 c2 = b2->Centroid();
|
||||
|
||||
if (c1[axis] < c2[axis])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return c1[axis] < c2[axis];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void b3StaticTree::Build(const b3AABB3* set, u32 n)
|
||||
static void b3Sort(const b3AABB3* set, u32 axis, u32* ids, u32 count)
|
||||
{
|
||||
B3_ASSERT(n > 0);
|
||||
|
||||
u32* ids = (u32*)b3Alloc(n * sizeof(u32));
|
||||
for (u32 i = 0; i < n; ++i)
|
||||
if (count <= 1)
|
||||
{
|
||||
ids[i] = i;
|
||||
return;
|
||||
}
|
||||
|
||||
// Leafs = n, Internals = n - 1, Total = 2n - 1, if we assume
|
||||
// each leaf node contains exactly 1 object.
|
||||
const u32 kMinObjectsPerLeaf = 1;
|
||||
|
||||
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;
|
||||
|
||||
u32 pivot = ids[count - 1];
|
||||
u32 low = 0;
|
||||
for (u32 i = 0; i < count - 1; ++i)
|
||||
{
|
||||
b3Params params;
|
||||
params.node = 0;
|
||||
params.indices = ids;
|
||||
params.numObjects = n;
|
||||
stack.Push(params);
|
||||
if (b3SortPredicate(set, axis, ids[i], pivot))
|
||||
{
|
||||
u32 tmp = ids[i];
|
||||
ids[i] = ids[low];
|
||||
ids[low] = tmp;
|
||||
low++;
|
||||
}
|
||||
}
|
||||
|
||||
while (stack.Count() > 0)
|
||||
{
|
||||
b3Params params = stack.Top();
|
||||
stack.Pop();
|
||||
ids[count - 1] = ids[low];
|
||||
ids[low] = pivot;
|
||||
|
||||
u32 nodeIndex = params.node;
|
||||
u32* indices = params.indices;
|
||||
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;
|
||||
b3Sort(set, axis, ids, low);
|
||||
b3Sort(set, axis, ids + low + 1, count - 1 - low);
|
||||
}
|
||||
|
||||
static u32 b3Partition(const b3AABB3& setAABB, const b3AABB3* set, u32* ids, u32 count)
|
||||
{
|
||||
u32 splitAxis = setAABB.GetLongestAxisIndex();
|
||||
float32 splitPos = setAABB.Centroid()[splitAxis];
|
||||
|
||||
// Sort along longest axis
|
||||
b3SortPredicate pred;
|
||||
pred.axis = splitAxis;
|
||||
pred.bs = set;
|
||||
std::sort(indices, indices + numObjects, pred);
|
||||
b3Sort(set, splitAxis, ids, count);
|
||||
|
||||
// Find the object that splits the set in two subsets.
|
||||
u32 left = 0;
|
||||
u32 right = numObjects - 1;
|
||||
u32 right = count - 1;
|
||||
u32 middle = left;
|
||||
while (middle < right)
|
||||
{
|
||||
b3Vec3 center = set[indices[middle]].Centroid();
|
||||
b3Vec3 center = set[ids[middle]].Centroid();
|
||||
if (center[splitAxis] > splitPos)
|
||||
{
|
||||
// Found median.
|
||||
@ -154,42 +94,85 @@ void b3StaticTree::Build(const b3AABB3* set, u32 n)
|
||||
B3_ASSERT(middle >= left);
|
||||
B3_ASSERT(middle <= right);
|
||||
|
||||
// Ensure we don't have empty subsets.
|
||||
// Ensure nonempty subsets.
|
||||
u32 count1 = middle;
|
||||
u32 count2 = numObjects - middle;
|
||||
u32 count2 = count - middle;
|
||||
if (count1 == 0 || count2 == 0)
|
||||
{
|
||||
// Split at object median.
|
||||
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);
|
||||
node->child1 = m_nodeCount;
|
||||
++m_nodeCount;
|
||||
|
||||
// Allocate right subtree
|
||||
B3_ASSERT(m_nodeCount < nodeCapacity);
|
||||
node->child2 = m_nodeCount;
|
||||
++m_nodeCount;
|
||||
|
||||
// Repeat for childs
|
||||
b3Params params1;
|
||||
params1.node = node->child1;
|
||||
params1.indices = indices;
|
||||
params1.numObjects = count1;
|
||||
stack.Push(params1);
|
||||
// Build left and right subtrees
|
||||
Build(set, m_nodes + node->child1, ids, middle, minObjectsPerLeaf, nodeCapacity, leafCount, internalCount);
|
||||
Build(set, m_nodes + node->child2, ids + middle, count - middle, minObjectsPerLeaf, nodeCapacity, leafCount, internalCount);
|
||||
}
|
||||
}
|
||||
|
||||
b3Params params2;
|
||||
params2.node = node->child2;
|
||||
params2.indices = indices + middle;
|
||||
params2.numObjects = count2;
|
||||
stack.Push(params2);
|
||||
}
|
||||
void b3StaticTree::Build(const b3AABB3* set, u32 count)
|
||||
{
|
||||
B3_ASSERT(count > 0);
|
||||
|
||||
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);
|
||||
|
||||
B3_ASSERT(leafCount == leafCapacity);
|
||||
|
Loading…
x
Reference in New Issue
Block a user