bool ray_aabb(ray_t* ray,aabb* box,intersection_response_t* resp) { float t_min = -100000.0f; // MIN VAL float t_max = 100000.0f; // MAX VAL float t1,t2; Vec3f Ac = box->pos + box->size*0.5; Vec3f p = Ac - ray->o; Vec3f d = ray->d; float f,e; Vec3f min = (box->pos - ray->o) / d; Vec3f max = (box->pos + box->size - ray->o) / d; for(size_t i=0;i<3;i++) { e = p.GetAxis(i); f = d.GetAxis(i); if(fabs(f) > 1.0E-9f) { float t1 = min.GetAxis(i); float t2 = max.GetAxis(i); if(t1 > t2) std::swap(t1,t2); if(t1 > t_min) t_min = t1; if(t2 < t_max) t_max = t2; if(t_min > t_max) return false; if(t_max < 0) return false; } else if( (-e -p.GetAxis(i) > 0) || (-e+p.GetAxis(i) < 0)) { return false; } } aabb_intersection_response_t* r = (aabb_intersection_response_t*) resp; r->t_min = t_min; r->t_max = t_max; return true; }
triangle_t* ray_tree_find_occluder(tree_t* tree, ray_t* ray, intersection_response_t &resp, float dist) { Vec3f o = ray->o; Vec3f d = ray->d; Vec3f inv_d = Inverse(d); ca_node_t* nodes = tree->nodes; ca_node_t* node = nodes; triangle_t* ret_p = 0; triangle_t* triangle_data = tree->triangle_data; int* index_list = tree->index_list; float t_min=0.0f,t_max=dist; // init stack stack_entry_t* stack = tree->stack; int entry_ptr=0,exit_ptr=1; Vec3f entry_v = o + d*t_min; Vec3f exit_v = o + d*t_max; stack[entry_ptr].node = node; stack[entry_ptr].p = entry_v; stack[exit_ptr].node = 0; stack[exit_ptr].p = exit_v; ca_node_t* near_node; ca_node_t* far_node; int i; // build stack while(node) { while(!node->is_leaf()) { unsigned axis = node->axis; float split_pos = node->split_pos; // determine near and far nodes if(stack[entry_ptr].p.GetAxis(axis) <= split_pos) { // enter point is on left side of split_position if(stack[exit_ptr].p.GetAxis(axis) <= split_pos) { // ray hit left child node = &nodes[node->data.inner_node.left_node]; continue; } // parallel //if(stack[exit_ptr].p.GetAxis(axis) >= split_pos && stack[exit_ptr].p.GetAxis(axis) <= (split_pos + KD_EPSILON)) if(stack[exit_ptr].p.GetAxis(axis) == split_pos) { // continue with right child node = &nodes[node->data.inner_node.right_node]; continue; } // ray hits both children far_node = &nodes[node->data.inner_node.right_node]; node = &nodes[node->data.inner_node.left_node]; } // ray origin is on right child else { // ray hits right only if(stack[exit_ptr].p.GetAxis(axis) > split_pos) { node = &nodes[node->data.inner_node.right_node]; continue; } // ray hits both, in opposite directions far_node = &nodes[node->data.inner_node.left_node]; node = &nodes[node->data.inner_node.right_node]; } // get distance to split position float t_split = (split_pos - o.GetAxis(axis)) * inv_d.GetAxis(axis); //4 d.GetAxis(axis); // set stack pointers int ptr = exit_ptr++; if(exit_ptr == entry_ptr) exit_ptr++; stack[exit_ptr].node = far_node; stack[exit_ptr].p = o + d * t_split; stack[exit_ptr].prev = ptr; } int start_index = node->data.leaf_node.list_index; int count = node->data.leaf_node.tri_count; float closest_depth = dist; ray_t r = *ray; bool retval = false; intersection_response_t _resp; for(int i=0; i < count; i++) { unsigned index = index_list[start_index + i]; triangle_t t = triangle_data[index]; if(ray_triangle(t.vertices,&r,&_resp)) { retval = true; if(_resp.depth < closest_depth) { ret_p = &triangle_data[index]; closest_depth = _resp.depth; resp = _resp; } } } if(retval) { return ret_p; } entry_ptr = exit_ptr; node = stack[exit_ptr].node; exit_ptr = stack[entry_ptr].prev; } return 0; }
triangle_t* ray_tree_intersection(tree_t* tree, ray_t* ray, intersection_response_t &resp) { Vec3f minpos = tree->min; Vec3f maxpos = tree->max; aabb box; box.pos = minpos; box.size = maxpos - minpos; if(!ray_aabb(ray,&box,&resp)) return 0; Vec3f o = ray->o; Vec3f d = ray->d; Vec3f inv_d = Inverse(d); ca_node_t* nodes = tree->nodes; ca_node_t* node = nodes; triangle_t* ret_p = 0; triangle_t* triangle_data = tree->triangle_data; int* index_list = tree->index_list; // get box extents float t_min=-FLT_MAX,t_max=FLT_MAX; Vec3f _min = (minpos - o) * inv_d; Vec3f _max = (maxpos - o) * inv_d; for(size_t i=0; i<3; i++) { float t1 = _min.GetAxis(i); float t2 = _max.GetAxis(i); if(t1 > t2) std::swap(t1,t2); if(t1 > t_min) t_min = t1; if(t2 < t_max) t_max = t2; } Vec3f enter = o + d*t_min; Vec3f exit = o + d*t_max; /* stack<stack_node_t,vector<stack_node_t>> candidates; int far_node; while(node) { while(!node->is_leaf()) { unsigned char axis = node->axis; float split_pos = node->split_pos; if(enter.GetAxis(axis) <= split_pos) { // left voxel if(exit.GetAxis(axis) <= split_pos) { // ray hits only left cell node = &nodes[node->data.inner_node.left_node]; continue; } //if(interval(exit.GetAxis(axis),split_pos)) { if(exit.GetAxis(axis) >= split_pos + KD_EPSILON) { // ray parallel to split plane, traverse right cell? node = &nodes[node->data.inner_node.right_node]; continue; } // ray hits both cells node = &nodes[node->data.inner_node.left_node]; far_node = node->data.inner_node.right_node; } else { // right voxel if(exit.GetAxis(axis) > split_pos) { // ray hits right cell only node = &nodes[node->data.inner_node.right_node]; continue; } // ray hits both cells node = &nodes[node->data.inner_node.right_node]; far_node = node->data.inner_node.left_node; } // distance to split position: float t = (split_pos - o.GetAxis(axis)) / d.GetAxis(axis); stack_node_t n; n.node = far_node; n.p = o + d*t; candidates.push(n); } int start_index = node->data.leaf_node.list_index; int count = node->data.leaf_node.tri_count; float closest_depth = 10000.0f; ray_t r = *ray; bool retval = false; intersection_response_t _resp; for(int i=0; i < count; i++) { unsigned index = index_list[start_index + i]; triangle_t t = triangle_data[index]; if(ray_triangle(t.vertices,&r,&_resp)) { retval = true; if(resp.depth < closest_depth) { ret_p = &triangle_data[index]; closest_depth = resp.depth; } } if(retval) return ret_p; } if(candidates.empty()) return 0; stack_node_t n = candidates.top(); candidates.pop(); enter = exit; exit = n.p; node = &nodes[n.node]; } return 0; */ // init stack stack_entry_t* stack = tree->stack; int entry_ptr=0,exit_ptr=1; Vec3f entry_v = o + d*t_min; Vec3f exit_v = o + d*t_max; if (t_min > 0.0f) stack[entry_ptr].p = o + d * t_min; else stack[entry_ptr].p = o; stack[entry_ptr].node = node; //stack[entry_ptr].p = entry_v; stack[exit_ptr].node = 0; stack[exit_ptr].p = exit_v; ca_node_t* near_node; ca_node_t* far_node; int i; // build stack while(node) { while(!node->is_leaf()) { unsigned axis = node->axis; float split_pos = node->split_pos; // determine near and far nodes if(stack[entry_ptr].p.GetAxis(axis) <= split_pos) { // enter point is on left side of split_position if(stack[exit_ptr].p.GetAxis(axis) <= split_pos) { // ray hit left child node = &nodes[node->data.inner_node.left_node]; continue; } // parallel //if(stack[exit_ptr].p.GetAxis(axis) >= split_pos && stack[exit_ptr].p.GetAxis(axis) <= (split_pos + KD_EPSILON)) if(stack[exit_ptr].p.GetAxis(axis) == split_pos) { // continue with right child node = &nodes[node->data.inner_node.right_node]; continue; } // ray hits both children far_node = &nodes[node->data.inner_node.right_node]; node = &nodes[node->data.inner_node.left_node]; } // ray origin is on right child else { // ray hits right only if(stack[exit_ptr].p.GetAxis(axis) > split_pos) { node = &nodes[node->data.inner_node.right_node]; continue; } // ray hits both, in opposite directions far_node = &nodes[node->data.inner_node.left_node]; node = &nodes[node->data.inner_node.right_node]; } // get distance to split position float t_split = (split_pos - o.GetAxis(axis)) * inv_d.GetAxis(axis); //4 d.GetAxis(axis); // set stack pointers int ptr = exit_ptr++; if(exit_ptr == entry_ptr) exit_ptr++; stack[exit_ptr].node = far_node; stack[exit_ptr].p = o + d * t_split; stack[exit_ptr].prev = ptr; } int start_index = node->data.leaf_node.list_index; int count = node->data.leaf_node.tri_count; float closest_depth = FLT_MAX; ray_t r = *ray; bool retval = false; intersection_response_t _resp; for(int i=0; i < count; i++) { unsigned index = index_list[start_index + i]; triangle_t t = triangle_data[index]; if(ray_triangle(t.vertices,&r,&_resp)) { retval = true; if(_resp.depth < closest_depth) { ret_p = &triangle_data[index]; closest_depth = _resp.depth; resp = _resp; } } } if(retval) { return ret_p; } entry_ptr = exit_ptr; node = stack[exit_ptr].node; exit_ptr = stack[entry_ptr].prev; } return 0; }