#include "bvh.h" #include "mesh.h" #include "ray.h" #include #include namespace mingfx { BVH::BVH() : root_(NULL) { } BVH::~BVH() { FreeNodeRecursive(root_); } void BVH::CreateFromMesh(const Mesh &mesh) { FreeNodeRecursive(root_); std::vector tri_boxes; for (int i=0; i &boxes) { FreeNodeRecursive(root_); root_ = new Node(); BuildHierarchyRecursive(root_, boxes); } void BVH::FreeNodeRecursive(Node* node) { if (node == NULL) return; FreeNodeRecursive(node->child1); FreeNodeRecursive(node->child2); delete node; } bool sort_by_x(const AABB &lhs, const AABB &rhs) { return (lhs.min()[0] + lhs.max()[0]) < (rhs.min()[0] + rhs.max()[0]); } bool sort_by_y(const AABB &lhs, const AABB &rhs) { return (lhs.min()[1] + lhs.max()[1]) < (rhs.min()[1] + rhs.max()[1]); } bool sort_by_z(const AABB &lhs, const AABB &rhs) { return (lhs.min()[2] + lhs.max()[2]) < (rhs.min()[2] + rhs.max()[2]); } void BVH::BuildHierarchyRecursive(Node *node, std::vector tri_boxes) { // got down to a leaf, a single box if (tri_boxes.size() == 1) { node->box = tri_boxes[0]; return; } // calc the full bounding box for this node for (int i=0; ibox = node->box + tri_boxes[i]; } // sort boxes along the longest axis Vector3 dims = node->box.Dimensions(); dims[0] = fabsf(dims[0]); dims[1] = fabsf(dims[1]); dims[2] = fabsf(dims[2]); if ((dims[0] > dims[1]) && (dims[0] > dims[2])) { std::sort(tri_boxes.begin(), tri_boxes.end(), sort_by_x); } else if ((dims[1] > dims[0]) && (dims[1] > dims[2])) { std::sort(tri_boxes.begin(), tri_boxes.end(), sort_by_y); } else { std::sort(tri_boxes.begin(), tri_boxes.end(), sort_by_z); } // assign half to child1 and half to child2 std::size_t const half_size = tri_boxes.size() / 2; std::vector left_boxes(tri_boxes.begin(), tri_boxes.begin() + half_size); std::vector right_boxes(tri_boxes.begin() + half_size, tri_boxes.end()); node->child1 = new Node(); BuildHierarchyRecursive(node->child1, left_boxes); node->child2 = new Node(); BuildHierarchyRecursive(node->child2, right_boxes); } std::vector BVH::IntersectAndReturnUserData(const Ray &r) const { std::vector data_list; IntersectRecursive(r, root_, &data_list); return data_list; } void BVH::IntersectRecursive(const Ray &r, Node *node, std::vector *data_list) const { float t; if (r.IntersectAABB(node->box, &t)) { if ((node->child1 == NULL) && (node->child2 == NULL)) { // reached a leaf node, add the object's user data to the list data_list->push_back(node->box.user_data()); } else { // go deeper and check children IntersectRecursive(r, node->child1, data_list); IntersectRecursive(r, node->child2, data_list); } } } } // end namespace