diff options
Diffstat (limited to 'modules/navigation/nav_map.cpp')
-rw-r--r-- | modules/navigation/nav_map.cpp | 254 |
1 files changed, 221 insertions, 33 deletions
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 91b13ba9c4..57d702e846 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -30,11 +30,14 @@ #include "nav_map.h" +#include "core/config/project_settings.h" #include "core/object/worker_thread_pool.h" #include "nav_agent.h" #include "nav_link.h" +#include "nav_obstacle.h" #include "nav_region.h" -#include <algorithm> + +#include <Obstacle2d.h> #define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a))) @@ -51,21 +54,33 @@ } void NavMap::set_up(Vector3 p_up) { + if (up == p_up) { + return; + } up = p_up; regenerate_polygons = true; } void NavMap::set_cell_size(real_t p_cell_size) { + if (cell_size == p_cell_size) { + return; + } cell_size = p_cell_size; regenerate_polygons = true; } void NavMap::set_edge_connection_margin(real_t p_edge_connection_margin) { + if (edge_connection_margin == p_edge_connection_margin) { + return; + } edge_connection_margin = p_edge_connection_margin; regenerate_links = true; } void NavMap::set_link_connection_radius(real_t p_link_connection_radius) { + if (link_connection_radius == p_link_connection_radius) { + return; + } link_connection_radius = p_link_connection_radius; regenerate_links = true; } @@ -522,9 +537,7 @@ gd::ClosestPointQueryResult NavMap::get_closest_point_info(const Vector3 &p_poin gd::ClosestPointQueryResult result; real_t closest_point_ds = FLT_MAX; - for (size_t i(0); i < polygons.size(); i++) { - const gd::Polygon &p = polygons[i]; - + for (const gd::Polygon &p : polygons) { // For each face check the distance to the point for (size_t point_id = 2; point_id < p.points.size(); point_id += 1) { const Face3 f(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos); @@ -549,7 +562,7 @@ void NavMap::add_region(NavRegion *p_region) { void NavMap::remove_region(NavRegion *p_region) { int64_t region_index = regions.find(p_region); - if (region_index != -1) { + if (region_index >= 0) { regions.remove_at_unordered(region_index); regenerate_links = true; } @@ -562,14 +575,14 @@ void NavMap::add_link(NavLink *p_link) { void NavMap::remove_link(NavLink *p_link) { int64_t link_index = links.find(p_link); - if (link_index != -1) { + if (link_index >= 0) { links.remove_at_unordered(link_index); regenerate_links = true; } } bool NavMap::has_agent(NavAgent *agent) const { - return (agents.find(agent) != -1); + return (agents.find(agent) >= 0); } void NavMap::add_agent(NavAgent *agent) { @@ -582,25 +595,57 @@ void NavMap::add_agent(NavAgent *agent) { void NavMap::remove_agent(NavAgent *agent) { remove_agent_as_controlled(agent); int64_t agent_index = agents.find(agent); - if (agent_index != -1) { + if (agent_index >= 0) { agents.remove_at_unordered(agent_index); agents_dirty = true; } } +bool NavMap::has_obstacle(NavObstacle *obstacle) const { + return (obstacles.find(obstacle) >= 0); +} + +void NavMap::add_obstacle(NavObstacle *obstacle) { + if (!has_obstacle(obstacle)) { + obstacles.push_back(obstacle); + obstacles_dirty = true; + } +} + +void NavMap::remove_obstacle(NavObstacle *obstacle) { + int64_t obstacle_index = obstacles.find(obstacle); + if (obstacle_index >= 0) { + obstacles.remove_at_unordered(obstacle_index); + obstacles_dirty = true; + } +} + void NavMap::set_agent_as_controlled(NavAgent *agent) { - const bool exist = (controlled_agents.find(agent) != -1); - if (!exist) { - ERR_FAIL_COND(!has_agent(agent)); - controlled_agents.push_back(agent); - agents_dirty = true; + remove_agent_as_controlled(agent); + if (agent->get_use_3d_avoidance()) { + int64_t agent_3d_index = active_3d_avoidance_agents.find(agent); + if (agent_3d_index < 0) { + active_3d_avoidance_agents.push_back(agent); + agents_dirty = true; + } + } else { + int64_t agent_2d_index = active_2d_avoidance_agents.find(agent); + if (agent_2d_index < 0) { + active_2d_avoidance_agents.push_back(agent); + agents_dirty = true; + } } } void NavMap::remove_agent_as_controlled(NavAgent *agent) { - int64_t active_avoidance_agent_index = controlled_agents.find(agent); - if (active_avoidance_agent_index != -1) { - controlled_agents.remove_at_unordered(active_avoidance_agent_index); + int64_t agent_3d_index = active_3d_avoidance_agents.find(agent); + if (agent_3d_index >= 0) { + active_3d_avoidance_agents.remove_at_unordered(agent_3d_index); + agents_dirty = true; + } + int64_t agent_2d_index = active_2d_avoidance_agents.find(agent); + if (agent_2d_index >= 0) { + active_2d_avoidance_agents.remove_at_unordered(agent_2d_index); agents_dirty = true; } } @@ -891,22 +936,30 @@ void NavMap::sync() { map_update_id = (map_update_id + 1) % 9999999; } - // Update agents tree. - if (agents_dirty) { - // cannot use LocalVector here as RVO library expects std::vector to build KdTree - std::vector<RVO::Agent *> raw_agents; - raw_agents.reserve(controlled_agents.size()); - for (NavAgent *controlled_agent : controlled_agents) { - raw_agents.push_back(controlled_agent->get_agent()); + // Do we have modified obstacle positions? + for (NavObstacle *obstacle : obstacles) { + if (obstacle->check_dirty()) { + obstacles_dirty = true; + } + } + // Do we have modified agent arrays? + for (NavAgent *agent : agents) { + if (agent->check_dirty()) { + agents_dirty = true; } - rvo.buildAgentTree(raw_agents); + } + + // Update avoidance worlds. + if (obstacles_dirty || agents_dirty) { + _update_rvo_simulation(); } regenerate_polygons = false; regenerate_links = false; + obstacles_dirty = false; agents_dirty = false; - // Performance Monitor + // Performance Monitor. pm_region_count = _new_pm_region_count; pm_agent_count = _new_pm_agent_count; pm_link_count = _new_pm_link_count; @@ -917,22 +970,155 @@ void NavMap::sync() { pm_edge_free_count = _new_pm_edge_free_count; } -void NavMap::compute_single_step(uint32_t index, NavAgent **agent) { - (*(agent + index))->get_agent()->computeNeighbors(&rvo); - (*(agent + index))->get_agent()->computeNewVelocity(deltatime); +void NavMap::_update_rvo_obstacles_tree_2d() { + int obstacle_vertex_count = 0; + for (NavObstacle *obstacle : obstacles) { + obstacle_vertex_count += obstacle->get_vertices().size(); + } + + // Cannot use LocalVector here as RVO library expects std::vector to build KdTree + std::vector<RVO2D::Obstacle2D *> raw_obstacles; + raw_obstacles.reserve(obstacle_vertex_count); + + // The following block is modified copy from RVO2D::AddObstacle() + // Obstacles are linked and depend on all other obstacles. + for (NavObstacle *obstacle : obstacles) { + const Vector3 &_obstacle_position = obstacle->get_position(); + const Vector<Vector3> &_obstacle_vertices = obstacle->get_vertices(); + + if (_obstacle_vertices.size() < 2) { + continue; + } + + std::vector<RVO2D::Vector2> rvo_2d_vertices; + rvo_2d_vertices.reserve(_obstacle_vertices.size()); + + uint32_t _obstacle_avoidance_layers = obstacle->get_avoidance_layers(); + + for (const Vector3 &_obstacle_vertex : _obstacle_vertices) { + rvo_2d_vertices.push_back(RVO2D::Vector2(_obstacle_vertex.x + _obstacle_position.x, _obstacle_vertex.z + _obstacle_position.z)); + } + + const size_t obstacleNo = raw_obstacles.size(); + + for (size_t i = 0; i < rvo_2d_vertices.size(); i++) { + RVO2D::Obstacle2D *rvo_2d_obstacle = new RVO2D::Obstacle2D(); + rvo_2d_obstacle->point_ = rvo_2d_vertices[i]; + rvo_2d_obstacle->avoidance_layers_ = _obstacle_avoidance_layers; + + if (i != 0) { + rvo_2d_obstacle->prevObstacle_ = raw_obstacles.back(); + rvo_2d_obstacle->prevObstacle_->nextObstacle_ = rvo_2d_obstacle; + } + + if (i == rvo_2d_vertices.size() - 1) { + rvo_2d_obstacle->nextObstacle_ = raw_obstacles[obstacleNo]; + rvo_2d_obstacle->nextObstacle_->prevObstacle_ = rvo_2d_obstacle; + } + + rvo_2d_obstacle->unitDir_ = normalize(rvo_2d_vertices[(i == rvo_2d_vertices.size() - 1 ? 0 : i + 1)] - rvo_2d_vertices[i]); + + if (rvo_2d_vertices.size() == 2) { + rvo_2d_obstacle->isConvex_ = true; + } else { + rvo_2d_obstacle->isConvex_ = (leftOf(rvo_2d_vertices[(i == 0 ? rvo_2d_vertices.size() - 1 : i - 1)], rvo_2d_vertices[i], rvo_2d_vertices[(i == rvo_2d_vertices.size() - 1 ? 0 : i + 1)]) >= 0.0f); + } + + rvo_2d_obstacle->id_ = raw_obstacles.size(); + + raw_obstacles.push_back(rvo_2d_obstacle); + } + } + + rvo_simulation_2d.kdTree_->buildObstacleTree(raw_obstacles); +} + +void NavMap::_update_rvo_agents_tree_2d() { + // Cannot use LocalVector here as RVO library expects std::vector to build KdTree. + std::vector<RVO2D::Agent2D *> raw_agents; + raw_agents.reserve(active_2d_avoidance_agents.size()); + for (NavAgent *agent : active_2d_avoidance_agents) { + raw_agents.push_back(agent->get_rvo_agent_2d()); + } + rvo_simulation_2d.kdTree_->buildAgentTree(raw_agents); +} + +void NavMap::_update_rvo_agents_tree_3d() { + // Cannot use LocalVector here as RVO library expects std::vector to build KdTree. + std::vector<RVO3D::Agent3D *> raw_agents; + raw_agents.reserve(active_3d_avoidance_agents.size()); + for (NavAgent *agent : active_3d_avoidance_agents) { + raw_agents.push_back(agent->get_rvo_agent_3d()); + } + rvo_simulation_3d.kdTree_->buildAgentTree(raw_agents); +} + +void NavMap::_update_rvo_simulation() { + if (obstacles_dirty) { + _update_rvo_obstacles_tree_2d(); + } + if (agents_dirty) { + _update_rvo_agents_tree_2d(); + _update_rvo_agents_tree_3d(); + } +} + +void NavMap::compute_single_avoidance_step_2d(uint32_t index, NavAgent **agent) { + (*(agent + index))->get_rvo_agent_2d()->computeNeighbors(&rvo_simulation_2d); + (*(agent + index))->get_rvo_agent_2d()->computeNewVelocity(&rvo_simulation_2d); + (*(agent + index))->get_rvo_agent_2d()->update(&rvo_simulation_2d); + (*(agent + index))->update(); +} + +void NavMap::compute_single_avoidance_step_3d(uint32_t index, NavAgent **agent) { + (*(agent + index))->get_rvo_agent_3d()->computeNeighbors(&rvo_simulation_3d); + (*(agent + index))->get_rvo_agent_3d()->computeNewVelocity(&rvo_simulation_3d); + (*(agent + index))->get_rvo_agent_3d()->update(&rvo_simulation_3d); + (*(agent + index))->update(); } void NavMap::step(real_t p_deltatime) { deltatime = p_deltatime; - if (controlled_agents.size() > 0) { - WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &NavMap::compute_single_step, controlled_agents.ptr(), controlled_agents.size(), -1, true, SNAME("NavigationMapAgents")); - WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); + + rvo_simulation_2d.setTimeStep(float(deltatime)); + rvo_simulation_3d.setTimeStep(float(deltatime)); + + if (active_2d_avoidance_agents.size() > 0) { + if (use_threads && avoidance_use_multiple_threads) { + WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &NavMap::compute_single_avoidance_step_2d, active_2d_avoidance_agents.ptr(), active_2d_avoidance_agents.size(), -1, true, SNAME("RVOAvoidanceAgents2D")); + WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); + } else { + for (NavAgent *agent : active_2d_avoidance_agents) { + agent->get_rvo_agent_2d()->computeNeighbors(&rvo_simulation_2d); + agent->get_rvo_agent_2d()->computeNewVelocity(&rvo_simulation_2d); + agent->get_rvo_agent_2d()->update(&rvo_simulation_2d); + agent->update(); + } + } + } + + if (active_3d_avoidance_agents.size() > 0) { + if (use_threads && avoidance_use_multiple_threads) { + WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &NavMap::compute_single_avoidance_step_3d, active_3d_avoidance_agents.ptr(), active_3d_avoidance_agents.size(), -1, true, SNAME("RVOAvoidanceAgents3D")); + WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); + } else { + for (NavAgent *agent : active_3d_avoidance_agents) { + agent->get_rvo_agent_3d()->computeNeighbors(&rvo_simulation_3d); + agent->get_rvo_agent_3d()->computeNewVelocity(&rvo_simulation_3d); + agent->get_rvo_agent_3d()->update(&rvo_simulation_3d); + agent->update(); + } + } } } void NavMap::dispatch_callbacks() { - for (NavAgent *agent : controlled_agents) { - agent->dispatch_callback(); + for (NavAgent *agent : active_2d_avoidance_agents) { + agent->dispatch_avoidance_callback(); + } + + for (NavAgent *agent : active_3d_avoidance_agents) { + agent->dispatch_avoidance_callback(); } } @@ -970,6 +1156,8 @@ void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys } NavMap::NavMap() { + avoidance_use_multiple_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_multiple_threads"); + avoidance_use_high_priority_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_high_priority_threads"); } NavMap::~NavMap() { |