summaryrefslogtreecommitdiffstats
path: root/modules/navigation/nav_map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/navigation/nav_map.cpp')
-rw-r--r--modules/navigation/nav_map.cpp254
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() {