25using TreeNodeID = uint32_t;
26inline constexpr TreeNodeID null_node = std::numeric_limits<TreeNodeID>::max();
30 TreeNodeID parent = null_node;
31 TreeNodeID left = null_node;
32 TreeNodeID right = null_node;
33 TreeNodeID next_free = null_node;
39 auto isAllocated()
const -> bool;
42 auto isLeaf()
const -> bool;
47 TreeNodeID
id = null_node;
52class TOAST_API AABBTree {
54 explicit AABBTree(
size_t expected_shapes = 0);
57 auto insert(
ShapeID shape,
const AABB& bounds) -> TreeNodeID;
58 void remove(TreeNodeID leaf_id);
60 auto updateLeaf(TreeNodeID leaf_id,
const AABB& tight_bounds) -> bool;
62 auto query(
const AABB& bounds,
ShapeID ignored_shape = {})
const -> std::vector<ShapeID>;
63 template<
typename Visit>
64 void raycast(glm::vec3 origin, glm::vec3 inv_dir,
float max_distance, Visit&& visit)
const;
66 auto debugNodes()
const -> std::vector<AABBTreeDebugNode>;
68 auto size()
const -> size_t;
70 auto validate()
const -> bool;
74 static auto fatMargin() -> float;
76 auto allocateNode() -> TreeNodeID;
77 void freeNode(TreeNodeID node_id);
78 void insertLeaf(TreeNodeID leaf_id);
79 void detachLeaf(TreeNodeID leaf_id);
80 void refitAncestors(TreeNodeID node_id);
81 auto balance(TreeNodeID node_id) -> TreeNodeID;
82 void recalculate(TreeNodeID node_id);
84 std::vector<TreeNode> m_nodes;
85 TreeNodeID m_root = null_node;
86 TreeNodeID m_free_list = null_node;
87 size_t m_active_node_count = 0;
90template<
typename Visit>
91void AABBTree::raycast(glm::vec3 origin, glm::vec3 inv_dir,
float max_distance, Visit&& visit)
const {
92 if (m_root == null_node) {
102 std::array<Pending, 64> stack;
105 float reach = max_distance;
106 const auto enters = [&](TreeNodeID id,
float& t_enter) {
107 const std::optional<AABB::RayHit> hit = m_nodes[id].bounds.intersectRay(origin, inv_dir);
108 if (!hit || hit->t_max < 0.0f || hit->t_min > reach) {
111 t_enter = std::max(hit->t_min, 0.0f);
116 if (!enters(m_root, t_root)) {
119 stack[count++] = {m_root, t_root};
122 const Pending pending = stack[--count];
124 if (pending.t_enter > reach) {
128 const TreeNode& node = m_nodes[pending.node];
130 reach = std::min(reach, visit(node.shape, pending.t_enter));
135 float t_right = 0.0f;
136 const bool hits_left = enters(node.left, t_left);
137 const bool hits_right = enters(node.right, t_right);
138 TOAST_ASSERT(count + 2 <= stack.size(),
"Physics",
"AABB tree ray stack is too small for the tree");
139 if (count + 2 > stack.size()) {
144 if (hits_left && hits_right) {
145 if (t_left <= t_right) {
146 stack[count++] = {node.right, t_right};
147 stack[count++] = {node.left, t_left};
149 stack[count++] = {node.left, t_left};
150 stack[count++] = {node.right, t_right};
152 }
else if (hits_left) {
153 stack[count++] = {node.left, t_left};
154 }
else if (hits_right) {
155 stack[count++] = {node.right, t_right};
Axis-aligned bounds node.
Public logging interface for the engine.
Shape identifiers, geometry, and runtime records.
Definition aabb_tree.hpp:45
Definition aabb_tree.hpp:28