void PLODRessource::ray_test(Ray const& ray, PickResult::Options options, node::Node* owner, std::set<PickResult>& hits) { if (!is_pickable_) return; const auto* tree = pbr::ren::ModelDatabase::GetInstance()->GetModel(model_id_)->kdn_tree(); const uint32_t num_nodes = tree->num_nodes(); const uint32_t fan_factor = tree->fan_factor(); const uint32_t first_leaf = num_nodes - pow(fan_factor, tree->depth()); const auto owner_transform = owner->get_world_transform(); const auto world_origin = owner_transform * ray.origin_; bool has_hit = false; PickResult pick = PickResult(0.f, owner, ray.origin_, math::vec3(0.f, 0.f, 0.f), math::vec3(0.f, 1.f, 0.f), math::vec3(0.f, 1.f, 0.f), math::vec2(0.f, 0.f)); std::stack<pbr::node_t> candidates; // there is always an intersection with root node candidates.push(0); while (!candidates.empty()) { pbr::node_t current = candidates.top(); candidates.pop(); for (pbr::node_t k = 0; k < fan_factor; ++k) { pbr::node_t n = tree->GetChildId(current, k); if (n >= num_nodes) break; Ray hit_ray(ray.intersection(tree->bounding_boxes()[n])); if (hit_ray.t_max_ >= 0.f) { if (n >= first_leaf) { // leaf with intersecion, check if frontmost float dist = scm::math::length(owner_transform * hit_ray.origin_ - world_origin); if (!has_hit || dist < pick.distance) { pick.distance = dist; pick.position = hit_ray.origin_; has_hit = true; } } else { // add to stack if not leaf candidates.push(n); } } } } if (has_hit) hits.insert(pick); }
void LodResource::ray_test(Ray const& ray, int options, node::Node* owner, std::set<PickResult>& hits) { if (!is_pickable_) return; bool has_hit = false; PickResult pick = PickResult( 0.f, owner, ray.origin_, math::vec3(0.f, 0.f, 0.f), math::vec3(0.f, 1.f, 0.f), math::vec3(0.f, 1.f, 0.f), math::vec2(0.f, 0.f)); const auto model_transform = owner->get_cached_world_transform(); const auto world_origin = ray.origin_; const auto world_direction = scm::math::normalize(ray.direction_); lamure::ren::ray lod_ray(math::vec3f(world_origin), math::vec3f(world_direction), scm::math::length(ray.direction_)); lamure::ren::ray::intersection intersection; auto lod_node = reinterpret_cast<node::PLodNode*>(owner); float aabb_scale = 9.0f; unsigned int max_depth = 255; unsigned int surfel_skip = 1; bool wysiwyg = true; lamure::ren::controller* controller = lamure::ren::controller::get_instance(); lamure::model_t model_id = controller->deduce_model_id(lod_node->get_geometry_description()); if (lod_ray.intersect_model(model_id, math::mat4f(model_transform), aabb_scale, max_depth, surfel_skip, wysiwyg, intersection)) { has_hit = true; pick.distance = intersection.distance_; pick.world_position = intersection.position_; auto object_position = scm::math::inverse(model_transform) * gua::math::vec4(intersection.position_.x, intersection.position_.y, intersection.position_.z, 1.0); pick.position = math::vec3(object_position.x, object_position.y, object_position.z); pick.normal = intersection.normal_; } if (has_hit) { if (hits.empty()) { hits.insert(pick); } else if (pick.distance < hits.begin()->distance) { hits.insert(pick); } } }