#include "debug.h" #include "../rays/bvh.h" #include namespace PT { template void BVH::build(std::vector&& prims, size_t max_leaf_size) { // NOTE (PathTracer): // This BVH is parameterized on the type of the primitive it contains. This allows // us to build a BVH over any type that defines a certain interface. Specifically, // we use this to both build a BVH over triangles within each Tri_Mesh, and over // a variety of Objects (which might be Tri_Meshes, Spheres, etc.) in Pathtracer. // // The Primitive interface must implement these two functions: // BBox bbox() const; // Trace hit(const Ray& ray) const; // Hence, you may call bbox() and hit() on any value of type Primitive. // // Finally, also note that while a BVH is a tree structure, our BVH nodes don't // contain pointers to children, but rather indicies. This is because instead // of allocating each node individually, the BVH class contains a vector that // holds all of the nodes. Hence, to get the child of a node, you have to // look up the child index in this vector (e.g. nodes[node.l]). Similarly, // to create a new node, don't allocate one yourself - use BVH::new_node, which // returns the index of a newly added node. nodes.clear(); primitives = std::move(prims); // TODO (PathTracer): Task 3 // Construct a BVH from the given vector of primitives and maximum leaf // size configuration. The starter code builds a BVH with a // single leaf node (which is also the root) that encloses all the // primitives. BBox box; for(const Primitive& prim : primitives) box.enclose(prim.bbox()); new_node(box, 0, primitives.size(), 0, 0); } template Trace BVH::hit(const Ray& ray) const { // TODO (PathTracer): Task 3 // Implement ray - BVH intersection test. A ray intersects // with a BVH aggregate if and only if it intersects a primitive in // the BVH that is not an aggregate. // The starter code simply iterates through all the primitives. // Again, remember you can use hit() on any Primitive value. Trace ret; for(const Primitive& prim : primitives) { Trace hit = prim.hit(ray); ret = Trace::min(ret, hit); } return ret; } template BVH::BVH(std::vector&& prims, size_t max_leaf_size) { build(std::move(prims), max_leaf_size); } template bool BVH::Node::is_leaf() const { return l == 0 && r == 0; } template size_t BVH::new_node(BBox box, size_t start, size_t size, size_t l, size_t r) { Node n; n.bbox = box; n.start = start; n.size = size; n.l = l; n.r = r; nodes.push_back(n); return nodes.size() - 1; } template BBox BVH::bbox() const { return nodes[0].bbox; } template std::vector BVH::destructure() { nodes.clear(); return std::move(primitives); } template void BVH::clear() { nodes.clear(); primitives.clear(); } template size_t BVH::visualize(GL::Lines& lines, GL::Lines& active, size_t level, const Mat4& trans) const { std::stack> tstack; tstack.push({0,0}); size_t max_level = 0; if(nodes.empty()) return max_level; while (!tstack.empty()) { auto [idx, lvl] = tstack.top(); max_level = std::max(max_level, lvl); const Node& node = nodes[idx]; tstack.pop(); Vec3 color = lvl == level ? Vec3(1.0f, 0.0f, 0.0f) : Vec3(1.0f); GL::Lines& add = lvl == level ? active : lines; BBox box = node.bbox; box.transform(trans); Vec3 min = box.min, max = box.max; auto edge = [&](Vec3 a, Vec3 b) { add.add(a, b, color); }; edge(min, Vec3{max.x, min.y, min.z}); edge(min, Vec3{min.x, max.y, min.z}); edge(min, Vec3{min.x, min.y, max.z}); edge(max, Vec3{min.x, max.y, max.z}); edge(max, Vec3{max.x, min.y, max.z}); edge(max, Vec3{max.x, max.y, min.z}); edge(Vec3{min.x, max.y, min.z}, Vec3{max.x, max.y, min.z}); edge(Vec3{min.x, max.y, min.z}, Vec3{min.x, max.y, max.z}); edge(Vec3{min.x, min.y, max.z}, Vec3{max.x, min.y, max.z}); edge(Vec3{min.x, min.y, max.z}, Vec3{min.x, max.y, max.z}); edge(Vec3{max.x, min.y, min.z}, Vec3{max.x, max.y, min.z}); edge(Vec3{max.x, min.y, min.z}, Vec3{max.x, min.y, max.z}); if(node.l) tstack.push({node.l, lvl + 1}); if(node.r) tstack.push({node.r, lvl + 1}); if(!node.l && !node.r) { for(size_t i = node.start; i < node.start + node.size; i++) { size_t c = primitives[i].visualize(lines, active, level - lvl, trans); max_level = std::max(c, max_level); } } } return max_level; } }