navigation_region_3d.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /**************************************************************************/
  2. /* navigation_region_3d.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "navigation_region_3d.h"
  31. #include "mesh_instance_3d.h"
  32. #include "servers/navigation_server_3d.h"
  33. void NavigationRegion3D::set_enabled(bool p_enabled) {
  34. if (enabled == p_enabled) {
  35. return;
  36. }
  37. enabled = p_enabled;
  38. if (!is_inside_tree()) {
  39. return;
  40. }
  41. if (!enabled) {
  42. NavigationServer3D::get_singleton()->region_set_map(region, RID());
  43. } else {
  44. NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
  45. }
  46. #ifdef DEBUG_ENABLED
  47. if (debug_instance.is_valid()) {
  48. if (!is_enabled()) {
  49. if (debug_mesh.is_valid()) {
  50. if (debug_mesh->get_surface_count() > 0) {
  51. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_material()->get_rid());
  52. }
  53. if (debug_mesh->get_surface_count() > 1) {
  54. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_disabled_material()->get_rid());
  55. }
  56. }
  57. } else {
  58. if (debug_mesh.is_valid()) {
  59. if (debug_mesh->get_surface_count() > 0) {
  60. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, RID());
  61. }
  62. if (debug_mesh->get_surface_count() > 1) {
  63. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, RID());
  64. }
  65. }
  66. }
  67. }
  68. #endif // DEBUG_ENABLED
  69. update_gizmos();
  70. }
  71. bool NavigationRegion3D::is_enabled() const {
  72. return enabled;
  73. }
  74. void NavigationRegion3D::set_navigation_layers(uint32_t p_navigation_layers) {
  75. if (navigation_layers == p_navigation_layers) {
  76. return;
  77. }
  78. navigation_layers = p_navigation_layers;
  79. NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
  80. }
  81. uint32_t NavigationRegion3D::get_navigation_layers() const {
  82. return navigation_layers;
  83. }
  84. void NavigationRegion3D::set_navigation_layer_value(int p_layer_number, bool p_value) {
  85. ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
  86. ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
  87. uint32_t _navigation_layers = get_navigation_layers();
  88. if (p_value) {
  89. _navigation_layers |= 1 << (p_layer_number - 1);
  90. } else {
  91. _navigation_layers &= ~(1 << (p_layer_number - 1));
  92. }
  93. set_navigation_layers(_navigation_layers);
  94. }
  95. bool NavigationRegion3D::get_navigation_layer_value(int p_layer_number) const {
  96. ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
  97. ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
  98. return get_navigation_layers() & (1 << (p_layer_number - 1));
  99. }
  100. void NavigationRegion3D::set_enter_cost(real_t p_enter_cost) {
  101. ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
  102. if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
  103. return;
  104. }
  105. enter_cost = p_enter_cost;
  106. NavigationServer3D::get_singleton()->region_set_enter_cost(region, enter_cost);
  107. }
  108. real_t NavigationRegion3D::get_enter_cost() const {
  109. return enter_cost;
  110. }
  111. void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) {
  112. ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
  113. if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
  114. return;
  115. }
  116. travel_cost = p_travel_cost;
  117. NavigationServer3D::get_singleton()->region_set_travel_cost(region, travel_cost);
  118. }
  119. real_t NavigationRegion3D::get_travel_cost() const {
  120. return travel_cost;
  121. }
  122. RID NavigationRegion3D::get_region_rid() const {
  123. return region;
  124. }
  125. void NavigationRegion3D::_notification(int p_what) {
  126. switch (p_what) {
  127. case NOTIFICATION_ENTER_TREE: {
  128. if (enabled) {
  129. NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
  130. }
  131. #ifdef DEBUG_ENABLED
  132. if (NavigationServer3D::get_singleton()->get_debug_enabled()) {
  133. _update_debug_mesh();
  134. }
  135. #endif // DEBUG_ENABLED
  136. } break;
  137. case NOTIFICATION_TRANSFORM_CHANGED: {
  138. NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform());
  139. #ifdef DEBUG_ENABLED
  140. if (is_inside_tree() && debug_instance.is_valid()) {
  141. RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
  142. }
  143. #endif // DEBUG_ENABLED
  144. } break;
  145. case NOTIFICATION_EXIT_TREE: {
  146. NavigationServer3D::get_singleton()->region_set_map(region, RID());
  147. #ifdef DEBUG_ENABLED
  148. if (debug_instance.is_valid()) {
  149. RS::get_singleton()->instance_set_visible(debug_instance, false);
  150. }
  151. if (debug_edge_connections_instance.is_valid()) {
  152. RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
  153. }
  154. #endif // DEBUG_ENABLED
  155. } break;
  156. }
  157. }
  158. void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navigation_mesh) {
  159. if (p_navigation_mesh == navigation_mesh) {
  160. return;
  161. }
  162. if (navigation_mesh.is_valid()) {
  163. navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
  164. }
  165. navigation_mesh = p_navigation_mesh;
  166. if (navigation_mesh.is_valid()) {
  167. navigation_mesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
  168. }
  169. NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, p_navigation_mesh);
  170. #ifdef DEBUG_ENABLED
  171. if (is_inside_tree() && NavigationServer3D::get_singleton()->get_debug_enabled()) {
  172. if (navigation_mesh.is_valid()) {
  173. _update_debug_mesh();
  174. _update_debug_edge_connections_mesh();
  175. } else {
  176. if (debug_instance.is_valid()) {
  177. RS::get_singleton()->instance_set_visible(debug_instance, false);
  178. }
  179. if (debug_edge_connections_instance.is_valid()) {
  180. RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
  181. }
  182. }
  183. }
  184. #endif // DEBUG_ENABLED
  185. emit_signal(SNAME("navigation_mesh_changed"));
  186. update_gizmos();
  187. update_configuration_warnings();
  188. }
  189. Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
  190. return navigation_mesh;
  191. }
  192. struct BakeThreadsArgs {
  193. NavigationRegion3D *nav_region = nullptr;
  194. };
  195. void _bake_navigation_mesh(void *p_user_data) {
  196. BakeThreadsArgs *args = static_cast<BakeThreadsArgs *>(p_user_data);
  197. if (args->nav_region->get_navigation_mesh().is_valid()) {
  198. Ref<NavigationMesh> nav_mesh = args->nav_region->get_navigation_mesh()->duplicate();
  199. NavigationServer3D::get_singleton()->region_bake_navigation_mesh(nav_mesh, args->nav_region);
  200. args->nav_region->call_deferred(SNAME("_bake_finished"), nav_mesh);
  201. memdelete(args);
  202. } else {
  203. ERR_PRINT("Can't bake the navigation mesh if the `NavigationMesh` resource doesn't exist");
  204. args->nav_region->call_deferred(SNAME("_bake_finished"), Ref<NavigationMesh>());
  205. memdelete(args);
  206. }
  207. }
  208. void NavigationRegion3D::bake_navigation_mesh(bool p_on_thread) {
  209. ERR_FAIL_COND_MSG(bake_thread.is_started(), "Unable to start another bake request. The navigation mesh bake thread is already baking a navigation mesh.");
  210. BakeThreadsArgs *args = memnew(BakeThreadsArgs);
  211. args->nav_region = this;
  212. if (p_on_thread) {
  213. bake_thread.start(_bake_navigation_mesh, args);
  214. } else {
  215. _bake_navigation_mesh(args);
  216. }
  217. }
  218. void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
  219. set_navigation_mesh(p_nav_mesh);
  220. bake_thread.wait_to_finish();
  221. emit_signal(SNAME("bake_finished"));
  222. }
  223. PackedStringArray NavigationRegion3D::get_configuration_warnings() const {
  224. PackedStringArray warnings = Node::get_configuration_warnings();
  225. if (is_visible_in_tree() && is_inside_tree()) {
  226. if (!navigation_mesh.is_valid()) {
  227. warnings.push_back(RTR("A NavigationMesh resource must be set or created for this node to work."));
  228. }
  229. }
  230. return warnings;
  231. }
  232. void NavigationRegion3D::_bind_methods() {
  233. ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navigation_mesh"), &NavigationRegion3D::set_navigation_mesh);
  234. ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationRegion3D::get_navigation_mesh);
  235. ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion3D::set_enabled);
  236. ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion3D::is_enabled);
  237. ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationRegion3D::set_navigation_layers);
  238. ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationRegion3D::get_navigation_layers);
  239. ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationRegion3D::set_navigation_layer_value);
  240. ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationRegion3D::get_navigation_layer_value);
  241. ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion3D::get_region_rid);
  242. ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion3D::set_enter_cost);
  243. ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion3D::get_enter_cost);
  244. ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion3D::set_travel_cost);
  245. ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion3D::get_travel_cost);
  246. ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true));
  247. ClassDB::bind_method(D_METHOD("_bake_finished", "navigation_mesh"), &NavigationRegion3D::_bake_finished);
  248. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_mesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh");
  249. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
  250. ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
  251. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
  252. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
  253. ADD_SIGNAL(MethodInfo("navigation_mesh_changed"));
  254. ADD_SIGNAL(MethodInfo("bake_finished"));
  255. }
  256. #ifndef DISABLE_DEPRECATED
  257. // Compatibility with earlier 4.0 betas.
  258. bool NavigationRegion3D::_set(const StringName &p_name, const Variant &p_value) {
  259. if (p_name == "navmesh") {
  260. set_navigation_mesh(p_value);
  261. return true;
  262. }
  263. return false;
  264. }
  265. bool NavigationRegion3D::_get(const StringName &p_name, Variant &r_ret) const {
  266. if (p_name == "navmesh") {
  267. r_ret = get_navigation_mesh();
  268. return true;
  269. }
  270. return false;
  271. }
  272. #endif // DISABLE_DEPRECATED
  273. void NavigationRegion3D::_navigation_changed() {
  274. update_gizmos();
  275. update_configuration_warnings();
  276. #ifdef DEBUG_ENABLED
  277. _update_debug_edge_connections_mesh();
  278. #endif // DEBUG_ENABLED
  279. }
  280. #ifdef DEBUG_ENABLED
  281. void NavigationRegion3D::_navigation_map_changed(RID p_map) {
  282. if (is_inside_tree() && p_map == get_world_3d()->get_navigation_map()) {
  283. _update_debug_edge_connections_mesh();
  284. }
  285. }
  286. #endif // DEBUG_ENABLED
  287. NavigationRegion3D::NavigationRegion3D() {
  288. set_notify_transform(true);
  289. region = NavigationServer3D::get_singleton()->region_create();
  290. NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
  291. NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
  292. NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
  293. #ifdef DEBUG_ENABLED
  294. NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
  295. NavigationServer3D::get_singleton()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
  296. NavigationServer3D::get_singleton()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
  297. #endif // DEBUG_ENABLED
  298. }
  299. NavigationRegion3D::~NavigationRegion3D() {
  300. if (bake_thread.is_started()) {
  301. bake_thread.wait_to_finish();
  302. }
  303. if (navigation_mesh.is_valid()) {
  304. navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
  305. }
  306. ERR_FAIL_NULL(NavigationServer3D::get_singleton());
  307. NavigationServer3D::get_singleton()->free(region);
  308. #ifdef DEBUG_ENABLED
  309. NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
  310. NavigationServer3D::get_singleton()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
  311. NavigationServer3D::get_singleton()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
  312. ERR_FAIL_NULL(RenderingServer::get_singleton());
  313. if (debug_instance.is_valid()) {
  314. RenderingServer::get_singleton()->free(debug_instance);
  315. }
  316. if (debug_mesh.is_valid()) {
  317. RenderingServer::get_singleton()->free(debug_mesh->get_rid());
  318. }
  319. if (debug_edge_connections_instance.is_valid()) {
  320. RenderingServer::get_singleton()->free(debug_edge_connections_instance);
  321. }
  322. if (debug_edge_connections_mesh.is_valid()) {
  323. RenderingServer::get_singleton()->free(debug_edge_connections_mesh->get_rid());
  324. }
  325. #endif // DEBUG_ENABLED
  326. }
  327. #ifdef DEBUG_ENABLED
  328. void NavigationRegion3D::_update_debug_mesh() {
  329. if (Engine::get_singleton()->is_editor_hint()) {
  330. // don't update inside Editor as node 3d gizmo takes care of this
  331. // as collisions and selections for Editor Viewport need to be updated
  332. return;
  333. }
  334. if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
  335. if (debug_instance.is_valid()) {
  336. RS::get_singleton()->instance_set_visible(debug_instance, false);
  337. }
  338. return;
  339. }
  340. if (!navigation_mesh.is_valid()) {
  341. if (debug_instance.is_valid()) {
  342. RS::get_singleton()->instance_set_visible(debug_instance, false);
  343. }
  344. return;
  345. }
  346. if (!debug_instance.is_valid()) {
  347. debug_instance = RenderingServer::get_singleton()->instance_create();
  348. }
  349. if (!debug_mesh.is_valid()) {
  350. debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
  351. }
  352. debug_mesh->clear_surfaces();
  353. bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
  354. bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
  355. Vector<Vector3> vertices = navigation_mesh->get_vertices();
  356. if (vertices.size() == 0) {
  357. return;
  358. }
  359. int polygon_count = navigation_mesh->get_polygon_count();
  360. if (polygon_count == 0) {
  361. return;
  362. }
  363. Vector<Vector3> face_vertex_array;
  364. face_vertex_array.resize(polygon_count * 3);
  365. Vector<Color> face_color_array;
  366. if (enabled_geometry_face_random_color) {
  367. face_color_array.resize(polygon_count * 3);
  368. }
  369. Vector<Vector3> line_vertex_array;
  370. if (enabled_edge_lines) {
  371. line_vertex_array.resize(polygon_count * 6);
  372. }
  373. Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
  374. Ref<StandardMaterial3D> face_material = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_material();
  375. Ref<StandardMaterial3D> line_material = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_material();
  376. RandomPCG rand;
  377. Color polygon_color = debug_navigation_geometry_face_color;
  378. for (int i = 0; i < polygon_count; i++) {
  379. if (enabled_geometry_face_random_color) {
  380. // Generate the polygon color, slightly randomly modified from the settings one.
  381. polygon_color.set_hsv(debug_navigation_geometry_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_navigation_geometry_face_color.get_s(), debug_navigation_geometry_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
  382. polygon_color.a = debug_navigation_geometry_face_color.a;
  383. }
  384. Vector<int> polygon = navigation_mesh->get_polygon(i);
  385. face_vertex_array.push_back(vertices[polygon[0]]);
  386. face_vertex_array.push_back(vertices[polygon[1]]);
  387. face_vertex_array.push_back(vertices[polygon[2]]);
  388. if (enabled_geometry_face_random_color) {
  389. face_color_array.push_back(polygon_color);
  390. face_color_array.push_back(polygon_color);
  391. face_color_array.push_back(polygon_color);
  392. }
  393. if (enabled_edge_lines) {
  394. line_vertex_array.push_back(vertices[polygon[0]]);
  395. line_vertex_array.push_back(vertices[polygon[1]]);
  396. line_vertex_array.push_back(vertices[polygon[1]]);
  397. line_vertex_array.push_back(vertices[polygon[2]]);
  398. line_vertex_array.push_back(vertices[polygon[2]]);
  399. line_vertex_array.push_back(vertices[polygon[0]]);
  400. }
  401. }
  402. Array face_mesh_array;
  403. face_mesh_array.resize(Mesh::ARRAY_MAX);
  404. face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
  405. if (enabled_geometry_face_random_color) {
  406. face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
  407. }
  408. debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
  409. debug_mesh->surface_set_material(0, face_material);
  410. if (enabled_edge_lines) {
  411. Array line_mesh_array;
  412. line_mesh_array.resize(Mesh::ARRAY_MAX);
  413. line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
  414. debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
  415. debug_mesh->surface_set_material(1, line_material);
  416. }
  417. RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid());
  418. if (is_inside_tree()) {
  419. RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario());
  420. RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree());
  421. }
  422. if (!is_enabled()) {
  423. if (debug_mesh.is_valid()) {
  424. if (debug_mesh->get_surface_count() > 0) {
  425. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_material()->get_rid());
  426. }
  427. if (debug_mesh->get_surface_count() > 1) {
  428. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_disabled_material()->get_rid());
  429. }
  430. }
  431. } else {
  432. if (debug_mesh.is_valid()) {
  433. if (debug_mesh->get_surface_count() > 0) {
  434. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, RID());
  435. }
  436. if (debug_mesh->get_surface_count() > 1) {
  437. RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, RID());
  438. }
  439. }
  440. }
  441. }
  442. #endif // DEBUG_ENABLED
  443. #ifdef DEBUG_ENABLED
  444. void NavigationRegion3D::_update_debug_edge_connections_mesh() {
  445. if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
  446. if (debug_edge_connections_instance.is_valid()) {
  447. RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
  448. }
  449. return;
  450. }
  451. if (!is_inside_tree()) {
  452. return;
  453. }
  454. if (!navigation_mesh.is_valid()) {
  455. if (debug_edge_connections_instance.is_valid()) {
  456. RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
  457. }
  458. return;
  459. }
  460. if (!debug_edge_connections_instance.is_valid()) {
  461. debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
  462. }
  463. if (!debug_edge_connections_mesh.is_valid()) {
  464. debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
  465. }
  466. debug_edge_connections_mesh->clear_surfaces();
  467. float edge_connection_margin = NavigationServer3D::get_singleton()->map_get_edge_connection_margin(get_world_3d()->get_navigation_map());
  468. float half_edge_connection_margin = edge_connection_margin * 0.5;
  469. int connections_count = NavigationServer3D::get_singleton()->region_get_connections_count(region);
  470. if (connections_count == 0) {
  471. RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
  472. return;
  473. }
  474. Vector<Vector3> vertex_array;
  475. vertex_array.resize(connections_count * 6);
  476. for (int i = 0; i < connections_count; i++) {
  477. Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(region, i);
  478. Vector3 connection_pathway_end = NavigationServer3D::get_singleton()->region_get_connection_pathway_end(region, i);
  479. Vector3 direction_start_end = connection_pathway_start.direction_to(connection_pathway_end);
  480. Vector3 direction_end_start = connection_pathway_end.direction_to(connection_pathway_start);
  481. Vector3 start_right_dir = direction_start_end.cross(Vector3(0, 1, 0));
  482. Vector3 start_left_dir = -start_right_dir;
  483. Vector3 end_right_dir = direction_end_start.cross(Vector3(0, 1, 0));
  484. Vector3 end_left_dir = -end_right_dir;
  485. Vector3 left_start_pos = connection_pathway_start + (start_left_dir * half_edge_connection_margin);
  486. Vector3 right_start_pos = connection_pathway_start + (start_right_dir * half_edge_connection_margin);
  487. Vector3 left_end_pos = connection_pathway_end + (end_right_dir * half_edge_connection_margin);
  488. Vector3 right_end_pos = connection_pathway_end + (end_left_dir * half_edge_connection_margin);
  489. vertex_array.push_back(right_end_pos);
  490. vertex_array.push_back(left_start_pos);
  491. vertex_array.push_back(right_start_pos);
  492. vertex_array.push_back(left_end_pos);
  493. vertex_array.push_back(right_end_pos);
  494. vertex_array.push_back(right_start_pos);
  495. }
  496. if (vertex_array.size() == 0) {
  497. return;
  498. }
  499. Ref<StandardMaterial3D> edge_connections_material = NavigationServer3D::get_singleton()->get_debug_navigation_edge_connections_material();
  500. Array mesh_array;
  501. mesh_array.resize(Mesh::ARRAY_MAX);
  502. mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
  503. debug_edge_connections_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mesh_array);
  504. debug_edge_connections_mesh->surface_set_material(0, edge_connections_material);
  505. RS::get_singleton()->instance_set_base(debug_edge_connections_instance, debug_edge_connections_mesh->get_rid());
  506. RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, is_visible_in_tree());
  507. if (is_inside_tree()) {
  508. RS::get_singleton()->instance_set_scenario(debug_edge_connections_instance, get_world_3d()->get_scenario());
  509. }
  510. bool enable_edge_connections = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_connections();
  511. if (!enable_edge_connections) {
  512. RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
  513. }
  514. }
  515. #endif // DEBUG_ENABLED