@@ -380,6 +380,134 @@ bool GridMap::get_center_z() const {
380380 return center_z;
381381}
382382
383+ void GridMap::set_debug_octant_color (const Color &p_color) {
384+ #ifdef DEBUG_ENABLED
385+ if (debug_octant_color == p_color) {
386+ return ;
387+ }
388+
389+ debug_octant_color = p_color;
390+
391+ if (debug_octant_line_material.is_valid ()) {
392+ debug_octant_line_material->set_albedo (debug_octant_color);
393+ }
394+ #endif
395+ }
396+
397+ Color GridMap::get_debug_octant_color () const {
398+ return debug_octant_color;
399+ }
400+
401+ #ifdef DEBUG_ENABLED
402+ void GridMap::_debug_update () {
403+ if (debug_dirty || !is_inside_tree ()) {
404+ return ;
405+ }
406+ debug_dirty = true ;
407+
408+ callable_mp (this , &GridMap::_debug_update_octants).call_deferred ();
409+ }
410+
411+ void GridMap::_debug_update_octants () {
412+ debug_dirty = false ;
413+
414+ if (!debug_show_octants) {
415+ _debug_clear_octants ();
416+ return ;
417+ }
418+
419+ if (debug_octant_line_material.is_null ()) {
420+ debug_octant_line_material.instantiate ();
421+ debug_octant_line_material->set_shading_mode (StandardMaterial3D::SHADING_MODE_UNSHADED );
422+ debug_octant_line_material->set_transparency (StandardMaterial3D::TRANSPARENCY_ALPHA );
423+ debug_octant_line_material->set_flag (StandardMaterial3D::FLAG_DISABLE_FOG , true );
424+ debug_octant_line_material->set_albedo (debug_octant_color);
425+ }
426+
427+ Array debug_mesh_arrays = _build_octant_line_mesh_arrays ();
428+
429+ if (debug_octant_line_mesh_rid.is_null ()) {
430+ debug_octant_line_mesh_rid = RS::get_singleton ()->mesh_create ();
431+ }
432+ RS::get_singleton ()->mesh_clear (debug_octant_line_mesh_rid);
433+ RS::get_singleton ()->mesh_add_surface_from_arrays (debug_octant_line_mesh_rid, RSE ::PRIMITIVE_LINES , debug_mesh_arrays);
434+ RS::get_singleton ()->mesh_surface_set_material (debug_octant_line_mesh_rid, 0 , debug_octant_line_material->get_rid ());
435+
436+ RID debug_scenario = get_world_3d ()->get_scenario ();
437+ const Transform3D &gridmap_xform = get_global_transform ();
438+
439+ for (const KeyValue<OctantKey, Octant *> &ele : octant_map) {
440+ OctantKey octant_key = ele.key ;
441+ HashMap<OctantKey, OctantDebug *, OctantKey>::Iterator E = debug_octant_map.find (octant_key);
442+ if (!E) {
443+ OctantDebug *octant_debug = memnew (OctantDebug);
444+
445+ RID debug_octant_line_instance_rid = RS::get_singleton ()->instance_create ();
446+
447+ RS::get_singleton ()->instance_set_base (debug_octant_line_instance_rid, debug_octant_line_mesh_rid);
448+ RS::get_singleton ()->instance_set_scenario (debug_octant_line_instance_rid, debug_scenario);
449+
450+ octant_debug->debug_line_instance_rid = debug_octant_line_instance_rid;
451+
452+ E = debug_octant_map.insert (octant_key, octant_debug);
453+ }
454+
455+ OctantDebug &octant_debug = *E->value ;
456+ const Transform3D octant_transform = gridmap_xform * (Transform3D (Basis (), Vector3 (octant_key.x , octant_key.y , octant_key.z ) * octant_size * cell_size));
457+
458+ RS::get_singleton ()->instance_set_scenario (octant_debug.debug_line_instance_rid , debug_scenario);
459+ RS::get_singleton ()->instance_set_transform (octant_debug.debug_line_instance_rid , octant_transform);
460+ RS::get_singleton ()->instance_set_visible (octant_debug.debug_line_instance_rid , is_visible_in_tree ());
461+ }
462+ }
463+
464+ void GridMap::_debug_clear_octants () {
465+ for (const KeyValue<OctantKey, Octant *> &ele : octant_map) {
466+ OctantKey octant_key = ele.key ;
467+ HashMap<OctantKey, OctantDebug *, OctantKey>::Iterator E = debug_octant_map.find (octant_key);
468+ if (E) {
469+ OctantDebug &octant_debug = *E->value ;
470+
471+ if (octant_debug.debug_line_mesh_rid .is_valid ()) {
472+ RS::get_singleton ()->free_rid (octant_debug.debug_line_mesh_rid );
473+ octant_debug.debug_line_mesh_rid = RID ();
474+ }
475+ if (octant_debug.debug_line_instance_rid .is_valid ()) {
476+ RS::get_singleton ()->free_rid (octant_debug.debug_line_instance_rid );
477+ octant_debug.debug_line_instance_rid = RID ();
478+ }
479+
480+ memdelete (&octant_debug);
481+ }
482+ }
483+
484+ debug_octant_map.clear ();
485+ }
486+
487+ Array GridMap::_build_octant_line_mesh_arrays () const {
488+ AABB aabb;
489+ aabb.size = octant_size * cell_size;
490+
491+ Vector<Vector3> vertex_array;
492+ vertex_array.resize (24 );
493+ Vector3 *vertex_array_ptrw = vertex_array.ptrw ();
494+ int vertex_index = 0 ;
495+
496+ for (int i = 0 ; i < 12 ; i++) {
497+ Vector3 a, b;
498+ aabb.get_edge (i, a, b);
499+ vertex_array_ptrw[vertex_index++] = a;
500+ vertex_array_ptrw[vertex_index++] = b;
501+ }
502+
503+ Array mesh_arrays;
504+ mesh_arrays.resize (Mesh::ARRAY_MAX );
505+ mesh_arrays[Mesh::ARRAY_VERTEX ] = vertex_array;
506+
507+ return mesh_arrays;
508+ }
509+ #endif // DEBUG_ENABLED
510+
383511void GridMap::set_cell_item (const Vector3i &p_position, int p_item, int p_rot) {
384512 if (baked_meshes.size () && !recreating_octants) {
385513 // if you set a cell item, baked meshes go good bye
@@ -1009,6 +1137,8 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
10091137 g.navigation_debug_edge_connections_mesh .unref ();
10101138 }
10111139 }
1140+
1141+ _debug_clear_octants ();
10121142#endif // DEBUG_ENABLED
10131143}
10141144
@@ -1058,9 +1188,11 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
10581188 g.navigation_debug_edge_connections_mesh .unref ();
10591189 }
10601190 }
1191+
1192+ _debug_clear_octants ();
10611193#endif // DEBUG_ENABLED
10621194
1063- // erase multimeshes
1195+ // Erase multimeshes.
10641196
10651197 for (int i = 0 ; i < g.multimesh_instances .size (); i++) {
10661198 RS::get_singleton ()->free_rid (g.multimesh_instances [i].instance );
@@ -1085,20 +1217,32 @@ void GridMap::_notification(int p_what) {
10851217 } break ;
10861218
10871219 case NOTIFICATION_ENTER_TREE : {
1088- #if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
1220+ #ifdef DEBUG_ENABLED
1221+ _debug_update ();
1222+
1223+ #ifndef NAVIGATION_3D_DISABLED
10891224 if (bake_navigation && NavigationServer3D::get_singleton ()->get_debug_navigation_enabled ()) {
10901225 _update_navigation_debug_edge_connections ();
10911226 }
1092- #endif // defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
1227+ #endif // NAVIGATION_3D_DISABLED
1228+
1229+ #endif // DEBUG_ENABLED
1230+
10931231 _update_visibility ();
10941232 } break ;
10951233
1234+ #ifdef DEBUG_ENABLED
1235+ case NOTIFICATION_EXIT_TREE : {
1236+ _debug_clear_octants ();
1237+ } break ;
1238+ #endif
1239+
10961240 case NOTIFICATION_TRANSFORM_CHANGED : {
10971241 Transform3D new_xform = get_global_transform ();
10981242 if (new_xform == last_transform) {
10991243 break ;
11001244 }
1101- // update run
1245+
11021246 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
11031247 _octant_transform (E.key );
11041248 }
@@ -1108,16 +1252,24 @@ void GridMap::_notification(int p_what) {
11081252 for (int i = 0 ; i < baked_meshes.size (); i++) {
11091253 RS::get_singleton ()->instance_set_transform (baked_meshes[i].instance , get_global_transform ());
11101254 }
1255+
1256+ #ifdef DEBUG_ENABLED
1257+ for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1258+ OctantKey octant_key = E.key ;
1259+ OctantDebug &octant_debug = *E.value ;
1260+ if (octant_debug.debug_line_instance_rid .is_valid ()) {
1261+ const Transform3D octant_transform = new_xform * (Transform3D (Basis (), Vector3 (octant_key.x , octant_key.y , octant_key.z ) * octant_size * cell_size));
1262+ RS::get_singleton ()->instance_set_transform (octant_debug.debug_line_instance_rid , octant_transform);
1263+ }
1264+ }
1265+ #endif
11111266 } break ;
11121267
11131268 case NOTIFICATION_EXIT_WORLD : {
11141269 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
11151270 _octant_exit_world (E.key );
11161271 }
11171272
1118- // _queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
1119- // _update_octants_callback();
1120- // _update_area_instances();
11211273 for (int i = 0 ; i < baked_meshes.size (); i++) {
11221274 RS::get_singleton ()->instance_set_scenario (baked_meshes[i].instance , RID ());
11231275 }
@@ -1145,6 +1297,15 @@ void GridMap::_update_visibility() {
11451297 for (int i = 0 ; i < baked_meshes.size (); i++) {
11461298 RS::get_singleton ()->instance_set_visible (baked_meshes[i].instance , is_visible_in_tree ());
11471299 }
1300+
1301+ #ifdef DEBUG_ENABLED
1302+ for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1303+ OctantDebug &octant_debug = *E.value ;
1304+ if (octant_debug.debug_line_instance_rid .is_valid ()) {
1305+ RS::get_singleton ()->instance_set_visible (octant_debug.debug_line_instance_rid , is_visible_in_tree ());
1306+ }
1307+ }
1308+ #endif
11481309}
11491310
11501311void GridMap::_queue_octants_dirty () {
@@ -1158,12 +1319,17 @@ void GridMap::_queue_octants_dirty() {
11581319
11591320void GridMap::_recreate_octant_data () {
11601321 recreating_octants = true ;
1322+
11611323 HashMap<IndexKey, Cell, IndexKey> cell_copy (cell_map);
11621324 _clear_internal ();
11631325 for (const KeyValue<IndexKey, Cell> &E : cell_copy) {
11641326 set_cell_item (Vector3i (E.key ), E.value .item , E.value .rot );
11651327 }
1328+
11661329 recreating_octants = false ;
1330+ #ifdef DEBUG_ENABLED
1331+ _debug_update ();
1332+ #endif
11671333}
11681334
11691335void GridMap::_clear_internal () {
@@ -1178,6 +1344,10 @@ void GridMap::_clear_internal() {
11781344
11791345 octant_map.clear ();
11801346 cell_map.clear ();
1347+ #ifdef DEBUG_ENABLED
1348+ _debug_clear_octants ();
1349+ _debug_update ();
1350+ #endif
11811351}
11821352
11831353void GridMap::clear () {
@@ -1212,6 +1382,10 @@ void GridMap::_update_octants_callback() {
12121382
12131383 _update_visibility ();
12141384 awaiting_update = false ;
1385+
1386+ #ifdef DEBUG_ENABLED
1387+ _debug_update_octants ();
1388+ #endif
12151389}
12161390
12171391void GridMap::_bind_methods () {
@@ -1302,6 +1476,12 @@ void GridMap::_bind_methods() {
13021476 ClassDB::bind_method (D_METHOD (" clear_baked_meshes" ), &GridMap::clear_baked_meshes);
13031477 ClassDB::bind_method (D_METHOD (" make_baked_meshes" , " gen_lightmap_uv" , " lightmap_uv_texel_size" ), &GridMap::make_baked_meshes, DEFVAL (false ), DEFVAL (0.1 ));
13041478
1479+ ClassDB::bind_method (D_METHOD (" set_debug_show_octants" , " enable" ), &GridMap::set_debug_show_octants);
1480+ ClassDB::bind_method (D_METHOD (" get_debug_show_octants" ), &GridMap::get_debug_show_octants);
1481+
1482+ ClassDB::bind_method (D_METHOD (" set_debug_octant_color" , " color" ), &GridMap::set_debug_octant_color);
1483+ ClassDB::bind_method (D_METHOD (" get_debug_octant_color" ), &GridMap::get_debug_octant_color);
1484+
13051485 ADD_PROPERTY (PropertyInfo (Variant::OBJECT , " mesh_library" , PROPERTY_HINT_RESOURCE_TYPE , MeshLibrary::get_class_static ()), " set_mesh_library" , " get_mesh_library" );
13061486#ifndef PHYSICS_3D_DISABLED
13071487 ADD_PROPERTY (PropertyInfo (Variant::OBJECT , " physics_material" , PROPERTY_HINT_RESOURCE_TYPE , PhysicsMaterial::get_class_static ()), " set_physics_material" , " get_physics_material" );
@@ -1322,6 +1502,9 @@ void GridMap::_bind_methods() {
13221502#endif // PHYSICS_3D_DISABLED
13231503 ADD_GROUP (" Navigation" , " " );
13241504 ADD_PROPERTY (PropertyInfo (Variant::BOOL , " bake_navigation" ), " set_bake_navigation" , " is_baking_navigation" );
1505+ ADD_GROUP (" Debug" , " " );
1506+ ADD_PROPERTY (PropertyInfo (Variant::BOOL , " debug_show_octants" ), " set_debug_show_octants" , " get_debug_show_octants" );
1507+ ADD_PROPERTY (PropertyInfo (Variant::COLOR , " debug_octant_color" ), " set_debug_octant_color" , " get_debug_octant_color" );
13251508
13261509 BIND_CONSTANT (INVALID_CELL_ITEM );
13271510
@@ -1707,6 +1890,21 @@ RID GridMap::get_bake_mesh_instance(int p_idx) {
17071890 return baked_meshes[p_idx].instance ;
17081891}
17091892
1893+ void GridMap::set_debug_show_octants (bool p_enable) {
1894+ #ifdef DEBUG_ENABLED
1895+ if (debug_show_octants == p_enable) {
1896+ return ;
1897+ }
1898+
1899+ debug_show_octants = p_enable;
1900+ _debug_update ();
1901+ #endif
1902+ }
1903+
1904+ bool GridMap::get_debug_show_octants () const {
1905+ return debug_show_octants;
1906+ }
1907+
17101908GridMap::GridMap () {
17111909 set_notify_transform (true );
17121910#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
@@ -1902,10 +2100,16 @@ void GridMap::_navigation_map_changed(RID p_map) {
19022100
19032101GridMap::~GridMap () {
19042102 clear ();
1905- #if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
2103+
2104+ #ifdef DEBUG_ENABLED
2105+ _debug_clear_octants ();
2106+
2107+ #ifndef NAVIGATION_3D_DISABLED
19062108 NavigationServer3D::get_singleton ()->disconnect (" map_changed" , callable_mp (this , &GridMap::_navigation_map_changed));
19072109 NavigationServer3D::get_singleton ()->disconnect (" navigation_debug_changed" , callable_mp (this , &GridMap::_update_navigation_debug_edge_connections));
1908- #endif // defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
2110+ #endif // NAVIGATION_3D_DISABLED
2111+
2112+ #endif // DEBUG_ENABLED
19092113}
19102114
19112115#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
0 commit comments