123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- void _split_inform_references(uint32_t p_node_id) {
- TNode &node = _nodes[p_node_id];
- TLeaf &leaf = _node_get_leaf(node);
- for (int n = 0; n < leaf.num_items; n++) {
- uint32_t ref_id = leaf.get_item_ref_id(n);
- ItemRef &ref = _refs[ref_id];
- ref.tnode_id = p_node_id;
- ref.item_id = n;
- }
- }
- void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, uint16_t *group_b, const BVHABB_CLASS *temp_bounds, const BVHABB_CLASS full_bound) {
- // special case for low leaf sizes .. should static compile out
- if constexpr (MAX_ITEMS < 4) {
- uint32_t ind = group_a[0];
- // add to b
- group_b[num_b++] = ind;
- // remove from a
- group_a[0] = group_a[num_a - 1];
- num_a--;
- return;
- }
- POINT center = full_bound.calculate_center();
- POINT size = full_bound.calculate_size();
- int order[POINT::AXIS_COUNT];
- order[0] = size.min_axis_index();
- order[POINT::AXIS_COUNT - 1] = size.max_axis_index();
- static_assert(POINT::AXIS_COUNT <= 3, "BVH POINT::AXIS_COUNT has unexpected size");
- if constexpr (POINT::AXIS_COUNT == 3) {
- order[1] = 3 - (order[0] + order[2]);
- }
- // simplest case, split on the longest axis
- int split_axis = order[0];
- for (int a = 0; a < num_a; a++) {
- uint32_t ind = group_a[a];
- if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) {
- // add to b
- group_b[num_b++] = ind;
- // remove from a
- group_a[a] = group_a[num_a - 1];
- num_a--;
- // do this one again, as it has been replaced
- a--;
- }
- }
- // detect when split on longest axis failed
- int min_threshold = MAX_ITEMS / 4;
- int min_group_size[POINT::AXIS_COUNT];
- min_group_size[0] = MIN(num_a, num_b);
- if (min_group_size[0] < min_threshold) {
- // slow but sure .. first move everything back into a
- for (int b = 0; b < num_b; b++) {
- group_a[num_a++] = group_b[b];
- }
- num_b = 0;
- // now calculate the best split
- for (int axis = 1; axis < POINT::AXIS_COUNT; axis++) {
- split_axis = order[axis];
- int count = 0;
- for (int a = 0; a < num_a; a++) {
- uint32_t ind = group_a[a];
- if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) {
- count++;
- }
- }
- min_group_size[axis] = MIN(count, num_a - count);
- } // for axis
- // best axis
- int best_axis = 0;
- int best_min = min_group_size[0];
- for (int axis = 1; axis < POINT::AXIS_COUNT; axis++) {
- if (min_group_size[axis] > best_min) {
- best_min = min_group_size[axis];
- best_axis = axis;
- }
- }
- // now finally do the split
- if (best_min > 0) {
- split_axis = order[best_axis];
- for (int a = 0; a < num_a; a++) {
- uint32_t ind = group_a[a];
- if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) {
- // add to b
- group_b[num_b++] = ind;
- // remove from a
- group_a[a] = group_a[num_a - 1];
- num_a--;
- // do this one again, as it has been replaced
- a--;
- }
- }
- } // if there was a split!
- } // if the longest axis wasn't a good split
- // special case, none crossed threshold
- if (!num_b) {
- uint32_t ind = group_a[0];
- // add to b
- group_b[num_b++] = ind;
- // remove from a
- group_a[0] = group_a[num_a - 1];
- num_a--;
- }
- // opposite problem! :)
- if (!num_a) {
- uint32_t ind = group_b[0];
- // add to a
- group_a[num_a++] = ind;
- // remove from b
- group_b[0] = group_b[num_b - 1];
- num_b--;
- }
- }
- void _split_leaf_sort_groups(int &num_a, int &num_b, uint16_t *group_a, uint16_t *group_b, const BVHABB_CLASS *temp_bounds) {
- BVHABB_CLASS groupb_aabb;
- groupb_aabb.set_to_max_opposite_extents();
- for (int n = 0; n < num_b; n++) {
- int which = group_b[n];
- groupb_aabb.merge(temp_bounds[which]);
- }
- BVHABB_CLASS groupb_aabb_new;
- BVHABB_CLASS rest_aabb;
- float best_size = FLT_MAX;
- int best_candidate = -1;
- // find most likely from a to move into b
- for (int check = 0; check < num_a; check++) {
- rest_aabb.set_to_max_opposite_extents();
- groupb_aabb_new = groupb_aabb;
- // find aabb of all the rest
- for (int rest = 0; rest < num_a; rest++) {
- if (rest == check) {
- continue;
- }
- int which = group_a[rest];
- rest_aabb.merge(temp_bounds[which]);
- }
- groupb_aabb_new.merge(temp_bounds[group_a[check]]);
- // now compare the sizes
- float size = groupb_aabb_new.get_area() + rest_aabb.get_area();
- if (size < best_size) {
- best_size = size;
- best_candidate = check;
- }
- }
- // we should now have the best, move it from group a to group b
- group_b[num_b++] = group_a[best_candidate];
- // remove best candidate from group a
- num_a--;
- group_a[best_candidate] = group_a[num_a];
- }
- uint32_t split_leaf(uint32_t p_node_id, const BVHABB_CLASS &p_added_item_aabb) {
- return split_leaf_complex(p_node_id, p_added_item_aabb);
- }
- // aabb is the new inserted node
- uint32_t split_leaf_complex(uint32_t p_node_id, const BVHABB_CLASS &p_added_item_aabb) {
- VERBOSE_PRINT("split_leaf");
- // note the tnode before and AFTER splitting may be a different address
- // in memory because the vector could get relocated. So we need to reget
- // the tnode after the split
- BVH_ASSERT(_nodes[p_node_id].is_leaf());
- // first create child leaf nodes
- uint32_t *child_ids = (uint32_t *)alloca(sizeof(uint32_t) * MAX_CHILDREN);
- for (int n = 0; n < MAX_CHILDREN; n++) {
- // create node children
- TNode *child_node = _nodes.request(child_ids[n]);
- child_node->clear();
- // back link to parent
- child_node->parent_id = p_node_id;
- // make each child a leaf node
- node_make_leaf(child_ids[n]);
- }
- // don't get any leaves or nodes till AFTER the split
- TNode &tnode = _nodes[p_node_id];
- uint32_t orig_leaf_id = tnode.get_leaf_id();
- const TLeaf &orig_leaf = _node_get_leaf(tnode);
- // store the final child ids
- for (int n = 0; n < MAX_CHILDREN; n++) {
- tnode.children[n] = child_ids[n];
- }
- // mark as no longer a leaf node
- tnode.num_children = MAX_CHILDREN;
- // 2 groups, A and B, and assign children to each to split equally
- int max_children = orig_leaf.num_items + 1; // plus 1 for the wildcard .. the item being added
- //CRASH_COND(max_children > MAX_CHILDREN);
- uint16_t *group_a = (uint16_t *)alloca(sizeof(uint16_t) * max_children);
- uint16_t *group_b = (uint16_t *)alloca(sizeof(uint16_t) * max_children);
- // we are copying the ABBs. This is ugly, but we need one extra for the inserted item...
- BVHABB_CLASS *temp_bounds = (BVHABB_CLASS *)alloca(sizeof(BVHABB_CLASS) * max_children);
- int num_a = max_children;
- int num_b = 0;
- // setup - start with all in group a
- for (int n = 0; n < orig_leaf.num_items; n++) {
- group_a[n] = n;
- temp_bounds[n] = orig_leaf.get_aabb(n);
- }
- // wildcard
- int wildcard = orig_leaf.num_items;
- group_a[wildcard] = wildcard;
- temp_bounds[wildcard] = p_added_item_aabb;
- // we can choose here either an equal split, or just 1 in the new leaf
- _split_leaf_sort_groups_simple(num_a, num_b, group_a, group_b, temp_bounds, tnode.aabb);
- uint32_t wildcard_node = BVHCommon::INVALID;
- // now there should be equal numbers in both groups
- for (int n = 0; n < num_a; n++) {
- int which = group_a[n];
- if (which != wildcard) {
- const BVHABB_CLASS &source_item_aabb = orig_leaf.get_aabb(which);
- uint32_t source_item_ref_id = orig_leaf.get_item_ref_id(which);
- //const Item &source_item = orig_leaf.get_item(which);
- _node_add_item(tnode.children[0], source_item_ref_id, source_item_aabb);
- } else {
- wildcard_node = tnode.children[0];
- }
- }
- for (int n = 0; n < num_b; n++) {
- int which = group_b[n];
- if (which != wildcard) {
- const BVHABB_CLASS &source_item_aabb = orig_leaf.get_aabb(which);
- uint32_t source_item_ref_id = orig_leaf.get_item_ref_id(which);
- //const Item &source_item = orig_leaf.get_item(which);
- _node_add_item(tnode.children[1], source_item_ref_id, source_item_aabb);
- } else {
- wildcard_node = tnode.children[1];
- }
- }
- // now remove all items from the parent and replace with the child nodes
- _leaves.free(orig_leaf_id);
- // we should keep the references up to date!
- for (int n = 0; n < MAX_CHILDREN; n++) {
- _split_inform_references(tnode.children[n]);
- }
- refit_upward(p_node_id);
- BVH_ASSERT(wildcard_node != BVHCommon::INVALID);
- return wildcard_node;
- }
|