void build_recursive(Node * node, uint32_t depth, std::vector<std::shared_ptr<Traceable>> & objects) { Bounds3D nodeBounds = objects[0]->world_bounds(); for (size_t i = 0; i < objects.size(); i++) { nodeBounds = nodeBounds.add(objects[i]->world_bounds()); } node->bounds = nodeBounds; // Recursion limit was reached, create a new leaf if (objects.size() <= leafThreshold) { node->data.insert(node->data.end(), objects.begin(), objects.end()); return; } // Split the node based on its longest axis node->axis = nodeBounds.maximum_extent(); const size_t median = objects.size() >> 1; std::nth_element(objects.begin(), objects.begin() + median, objects.end(), ObjectComparator(node->axis)); node->position = objects[median]->world_bounds().center()[node->axis]; node->left = new Node(); node->right = new Node(); std::vector<std::shared_ptr<Traceable>> leftList(median); std::vector<std::shared_ptr<Traceable>> rightList(objects.size() - median); std::copy(objects.begin(), objects.begin() + median, leftList.begin()); std::copy(objects.begin() + median, objects.end(), rightList.begin()); build_recursive(node->left, depth + 1, leftList); build_recursive(node->right, depth + 1, rightList); }
void PhotonAccelerator::build_recursive(int left_index, int right_index, BVHNode *node, int depth) { static int MAX_NUM_PRIMITIVES_IN_LEAF = 4; static int MAX_DEPTH = 20; int n_objs = right_index - left_index; if (n_objs <= MAX_NUM_PRIMITIVES_IN_LEAF || depth == MAX_DEPTH) { node->makeLeaf(left_index, n_objs); } else { // Sort the hitpoints along the largest axis AABB& node_box = node->getAABB(); int sort_dim = node_box.getLargestAxis(); std::sort(hps.begin() + left_index, hps.begin() + right_index, [&] (Hitpoint* a, Hitpoint* b) -> bool { float ca = a->is.mPosition(sort_dim); float cb = b->is.mPosition(sort_dim); return ca < cb; }); // Find split index float mid = (node_box.mMax(sort_dim) + node_box.mMin(sort_dim)) * 0.5f; int split_index = left_index; float cb; do { cb = hps[split_index++]->is.mPosition(sort_dim); } while (cb <= mid && split_index < right_index); if (split_index == left_index || split_index == right_index) { split_index = static_cast<int>((left_index + right_index - 1) * 0.5f + 0.5f); } // Create left and right nodes with AABB BVHNode left_node; BVHNode right_node; AABB& left_box = left_node.getAABB(); AABB& right_box = right_node.getAABB(); std::for_each(hps.begin() + left_index, hps.begin() + split_index, [&] (Hitpoint* hp) { AABB aabb(hp->is.mPosition); aabb.grow(hp->radius); left_box.include(aabb); }); std::for_each(hps.begin() + split_index, hps.begin() + right_index, [&] (Hitpoint* hp) { AABB aabb(hp->is.mPosition); aabb.grow(hp->radius); right_box.include(aabb); }); int n_nodes = nodes.size(); nodes.push_back(left_node); nodes.push_back(right_node); // Initiate current node as interior node node->makeNode(n_nodes); // Recurse build_recursive(left_index, split_index, &nodes[n_nodes], depth + 1); build_recursive(split_index, right_index, &nodes[n_nodes + 1], depth + 1); } }
void PhotonAccelerator::build(const std::vector<Hitpoint*>& hitpoints) { hps = hitpoints; nodes.reserve(2 * hitpoints.size() - 1); BVHNode root; AABB& world_box = root.getAABB(); std::for_each(hps.begin(), hps.end(), [&] (Hitpoint* hp) { AABB aabb(hp->is.mPosition); aabb.grow(hp->radius); world_box.include(aabb); }); nodes.push_back(root); build_recursive(0, hps.size(), &nodes[0], 0); }
void build() { root = new Node(); build_recursive(root, 0, objects); initialized = true; }