summaryrefslogtreecommitdiff
path: root/core/math/dynamic_bvh.h
diff options
context:
space:
mode:
Diffstat (limited to 'core/math/dynamic_bvh.h')
-rw-r--r--core/math/dynamic_bvh.h125
1 files changed, 116 insertions, 9 deletions
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
index 81d70d7469..cdea51c674 100644
--- a/core/math/dynamic_bvh.h
+++ b/core/math/dynamic_bvh.h
@@ -61,13 +61,10 @@ class DynamicBVH {
public:
struct ID {
- Node *node;
+ Node *node = nullptr;
public:
_FORCE_INLINE_ bool is_valid() const { return node != nullptr; }
- _FORCE_INLINE_ ID() {
- node = nullptr;
- }
};
private:
@@ -134,6 +131,48 @@ private:
(min.z <= b.max.z) &&
(max.z >= b.min.z));
}
+
+ _FORCE_INLINE_ bool intersects_convex(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
+ Vector3 half_extents = (max - min) * 0.5;
+ Vector3 ofs = min + half_extents;
+
+ for (int i = 0; i < p_plane_count; i++) {
+ const Plane &p = p_planes[i];
+ Vector3 point(
+ (p.normal.x > 0) ? -half_extents.x : half_extents.x,
+ (p.normal.y > 0) ? -half_extents.y : half_extents.y,
+ (p.normal.z > 0) ? -half_extents.z : half_extents.z);
+ point += ofs;
+ if (p.is_point_over(point)) {
+ return false;
+ }
+ }
+
+ // Make sure all points in the shape aren't fully separated from the AABB on
+ // each axis.
+ int bad_point_counts_positive[3] = { 0 };
+ int bad_point_counts_negative[3] = { 0 };
+
+ for (int k = 0; k < 3; k++) {
+ for (int i = 0; i < p_point_count; i++) {
+ if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) {
+ bad_point_counts_positive[k]++;
+ }
+ if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) {
+ bad_point_counts_negative[k]++;
+ }
+ }
+
+ if (bad_point_counts_negative[k] == p_point_count) {
+ return false;
+ }
+ if (bad_point_counts_positive[k] == p_point_count) {
+ return false;
+ }
+ }
+
+ return true;
+ }
};
struct Node {
@@ -144,14 +183,14 @@ private:
void *data;
};
- _FORCE_INLINE_ bool is_leaf() const { return data != nullptr; }
+ _FORCE_INLINE_ bool is_leaf() const { return childs[1] == nullptr; }
_FORCE_INLINE_ bool is_internal() const { return (!is_leaf()); }
_FORCE_INLINE_ int get_index_in_parent() const {
ERR_FAIL_COND_V(!parent, 0);
return (parent->childs[1] == this) ? 1 : 0;
}
- _FORCE_INLINE_ void get_max_depth(int depth, int &maxdepth) {
+ void get_max_depth(int depth, int &maxdepth) {
if (is_internal()) {
childs[0]->get_max_depth(depth + 1, maxdepth);
childs[1]->get_max_depth(depth + 1, maxdepth);
@@ -183,6 +222,7 @@ private:
int lkhd = -1;
int total_leaves = 0;
uint32_t opath = 0;
+ uint32_t index = 0;
enum {
ALLOCA_STACK_SIZE = 128
@@ -245,6 +285,9 @@ public:
void remove(const ID &p_id);
void get_elements(List<ID> *r_elements);
+ int get_leaf_count() const;
+ int get_max_depth() const;
+
/* Discouraged, but works as a reference on how it must be used */
struct DefaultQueryResult {
virtual bool operator()(void *p_data) = 0; //return true whether you want to continue the query
@@ -254,9 +297,13 @@ public:
template <class QueryResult>
_FORCE_INLINE_ void aabb_query(const AABB &p_aabb, QueryResult &r_result);
template <class QueryResult>
+ _FORCE_INLINE_ void convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result);
+ template <class QueryResult>
_FORCE_INLINE_ void ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result);
- DynamicBVH();
+ void set_index(uint32_t p_index);
+ uint32_t get_index() const;
+
~DynamicBVH();
};
@@ -278,8 +325,8 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
do {
- const Node *n = stack[depth - 1];
depth--;
+ const Node *n = stack[depth];
if (n->volume.intersects(volume)) {
if (n->is_internal()) {
if (depth > threshold) {
@@ -304,7 +351,66 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
}
template <class QueryResult>
+void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result) {
+ if (!bvh_root) {
+ return;
+ }
+
+ //generate a volume anyway to improve pre-testing
+ Volume volume;
+ for (int i = 0; i < p_point_count; i++) {
+ if (i == 0) {
+ volume.min = p_points[0];
+ volume.max = p_points[0];
+ } else {
+ volume.min.x = MIN(volume.min.x, p_points[i].x);
+ volume.min.y = MIN(volume.min.y, p_points[i].y);
+ volume.min.z = MIN(volume.min.z, p_points[i].z);
+
+ volume.max.x = MAX(volume.max.x, p_points[i].x);
+ volume.max.y = MAX(volume.max.y, p_points[i].y);
+ volume.max.z = MAX(volume.max.z, p_points[i].z);
+ }
+ }
+
+ const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *));
+ stack[0] = bvh_root;
+ int32_t depth = 1;
+ int32_t threshold = ALLOCA_STACK_SIZE - 2;
+
+ LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
+
+ do {
+ depth--;
+ const Node *n = stack[depth];
+ if (n->volume.intersects(volume) && n->volume.intersects_convex(p_planes, p_plane_count, p_points, p_point_count)) {
+ if (n->is_internal()) {
+ if (depth > threshold) {
+ if (aux_stack.empty()) {
+ aux_stack.resize(ALLOCA_STACK_SIZE * 2);
+ copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ } else {
+ aux_stack.resize(aux_stack.size() * 2);
+ }
+ stack = aux_stack.ptr();
+ threshold = aux_stack.size() - 2;
+ }
+ stack[depth++] = n->childs[0];
+ stack[depth++] = n->childs[1];
+ } else {
+ if (r_result(n->data)) {
+ return;
+ }
+ }
+ }
+ } while (depth > 0);
+}
+template <class QueryResult>
void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result) {
+ if (!bvh_root) {
+ return;
+ }
+
Vector3 ray_dir = (p_to - p_from);
ray_dir.normalize();
@@ -327,7 +433,8 @@ void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResu
LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
do {
- const Node *node = stack[--depth];
+ depth--;
+ const Node *node = stack[depth];
bounds[0] = node->volume.min;
bounds[1] = node->volume.max;
real_t tmin = 1.f, lambda_min = 0.f;