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; }
// intersects the scene and return for any intersection bool intersect_shadow(Scene* scene, ray3f ray) { // foreach surface for(auto surface : scene->surfaces) { // if it is a quad if(surface->isquad) { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect quad if(intersect_quad(tray, surface->radius)) return true; } else { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect sphere if(intersect_sphere(tray, surface->radius)) return true; } } // foreach mesh for(auto mesh : scene->meshes) { // quads are not supported: check for error error_if_not(mesh->quad.empty(), "quad intersection is not supported"); // tranform the ray auto tray = transform_ray_inverse(mesh->frame, ray); // if it is accelerated if(mesh->bvh) { if(intersect_shadow(mesh->bvh, 0, tray, [mesh](int tid, ray3f tray){ // grab triangle auto triangle = mesh->triangle[tid]; // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // return if intersected return intersect_triangle(tray, v0, v1, v2);})) return true; } else { // foreach triangle for(auto triangle : mesh->triangle) { // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // intersect triangle if(intersect_triangle(tray, v0, v1, v2)) return true; } } } // no intersection found return false; }
bool geometry::intersect(nex::ray* ray) const { nex::ray object_ray(ray->origin * world_inverse, ray->direction * world_inverse, ray->max, ray->depth); float t; if (intersect_shadow(object_ray, &t) && (t > nex::EPSILON) && (t <= ray->max)) { ray->max = t; return true; } return false; }