#include #include #include "BVH.hpp" BVHAccel::BVHAccel(std::vector p, int maxPrimsInNode, SplitMethod splitMethod) : maxPrimsInNode(std::min(255, maxPrimsInNode)), splitMethod(splitMethod), primitives(std::move(p)) { time_t start, stop; time(&start); if (primitives.empty()) return; root = recursiveBuild(primitives); time(&stop); double diff = difftime(stop, start); int hrs = (int)diff / 3600; int mins = ((int)diff / 60) - (hrs * 60); int secs = (int)diff - (hrs * 3600) - (mins * 60); printf( "\rBVH Generation complete: \nTime Taken: %i hrs, %i mins, %i secs\n\n", hrs, mins, secs); } BVHBuildNode* BVHAccel::recursiveBuild(std::vector objects) { BVHBuildNode* node = new BVHBuildNode(); // Compute bounds of all primitives in BVH node Bounds3 bounds; for (int i = 0; i < objects.size(); ++i) bounds = Union(bounds, objects[i]->getBounds()); if (objects.size() == 1) { // Create leaf _BVHBuildNode_ node->bounds = objects[0]->getBounds(); node->object = objects[0]; node->left = nullptr; node->right = nullptr; return node; } else if (objects.size() == 2) { node->left = recursiveBuild(std::vector{objects[0]}); node->right = recursiveBuild(std::vector{objects[1]}); node->bounds = Union(node->left->bounds, node->right->bounds); return node; } else { Bounds3 centroidBounds; for (int i = 0; i < objects.size(); ++i) centroidBounds = Union(centroidBounds, objects[i]->getBounds().Centroid()); int dim = centroidBounds.maxExtent(); switch (dim) { case 0: std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) { return f1->getBounds().Centroid().x < f2->getBounds().Centroid().x; }); break; case 1: std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) { return f1->getBounds().Centroid().y < f2->getBounds().Centroid().y; }); break; case 2: std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) { return f1->getBounds().Centroid().z < f2->getBounds().Centroid().z; }); break; } auto beginning = objects.begin(); auto middling = objects.begin() + (objects.size() / 2); auto ending = objects.end(); auto leftshapes = std::vector(beginning, middling); auto rightshapes = std::vector(middling, ending); assert(objects.size() == (leftshapes.size() + rightshapes.size())); node->left = recursiveBuild(leftshapes); node->right = recursiveBuild(rightshapes); node->bounds = Union(node->left->bounds, node->right->bounds); } return node; } Intersection BVHAccel::Intersect(const Ray& ray) const { Intersection isect; if (!root) return isect; isect = BVHAccel::getIntersection(root, ray); return isect; } Intersection BVHAccel::getIntersection(BVHBuildNode* node, const Ray& ray) const { // TODO Traverse the BVH to find intersection Vector3f invDir(1.0/ray.direction.x,1.0/ray.direction.y,1.0/ray.direction.z); std::arraydirIsNeg; dirIsNeg[0] = ray.direction.x>0 ? 0:1; dirIsNeg[1] = ray.direction.y>0 ? 0:1; dirIsNeg[2] = ray.direction.z>0 ? 0:1; if(!node->bounds.IntersectP(ray,invDir,dirIsNeg)) { return{}; } if(node->left == nullptr && node->right == nullptr) { return node->object->getIntersection(ray); } Intersection leaf_left = BVHAccel::getIntersection(node->left,ray); Intersection leaf_right = BVHAccel::getIntersection(node->right,ray); return leaf_left.distance < leaf_right.distance ? leaf_left:leaf_right; }