11 m_nodes.resize(m_nodeCapacity);
13 for (
int i = 0; i < m_nodeCapacity - 1; ++i) {
14 m_nodes[i].parent = i + 1;
15 m_nodes[i].height = -1;
17 m_nodes[m_nodeCapacity - 1].parent =
NULL_NODE;
18 m_nodes[m_nodeCapacity - 1].height = -1;
22int DynamicAABBTree::AllocateNode() {
24 int oldCapacity = m_nodeCapacity;
26 m_nodes.resize(m_nodeCapacity);
28 for (
int i = oldCapacity; i < m_nodeCapacity - 1; ++i) {
29 m_nodes[i].parent = i + 1;
30 m_nodes[i].height = -1;
32 m_nodes[m_nodeCapacity - 1].parent =
NULL_NODE;
33 m_nodes[m_nodeCapacity - 1].height = -1;
34 m_freeList = oldCapacity;
37 int nodeId = m_freeList;
38 m_freeList = m_nodes[nodeId].parent;
43 m_nodes[nodeId].height = 0;
44 m_nodes[nodeId].userData =
nullptr;
50void DynamicAABBTree::FreeNode(
int nodeId) {
51 m_nodes[nodeId].parent = m_freeList;
52 m_nodes[nodeId].height = -1;
53 m_nodes[nodeId].userData =
nullptr;
59 int proxyId = AllocateNode();
61 m_nodes[proxyId].userData = userData;
62 m_nodes[proxyId].height = 0;
75 if (m_nodes[proxyId].fatAABB.Contains(newAABB.
min) &&
76 m_nodes[proxyId].fatAABB.Contains(newAABB.
max)) {
86 if (d.
GetX() < 0.0f) {
91 if (d.
GetY() < 0.0f) {
96 if (d.
GetZ() < 0.0f) {
102 m_nodes[proxyId].fatAABB = fatAABB;
107void DynamicAABBTree::InsertLeaf(
int leaf) {
115 AABB leafAABB = m_nodes[leaf].fatAABB;
118 while (!m_nodes[index].IsLeaf()) {
119 int leftChild = m_nodes[index].left;
120 int rightChild = m_nodes[index].right;
122 float area = m_nodes[index].fatAABB.GetSurfaceArea();
123 AABB combinedAABB = m_nodes[index].fatAABB.Merge(leafAABB);
124 float combinedArea = combinedAABB.GetSurfaceArea();
127 float cost = 2.0f * combinedArea;
128 float inheritanceCost = 2.0f * (combinedArea - area);
132 if (m_nodes[leftChild].IsLeaf()) {
133 costLeft = m_nodes[leftChild].fatAABB.Merge(leafAABB).GetSurfaceArea() + inheritanceCost;
135 float oldArea = m_nodes[leftChild].fatAABB.GetSurfaceArea();
136 float newArea = m_nodes[leftChild].fatAABB.Merge(leafAABB).GetSurfaceArea();
137 costLeft = (newArea - oldArea) + inheritanceCost;
142 if (m_nodes[rightChild].IsLeaf()) {
143 costRight = m_nodes[rightChild].fatAABB.Merge(leafAABB).GetSurfaceArea() + inheritanceCost;
145 float oldArea = m_nodes[rightChild].fatAABB.GetSurfaceArea();
146 float newArea = m_nodes[rightChild].fatAABB.Merge(leafAABB).GetSurfaceArea();
147 costRight = (newArea - oldArea) + inheritanceCost;
150 if (cost < costLeft && cost < costRight)
break;
152 index = (costLeft < costRight) ? leftChild : rightChild;
158 int oldParent = m_nodes[sibling].parent;
159 int newParent = AllocateNode();
160 m_nodes[newParent].parent = oldParent;
161 m_nodes[newParent].fatAABB = leafAABB.
Merge(m_nodes[sibling].fatAABB);
162 m_nodes[newParent].height = m_nodes[sibling].height + 1;
165 if (m_nodes[oldParent].left == sibling) {
166 m_nodes[oldParent].left = newParent;
168 m_nodes[oldParent].right = newParent;
174 m_nodes[newParent].left = sibling;
175 m_nodes[newParent].right = leaf;
176 m_nodes[sibling].parent = newParent;
177 m_nodes[leaf].parent = newParent;
180 int node = m_nodes[leaf].parent;
182 node = Balance(node);
184 int left = m_nodes[node].left;
185 int right = m_nodes[node].right;
187 m_nodes[node].height = 1 + std::max(m_nodes[left].
height, m_nodes[right].
height);
188 m_nodes[node].fatAABB = m_nodes[left].fatAABB.Merge(m_nodes[right].fatAABB);
190 node = m_nodes[node].parent;
194void DynamicAABBTree::RemoveLeaf(
int leaf) {
195 if (leaf == m_root) {
200 int parent = m_nodes[leaf].parent;
201 int grandParent = m_nodes[parent].parent;
202 int sibling = (m_nodes[parent].left == leaf) ? m_nodes[parent].right : m_nodes[parent].left;
205 if (m_nodes[grandParent].left == parent) {
206 m_nodes[grandParent].left = sibling;
208 m_nodes[grandParent].right = sibling;
210 m_nodes[sibling].parent = grandParent;
213 int node = grandParent;
215 node = Balance(node);
217 int left = m_nodes[node].left;
218 int right = m_nodes[node].right;
220 m_nodes[node].fatAABB = m_nodes[left].fatAABB.Merge(m_nodes[right].fatAABB);
221 m_nodes[node].height = 1 + std::max(m_nodes[left].
height, m_nodes[right].
height);
223 node = m_nodes[node].parent;
232int DynamicAABBTree::Balance(
int nodeId) {
233 if (m_nodes[nodeId].IsLeaf() || m_nodes[nodeId].
height < 2) {
237 int left = m_nodes[nodeId].left;
238 int right = m_nodes[nodeId].right;
240 int balance = m_nodes[right].height - m_nodes[left].height;
244 int rightLeft = m_nodes[right].left;
245 int rightRight = m_nodes[right].right;
248 m_nodes[right].left = nodeId;
249 m_nodes[right].parent = m_nodes[nodeId].parent;
250 m_nodes[nodeId].parent = right;
252 if (m_nodes[right].parent !=
NULL_NODE) {
253 if (m_nodes[m_nodes[right].parent].left == nodeId) {
254 m_nodes[m_nodes[right].parent].left = right;
256 m_nodes[m_nodes[right].parent].right = right;
263 if (m_nodes[rightLeft].
height > m_nodes[rightRight].
height) {
264 m_nodes[right].right = rightLeft;
265 m_nodes[nodeId].right = rightRight;
266 m_nodes[rightRight].parent = nodeId;
267 m_nodes[nodeId].fatAABB = m_nodes[left].fatAABB.Merge(m_nodes[rightRight].fatAABB);
268 m_nodes[right].fatAABB = m_nodes[nodeId].fatAABB.Merge(m_nodes[rightLeft].fatAABB);
269 m_nodes[nodeId].height = 1 + std::max(m_nodes[left].
height, m_nodes[rightRight].
height);
270 m_nodes[right].height = 1 + std::max(m_nodes[nodeId].
height, m_nodes[rightLeft].
height);
272 m_nodes[right].right = rightRight;
273 m_nodes[nodeId].right = rightLeft;
274 m_nodes[rightLeft].parent = nodeId;
275 m_nodes[nodeId].fatAABB = m_nodes[left].fatAABB.Merge(m_nodes[rightLeft].fatAABB);
276 m_nodes[right].fatAABB = m_nodes[nodeId].fatAABB.Merge(m_nodes[rightRight].fatAABB);
277 m_nodes[nodeId].height = 1 + std::max(m_nodes[left].
height, m_nodes[rightLeft].
height);
278 m_nodes[right].height = 1 + std::max(m_nodes[nodeId].
height, m_nodes[rightRight].
height);
286 int leftLeft = m_nodes[left].left;
287 int leftRight = m_nodes[left].right;
289 m_nodes[left].left = nodeId;
290 m_nodes[left].parent = m_nodes[nodeId].parent;
291 m_nodes[nodeId].parent = left;
294 if (m_nodes[m_nodes[left].parent].left == nodeId) {
295 m_nodes[m_nodes[left].parent].left = left;
297 m_nodes[m_nodes[left].parent].right = left;
303 if (m_nodes[leftLeft].
height > m_nodes[leftRight].
height) {
304 m_nodes[left].right = leftLeft;
305 m_nodes[nodeId].left = leftRight;
306 m_nodes[leftRight].parent = nodeId;
307 m_nodes[nodeId].fatAABB = m_nodes[right].fatAABB.Merge(m_nodes[leftRight].fatAABB);
308 m_nodes[left].fatAABB = m_nodes[nodeId].fatAABB.Merge(m_nodes[leftLeft].fatAABB);
309 m_nodes[nodeId].height = 1 + std::max(m_nodes[right].
height, m_nodes[leftRight].
height);
310 m_nodes[left].height = 1 + std::max(m_nodes[nodeId].
height, m_nodes[leftLeft].
height);
312 m_nodes[left].right = leftRight;
313 m_nodes[nodeId].left = leftLeft;
314 m_nodes[leftLeft].parent = nodeId;
315 m_nodes[nodeId].fatAABB = m_nodes[right].fatAABB.Merge(m_nodes[leftLeft].fatAABB);
316 m_nodes[left].fatAABB = m_nodes[nodeId].fatAABB.Merge(m_nodes[leftRight].fatAABB);
317 m_nodes[nodeId].height = 1 + std::max(m_nodes[right].
height, m_nodes[leftLeft].
height);
318 m_nodes[left].height = 1 + std::max(m_nodes[nodeId].
height, m_nodes[leftRight].
height);
330 std::stack<int> stack;
333 while (!stack.empty()) {
334 int nodeId = stack.top();
339 if (m_nodes[nodeId].fatAABB.Overlaps(queryAABB)) {
340 if (m_nodes[nodeId].IsLeaf()) {
341 bool shouldContinue = callback(nodeId);
342 if (!shouldContinue)
return;
344 stack.push(m_nodes[nodeId].left);
345 stack.push(m_nodes[nodeId].right);
352 const std::function<
bool(
int)>& callback)
const {
356 std::abs(direction.
GetX()) > 1e-8f ? 1.0f / direction.
GetX() : 1e8f,
357 std::abs(direction.
GetY()) > 1e-8f ? 1.0f / direction.
GetY() : 1e8f,
358 std::abs(direction.
GetZ()) > 1e-8f ? 1.0f / direction.
GetZ() : 1e8f
361 std::stack<int> stack;
364 while (!stack.empty()) {
365 int nodeId = stack.top();
370 const AABB& aabb = m_nodes[nodeId].fatAABB;
374 float tmax = maxDist;
376 for (
int i = 0; i < 3; ++i) {
377 float aabbMin, aabbMax, o, id;
378 if (i == 0) { aabbMin = aabb.
min.
GetX(); aabbMax = aabb.
max.
GetX(); o = origin.
GetX();
id = invDir.
GetX(); }
379 else if (i == 1) { aabbMin = aabb.
min.
GetY(); aabbMax = aabb.
max.
GetY(); o = origin.
GetY();
id = invDir.
GetY(); }
382 float t1 = (aabbMin - o) *
id;
383 float t2 = (aabbMax - o) *
id;
385 if (t1 > t2) std::swap(t1, t2);
386 tmin = std::max(tmin, t1);
387 tmax = std::min(tmax, t2);
389 if (tmin > tmax)
break;
392 if (tmin > tmax)
continue;
394 if (m_nodes[nodeId].IsLeaf()) {
395 if (!callback(nodeId))
return;
397 stack.push(m_nodes[nodeId].left);
398 stack.push(m_nodes[nodeId].right);
void Query(const AABB &queryAABB, const std::function< bool(int)> &callback) const
Visits every leaf whose fat AABB overlaps queryAABB; stop early by returning false from callback.
int Insert(const AABB &aabb, void *userData)
Adds a new proxy with a fattened AABB and returns its id.
bool MoveProxy(int proxyId, const AABB &newAABB, const Vector3D &displacement)
Refits a proxy's fat AABB to newAABB, re-inserting it only if it moved outside the fat margin.
void Remove(int proxyId)
Removes a proxy and rebalances the tree around it.
void RayCast(const Vector3D &origin, const Vector3D &direction, float maxDist, const std::function< bool(int)> &callback) const
Walks the tree along a ray, visiting candidate leaves within maxDist.
Collision shapes, the broadphase tree, and the world that steps them.
static constexpr int NULL_NODE
static constexpr float FAT_AABB_MARGIN
Root namespace for everything the engine exposes.
void Merge(const AABB &o)
Grows this box to also cover o.
AABB Fatten(float margin) const