TraversalState BVH::Traverse(TraversalState state, const SlimRay& ray, HitRecord* nearest, function<bool (uint32_t index, const SlimRay& ray, HitRecord* hit, bool* request_suspend)> intersector, bool resume) { // Precompute the inverse direction of the ray. vec3 inv_dir(1.0f / ray.direction.x, 1.0f / ray.direction.y, 1.0f / ray.direction.z); // Initialize traversal based on passed state. TraversalState traversal = state; bool request_suspend = false; if (resume) { if (traversal.state == TraversalState::State::FROM_PARENT) { goto resume_parent; } else if (traversal.state == TraversalState::State::FROM_SIBLING) { goto resume_sibling; } else { TERRLN("Must be in FROM_PARENT or FROM_SIBLING state to resume traversal!"); } } while (true) { switch (traversal.state) { case TraversalState::State::FROM_PARENT: if (!BoundingHit(_nodes[traversal.current].bounds, ray, inv_dir, nearest->t)) { // Ray missed the near child, try the far child. traversal.current = Sibling(traversal.current); traversal.state = TraversalState::State::FROM_SIBLING; } else if (_nodes[traversal.current].leaf) { // Ray hit the near child and it's a leaf node. request_suspend = false; traversal.hit = intersector(_nodes[traversal.current].index, ray, nearest, &request_suspend) || traversal.hit; if (request_suspend) goto suspend_traversal; resume_parent: traversal.current = Sibling(traversal.current); traversal.state = TraversalState::State::FROM_SIBLING; } else { // Ray hit the near child and it's an interior node. traversal.current = NearChild(traversal.current, ray.direction); traversal.state = TraversalState::State::FROM_PARENT; } break; case TraversalState::State::FROM_SIBLING: if (!BoundingHit(_nodes[traversal.current].bounds, ray, inv_dir, nearest->t)) { // Ray missed the far child, backtrack to the parent. traversal.current = _nodes[traversal.current].parent; traversal.state = TraversalState::State::FROM_CHILD; } else if (_nodes[traversal.current].leaf) { // Ray hit the far child and it's a leaf node. request_suspend = false; traversal.hit = intersector(_nodes[traversal.current].index, ray, nearest, &request_suspend) || traversal.hit; if (request_suspend) goto suspend_traversal; resume_sibling: traversal.current = _nodes[traversal.current].parent; traversal.state = TraversalState::State::FROM_CHILD; } else { // Ray hit the far child and it's an interior node. traversal.current = NearChild(traversal.current, ray.direction); traversal.state = TraversalState::State::FROM_PARENT; } break; case TraversalState::State::FROM_CHILD: if (traversal.current == 0) { // Traversal has finished. return traversal; } if (traversal.current == NearChild(_nodes[traversal.current].parent, ray.direction)) { // Coming back up through the near child, so traverse // to the far child. traversal.current = Sibling(traversal.current); traversal.state = TraversalState::State::FROM_SIBLING; } else { // Coming back up through the far child, so continue // backtracking through the parent. traversal.current = _nodes[traversal.current].parent; traversal.state = TraversalState::State::FROM_CHILD; } break; default: TERRLN("BVH traversal in unknown state!"); exit(EXIT_FAILURE); break; } } /// Shouldn't ever get here... TERRLN("Unexpected exit path in BVH traversal."); return TraversalState(); suspend_traversal: return traversal; }
bool BoundingBox::IntersectP(const Ray & ray) { //shadow ray and reflected ray returns false mistakenly //probably because they are in the box Vector3f pos(ray.getStartPosition()); Vector3f inv_dir(ray.getInvDirection()); float tx1 = (min_pos.x() - pos.x())*inv_dir.x(); float tx2 = (max_pos.x() - pos.x())*inv_dir.x(); float tmin = min(tx1, tx2); float tmax = max(tx1, tx2); float ty1 = (min_pos.y() - pos.y())*inv_dir.y(); float ty2 = (max_pos.y() - pos.y())*inv_dir.y(); tmin = max(tmin, min(ty1, ty2)); tmax = min(tmax, max(ty1, ty2)); //TODO, t should >0 if (tmax >= tmin) { float tz1 = (min_pos.z() - pos.z())*inv_dir.z(); float tz2 = (max_pos.z() - pos.z())*inv_dir.z(); tmin = max(tmin, min(tz1, tz2)); tmax = min(tmax, max(tz1, tz2)); //To confirm?? tmax>0 if(tmax >= tmin && tmax > 0) { //the line of ray will intersect //but maybe the t < 0 return true; } } return false; //Vector3f dir(ray.getDirection()); //Vector3f inv_dir(ray.getInvDirection()); //float tx1 = (min_pos.x() - dir.x())*inv_dir.x(); //float tx2 = (max_pos.x() - dir.x())*inv_dir.x(); //float tmin = min(tx1, tx2); //float tmax = max(tx1, tx2); //float ty1 = (min_pos.y() - dir.y())*inv_dir.y(); //float ty2 = (max_pos.y() - dir.y())*inv_dir.y(); //tmin = max(tmin, min(ty1, ty2)); //tmax = min(tmax, max(ty1, ty2)); ////TODO, t should >0 //if (tmax >= tmin) //{ // float tz1 = (min_pos.z() - dir.z())*inv_dir.z(); // float tz2 = (max_pos.z() - dir.z())*inv_dir.z(); // tmin = max(tmin, min(tz1, tz2)); // tmax = min(tmax, max(tz1, tz2)); // if(tmax >= tmin) // { // //the line of ray will intersect // //but maybe the t < 0 // //TODO // return true; // } //} //return false; }