intersection3f intersect(BVHAccelerator* bvh, int nodeid, const ray3f& ray, const intersect_func& intersect_elem) { // grab node auto& node = bvh->nodes[nodeid]; // intersect bbox if(not intersect_bbox(ray, node.bbox)) return intersection3f(); // recursively intersect nodes intersection3f intersection; // copy the ray to allow for shortening it auto sray = ray; if(node.leaf) { for(int idx = node.start; idx < node.end; idx ++) { auto i = bvh->prims[idx]; intersection3f sintersection = intersect_elem(i,sray); if(not sintersection.hit) continue; if(sintersection.ray_t > intersection.ray_t and intersection.hit) continue; intersection = sintersection; sray.tmax = intersection.ray_t; } } else { for(auto n : { node.n0, node.n1 }) { intersection3f sintersection = intersect(bvh,n,sray,intersect_elem); if(not sintersection.hit) continue; if(sintersection.ray_t > intersection.ray_t and intersection.hit) continue; intersection = sintersection; sray.tmax = intersection.ray_t; } } return intersection; }
bool intersect_shadow(BVHAccelerator* bvh, int nodeid, const ray3f& ray, const intersect_func& intersect_elem_shadow) { // grab node auto& node = bvh->nodes[nodeid]; // intersect bbox if(not intersect_bbox(ray, node.bbox)) return false; // recursively intersect nodes if(node.leaf) { // for(auto idx : range(node.start,node.end)) { for(int idx = node.start; idx < node.end; idx++) { auto i = bvh->prims[idx]; if(intersect_elem_shadow(i,ray)) return true; } } else { if(intersect_shadow(bvh,node.n0,ray,intersect_elem_shadow)) return true; if(intersect_shadow(bvh,node.n1,ray,intersect_elem_shadow)) return true; } return false; }
bool RayTracer::rayIntersectNodeShadow(const Vec3f& orig, const Vec3f& dir, const float maxval, const Node* node) const { // Test whether the ray intersects the node's bounding box at all if (!intersect_bbox(&orig.x, &dir.x, &(node->bbMin).x, &(node->bbMax).x, maxval)) { return false; } // If the node is a leaf node if (!node->leftChild && !node->rightChild) { return rayIntersectTriangles(orig, dir, node->startPrim, node->endPrim).triangle ? true : false; } if (rayIntersectNodeShadow(orig, dir, maxval, node->leftChild)) return true; if (rayIntersectNodeShadow(orig, dir, maxval, node->rightChild)) return true; return false; }
Hit RayTracer::rayIntersectNode(const Vec3f& orig, const Vec3f& dir, const float maxval, const Node* node) const { // Test whether the ray intersects the node's bounding box at all if (!intersect_bbox(&orig.x, &dir.x, &(node->bbMin).x, &(node->bbMax).x, maxval)) { return Hit(NULL); } // If the node is a leaf node if (!node->leftChild && !node->rightChild) { return rayIntersectTriangles(orig, dir, node->startPrim, node->endPrim); } Hit left = rayIntersectNode(orig, dir, maxval, node->leftChild); Hit right = rayIntersectNode(orig, dir, maxval, node->rightChild); if (!left.triangle && !right.triangle) return Hit(NULL); else if (left.tmin < right.tmin) return left; else return right; }
// intersect bounding box without returning bounds inline bool intersect_bbox(const ray3f& ray, const range3f& bbox) { float t0, t1; return intersect_bbox(ray,bbox,t0,t1); }