Replace Octree by DynamicBVH in cull code
-Much greater pairing/unpairing performance -For now, using it for culling too, but this will change in a couple of days. -Added a paged allocator, to efficiently alloc/free some types of objects.
This commit is contained in:
parent
c4c211c3b7
commit
83058597cf
13 changed files with 1041 additions and 571 deletions
|
|
@ -49,7 +49,6 @@ DynamicBVH::Node *DynamicBVH::_create_node(Node *p_parent, void *p_data) {
|
|||
Node *node = memnew(Node);
|
||||
node->parent = p_parent;
|
||||
node->data = p_data;
|
||||
node->childs[1] = 0;
|
||||
return (node);
|
||||
}
|
||||
|
||||
|
|
@ -335,6 +334,7 @@ DynamicBVH::ID DynamicBVH::insert(const AABB &p_box, void *p_userdata) {
|
|||
|
||||
ID id;
|
||||
id.node = leaf;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
|
@ -389,12 +389,35 @@ void DynamicBVH::_extract_leaves(Node *p_node, List<ID> *r_elements) {
|
|||
}
|
||||
}
|
||||
|
||||
void DynamicBVH::set_index(uint32_t p_index) {
|
||||
ERR_FAIL_COND(bvh_root != nullptr);
|
||||
index = p_index;
|
||||
}
|
||||
|
||||
uint32_t DynamicBVH::get_index() const {
|
||||
return index;
|
||||
}
|
||||
|
||||
void DynamicBVH::get_elements(List<ID> *r_elements) {
|
||||
if (bvh_root) {
|
||||
_extract_leaves(bvh_root, r_elements);
|
||||
}
|
||||
}
|
||||
|
||||
int DynamicBVH::get_leaf_count() const {
|
||||
return total_leaves;
|
||||
}
|
||||
int DynamicBVH::get_max_depth() const {
|
||||
if (bvh_root) {
|
||||
int depth = 1;
|
||||
int max_depth = 0;
|
||||
bvh_root->get_max_depth(depth, max_depth);
|
||||
return max_depth;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DynamicBVH::~DynamicBVH() {
|
||||
clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -303,8 +350,67 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
|
|||
} while (depth > 0);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue