Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/AABBTree/AABBTreeBuilder.cpp
9906 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
7
#include <Jolt/AABBTree/AABBTreeBuilder.h>
8
9
JPH_NAMESPACE_BEGIN
10
11
uint AABBTreeBuilder::Node::GetMinDepth(const Array<Node> &inNodes) const
12
{
13
if (HasChildren())
14
{
15
uint left = inNodes[mChild[0]].GetMinDepth(inNodes);
16
uint right = inNodes[mChild[1]].GetMinDepth(inNodes);
17
return min(left, right) + 1;
18
}
19
else
20
return 1;
21
}
22
23
uint AABBTreeBuilder::Node::GetMaxDepth(const Array<Node> &inNodes) const
24
{
25
if (HasChildren())
26
{
27
uint left = inNodes[mChild[0]].GetMaxDepth(inNodes);
28
uint right = inNodes[mChild[1]].GetMaxDepth(inNodes);
29
return max(left, right) + 1;
30
}
31
else
32
return 1;
33
}
34
35
uint AABBTreeBuilder::Node::GetNodeCount(const Array<Node> &inNodes) const
36
{
37
if (HasChildren())
38
return inNodes[mChild[0]].GetNodeCount(inNodes) + inNodes[mChild[1]].GetNodeCount(inNodes) + 1;
39
else
40
return 1;
41
}
42
43
uint AABBTreeBuilder::Node::GetLeafNodeCount(const Array<Node> &inNodes) const
44
{
45
if (HasChildren())
46
return inNodes[mChild[0]].GetLeafNodeCount(inNodes) + inNodes[mChild[1]].GetLeafNodeCount(inNodes);
47
else
48
return 1;
49
}
50
51
uint AABBTreeBuilder::Node::GetTriangleCountInTree(const Array<Node> &inNodes) const
52
{
53
if (HasChildren())
54
return inNodes[mChild[0]].GetTriangleCountInTree(inNodes) + inNodes[mChild[1]].GetTriangleCountInTree(inNodes);
55
else
56
return GetTriangleCount();
57
}
58
59
void AABBTreeBuilder::Node::GetTriangleCountPerNode(const Array<Node> &inNodes, float &outAverage, uint &outMin, uint &outMax) const
60
{
61
outMin = INT_MAX;
62
outMax = 0;
63
outAverage = 0;
64
uint avg_divisor = 0;
65
GetTriangleCountPerNodeInternal(inNodes, outAverage, avg_divisor, outMin, outMax);
66
if (avg_divisor > 0)
67
outAverage /= avg_divisor;
68
}
69
70
float AABBTreeBuilder::Node::CalculateSAHCost(const Array<Node> &inNodes, float inCostTraversal, float inCostLeaf) const
71
{
72
float surface_area = mBounds.GetSurfaceArea();
73
return surface_area > 0.0f? CalculateSAHCostInternal(inNodes, inCostTraversal / surface_area, inCostLeaf / surface_area) : 0.0f;
74
}
75
76
void AABBTreeBuilder::Node::GetNChildren(const Array<Node> &inNodes, uint inN, Array<const Node*> &outChildren) const
77
{
78
JPH_ASSERT(outChildren.empty());
79
80
// Check if there is anything to expand
81
if (!HasChildren())
82
return;
83
84
// Start with the children of this node
85
outChildren.push_back(&inNodes[mChild[0]]);
86
outChildren.push_back(&inNodes[mChild[1]]);
87
88
size_t next = 0;
89
bool all_triangles = true;
90
while (outChildren.size() < inN)
91
{
92
// If we have looped over all nodes, start over with the first node again
93
if (next >= outChildren.size())
94
{
95
// If there only triangle nodes left, we have to terminate
96
if (all_triangles)
97
return;
98
next = 0;
99
all_triangles = true;
100
}
101
102
// Try to expand this node into its two children
103
const Node *to_expand = outChildren[next];
104
if (to_expand->HasChildren())
105
{
106
outChildren.erase(outChildren.begin() + next);
107
outChildren.push_back(&inNodes[to_expand->mChild[0]]);
108
outChildren.push_back(&inNodes[to_expand->mChild[1]]);
109
all_triangles = false;
110
}
111
else
112
{
113
++next;
114
}
115
}
116
}
117
118
float AABBTreeBuilder::Node::CalculateSAHCostInternal(const Array<Node> &inNodes, float inCostTraversalDivSurfaceArea, float inCostLeafDivSurfaceArea) const
119
{
120
if (HasChildren())
121
return inCostTraversalDivSurfaceArea * mBounds.GetSurfaceArea()
122
+ inNodes[mChild[0]].CalculateSAHCostInternal(inNodes, inCostTraversalDivSurfaceArea, inCostLeafDivSurfaceArea)
123
+ inNodes[mChild[1]].CalculateSAHCostInternal(inNodes, inCostTraversalDivSurfaceArea, inCostLeafDivSurfaceArea);
124
else
125
return inCostLeafDivSurfaceArea * mBounds.GetSurfaceArea() * GetTriangleCount();
126
}
127
128
void AABBTreeBuilder::Node::GetTriangleCountPerNodeInternal(const Array<Node> &inNodes, float &outAverage, uint &outAverageDivisor, uint &outMin, uint &outMax) const
129
{
130
if (HasChildren())
131
{
132
inNodes[mChild[0]].GetTriangleCountPerNodeInternal(inNodes, outAverage, outAverageDivisor, outMin, outMax);
133
inNodes[mChild[1]].GetTriangleCountPerNodeInternal(inNodes, outAverage, outAverageDivisor, outMin, outMax);
134
}
135
else
136
{
137
outAverage += GetTriangleCount();
138
outAverageDivisor++;
139
outMin = min(outMin, GetTriangleCount());
140
outMax = max(outMax, GetTriangleCount());
141
}
142
}
143
144
AABBTreeBuilder::AABBTreeBuilder(TriangleSplitter &inSplitter, uint inMaxTrianglesPerLeaf) :
145
mTriangleSplitter(inSplitter),
146
mMaxTrianglesPerLeaf(inMaxTrianglesPerLeaf)
147
{
148
}
149
150
AABBTreeBuilder::Node *AABBTreeBuilder::Build(AABBTreeBuilderStats &outStats)
151
{
152
TriangleSplitter::Range initial = mTriangleSplitter.GetInitialRange();
153
154
// Worst case for number of nodes: 1 leaf node per triangle. At each level above, the number of nodes is half that of the level below.
155
// This means that at most we'll be allocating 2x the number of triangles in nodes.
156
mNodes.reserve(2 * initial.Count());
157
mTriangles.reserve(initial.Count());
158
159
// Build the tree
160
Node &root = mNodes[BuildInternal(initial)];
161
162
// Collect stats
163
float avg_triangles_per_leaf;
164
uint min_triangles_per_leaf, max_triangles_per_leaf;
165
root.GetTriangleCountPerNode(mNodes, avg_triangles_per_leaf, min_triangles_per_leaf, max_triangles_per_leaf);
166
167
mTriangleSplitter.GetStats(outStats.mSplitterStats);
168
169
outStats.mSAHCost = root.CalculateSAHCost(mNodes, 1.0f, 1.0f);
170
outStats.mMinDepth = root.GetMinDepth(mNodes);
171
outStats.mMaxDepth = root.GetMaxDepth(mNodes);
172
outStats.mNodeCount = root.GetNodeCount(mNodes);
173
outStats.mLeafNodeCount = root.GetLeafNodeCount(mNodes);
174
outStats.mMaxTrianglesPerLeaf = mMaxTrianglesPerLeaf;
175
outStats.mTreeMinTrianglesPerLeaf = min_triangles_per_leaf;
176
outStats.mTreeMaxTrianglesPerLeaf = max_triangles_per_leaf;
177
outStats.mTreeAvgTrianglesPerLeaf = avg_triangles_per_leaf;
178
179
return &root;
180
}
181
182
uint AABBTreeBuilder::BuildInternal(const TriangleSplitter::Range &inTriangles)
183
{
184
// Check if there are too many triangles left
185
if (inTriangles.Count() > mMaxTrianglesPerLeaf)
186
{
187
// Split triangles in two batches
188
TriangleSplitter::Range left, right;
189
if (!mTriangleSplitter.Split(inTriangles, left, right))
190
{
191
// When the trace below triggers:
192
//
193
// This code builds a tree structure to accelerate collision detection.
194
// At top level it will start with all triangles in a mesh and then divides the triangles into two batches.
195
// This process repeats until until the batch size is smaller than mMaxTrianglePerLeaf.
196
//
197
// It uses a TriangleSplitter to find a good split. When this warning triggers, the splitter was not able
198
// to create a reasonable split for the triangles. This usually happens when the triangles in a batch are
199
// intersecting. They could also be overlapping when projected on the 3 coordinate axis.
200
//
201
// To solve this issue, you could try to pass your mesh through a mesh cleaning / optimization algorithm.
202
// You could also inspect the triangles that cause this issue and see if that part of the mesh can be fixed manually.
203
//
204
// When you do not fix this warning, the tree will be less efficient for collision detection, but it will still work.
205
JPH_IF_DEBUG(Trace("AABBTreeBuilder: Doing random split for %d triangles (max per node: %u)!", (int)inTriangles.Count(), mMaxTrianglesPerLeaf);)
206
int half = inTriangles.Count() / 2;
207
JPH_ASSERT(half > 0);
208
left = TriangleSplitter::Range(inTriangles.mBegin, inTriangles.mBegin + half);
209
right = TriangleSplitter::Range(inTriangles.mBegin + half, inTriangles.mEnd);
210
}
211
212
// Recursively build
213
const uint node_index = (uint)mNodes.size();
214
mNodes.push_back(Node());
215
uint left_index = BuildInternal(left);
216
uint right_index = BuildInternal(right);
217
Node &node = mNodes[node_index];
218
node.mChild[0] = left_index;
219
node.mChild[1] = right_index;
220
node.mBounds = mNodes[node.mChild[0]].mBounds;
221
node.mBounds.Encapsulate(mNodes[node.mChild[1]].mBounds);
222
return node_index;
223
}
224
225
// Create leaf node
226
const uint node_index = (uint)mNodes.size();
227
mNodes.push_back(Node());
228
Node &node = mNodes.back();
229
node.mTrianglesBegin = (uint)mTriangles.size();
230
node.mNumTriangles = inTriangles.mEnd - inTriangles.mBegin;
231
const VertexList &v = mTriangleSplitter.GetVertices();
232
for (uint i = inTriangles.mBegin; i < inTriangles.mEnd; ++i)
233
{
234
const IndexedTriangle &t = mTriangleSplitter.GetTriangle(i);
235
mTriangles.push_back(t);
236
node.mBounds.Encapsulate(v, t);
237
}
238
239
return node_index;
240
}
241
242
JPH_NAMESPACE_END
243
244