@@ -362,6 +362,134 @@ bool GridMap::get_center_z() const {
362362 return center_z;
363363}
364364
365+ void GridMap::set_debug_octant_color (const Color &p_color) {
366+ #ifdef DEBUG_ENABLED
367+ if (debug_octant_color == p_color) {
368+ return ;
369+ }
370+
371+ debug_octant_color = p_color;
372+
373+ if (debug_octant_line_material.is_valid ()) {
374+ debug_octant_line_material->set_albedo (debug_octant_color);
375+ }
376+ #endif
377+ }
378+
379+ Color GridMap::get_debug_octant_color () const {
380+ return debug_octant_color;
381+ }
382+
383+ #ifdef DEBUG_ENABLED
384+ void GridMap::_debug_update () {
385+ if (debug_dirty || !is_inside_tree ()) {
386+ return ;
387+ }
388+ debug_dirty = true ;
389+
390+ callable_mp (this , &GridMap::_debug_update_octants).call_deferred ();
391+ }
392+
393+ void GridMap::_debug_update_octants () {
394+ debug_dirty = false ;
395+
396+ if (!debug_show_octants) {
397+ _debug_clear_octants ();
398+ return ;
399+ }
400+
401+ if (debug_octant_line_material.is_null ()) {
402+ debug_octant_line_material.instantiate ();
403+ debug_octant_line_material->set_shading_mode (StandardMaterial3D::SHADING_MODE_UNSHADED );
404+ debug_octant_line_material->set_transparency (StandardMaterial3D::TRANSPARENCY_ALPHA );
405+ debug_octant_line_material->set_flag (StandardMaterial3D::FLAG_DISABLE_FOG , true );
406+ debug_octant_line_material->set_albedo (debug_octant_color);
407+ }
408+
409+ Array debug_mesh_arrays = _build_octant_line_mesh_arrays ();
410+
411+ if (debug_octant_line_mesh_rid.is_null ()) {
412+ debug_octant_line_mesh_rid = RS::get_singleton ()->mesh_create ();
413+ }
414+ RS::get_singleton ()->mesh_clear (debug_octant_line_mesh_rid);
415+ RS::get_singleton ()->mesh_add_surface_from_arrays (debug_octant_line_mesh_rid, RSE ::PRIMITIVE_LINES , debug_mesh_arrays);
416+ RS::get_singleton ()->mesh_surface_set_material (debug_octant_line_mesh_rid, 0 , debug_octant_line_material->get_rid ());
417+
418+ RID debug_scenario = get_world_3d ()->get_scenario ();
419+ const Transform3D &gridmap_xform = get_global_transform ();
420+
421+ for (const KeyValue<OctantKey, Octant *> &ele : octant_map) {
422+ OctantKey octant_key = ele.key ;
423+ HashMap<OctantKey, OctantDebug *, OctantKey>::Iterator E = debug_octant_map.find (octant_key);
424+ if (!E) {
425+ OctantDebug *octant_debug = memnew (OctantDebug);
426+
427+ RID debug_octant_line_instance_rid = RS::get_singleton ()->instance_create ();
428+
429+ RS::get_singleton ()->instance_set_base (debug_octant_line_instance_rid, debug_octant_line_mesh_rid);
430+ RS::get_singleton ()->instance_set_scenario (debug_octant_line_instance_rid, debug_scenario);
431+
432+ octant_debug->debug_line_instance_rid = debug_octant_line_instance_rid;
433+
434+ E = debug_octant_map.insert (octant_key, octant_debug);
435+ }
436+
437+ OctantDebug &octant_debug = *E->value ;
438+ const Transform3D octant_transform = gridmap_xform * (Transform3D (Basis (), Vector3 (octant_key.x , octant_key.y , octant_key.z ) * octant_size * cell_size));
439+
440+ RS::get_singleton ()->instance_set_scenario (octant_debug.debug_line_instance_rid , debug_scenario);
441+ RS::get_singleton ()->instance_set_transform (octant_debug.debug_line_instance_rid , octant_transform);
442+ RS::get_singleton ()->instance_set_visible (octant_debug.debug_line_instance_rid , is_visible_in_tree ());
443+ }
444+ }
445+
446+ void GridMap::_debug_clear_octants () {
447+ for (const KeyValue<OctantKey, Octant *> &ele : octant_map) {
448+ OctantKey octant_key = ele.key ;
449+ HashMap<OctantKey, OctantDebug *, OctantKey>::Iterator E = debug_octant_map.find (octant_key);
450+ if (E) {
451+ OctantDebug &octant_debug = *E->value ;
452+
453+ if (octant_debug.debug_line_mesh_rid .is_valid ()) {
454+ RS::get_singleton ()->free_rid (octant_debug.debug_line_mesh_rid );
455+ octant_debug.debug_line_mesh_rid = RID ();
456+ }
457+ if (octant_debug.debug_line_instance_rid .is_valid ()) {
458+ RS::get_singleton ()->free_rid (octant_debug.debug_line_instance_rid );
459+ octant_debug.debug_line_instance_rid = RID ();
460+ }
461+
462+ memdelete (&octant_debug);
463+ }
464+ }
465+
466+ debug_octant_map.clear ();
467+ }
468+
469+ Array GridMap::_build_octant_line_mesh_arrays () const {
470+ AABB aabb;
471+ aabb.size = octant_size * cell_size;
472+
473+ Vector<Vector3> vertex_array;
474+ vertex_array.resize (24 );
475+ Vector3 *vertex_array_ptrw = vertex_array.ptrw ();
476+ int vertex_index = 0 ;
477+
478+ for (int i = 0 ; i < 12 ; i++) {
479+ Vector3 a, b;
480+ aabb.get_edge (i, a, b);
481+ vertex_array_ptrw[vertex_index++] = a;
482+ vertex_array_ptrw[vertex_index++] = b;
483+ }
484+
485+ Array mesh_arrays;
486+ mesh_arrays.resize (Mesh::ARRAY_MAX );
487+ mesh_arrays[Mesh::ARRAY_VERTEX ] = vertex_array;
488+
489+ return mesh_arrays;
490+ }
491+ #endif // DEBUG_ENABLED
492+
365493void GridMap::set_cell_item (const Vector3i &p_position, int p_item, int p_rot) {
366494 if (baked_meshes.size () && !recreating_octants) {
367495 // if you set a cell item, baked meshes go good bye
@@ -991,6 +1119,8 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
9911119 g.navigation_debug_edge_connections_mesh .unref ();
9921120 }
9931121 }
1122+
1123+ _debug_clear_octants ();
9941124#endif // DEBUG_ENABLED
9951125}
9961126
@@ -1040,9 +1170,11 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
10401170 g.navigation_debug_edge_connections_mesh .unref ();
10411171 }
10421172 }
1173+
1174+ _debug_clear_octants ();
10431175#endif // DEBUG_ENABLED
10441176
1045- // erase multimeshes
1177+ // Erase multimeshes.
10461178
10471179 for (int i = 0 ; i < g.multimesh_instances .size (); i++) {
10481180 RS::get_singleton ()->free_rid (g.multimesh_instances [i].instance );
@@ -1067,20 +1199,32 @@ void GridMap::_notification(int p_what) {
10671199 } break ;
10681200
10691201 case NOTIFICATION_ENTER_TREE : {
1070- #if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
1202+ #ifdef DEBUG_ENABLED
1203+ _debug_update ();
1204+
1205+ #ifndef NAVIGATION_3D_DISABLED
10711206 if (bake_navigation && NavigationServer3D::get_singleton ()->get_debug_navigation_enabled ()) {
10721207 _update_navigation_debug_edge_connections ();
10731208 }
1074- #endif // defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
1209+ #endif // NAVIGATION_3D_DISABLED
1210+
1211+ #endif // DEBUG_ENABLED
1212+
10751213 _update_visibility ();
10761214 } break ;
10771215
1216+ #ifdef DEBUG_ENABLED
1217+ case NOTIFICATION_EXIT_TREE : {
1218+ _debug_clear_octants ();
1219+ } break ;
1220+ #endif
1221+
10781222 case NOTIFICATION_TRANSFORM_CHANGED : {
10791223 Transform3D new_xform = get_global_transform ();
10801224 if (new_xform == last_transform) {
10811225 break ;
10821226 }
1083- // update run
1227+
10841228 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
10851229 _octant_transform (E.key );
10861230 }
@@ -1090,16 +1234,24 @@ void GridMap::_notification(int p_what) {
10901234 for (int i = 0 ; i < baked_meshes.size (); i++) {
10911235 RS::get_singleton ()->instance_set_transform (baked_meshes[i].instance , get_global_transform ());
10921236 }
1237+
1238+ #ifdef DEBUG_ENABLED
1239+ for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1240+ OctantKey octant_key = E.key ;
1241+ OctantDebug &octant_debug = *E.value ;
1242+ if (octant_debug.debug_line_instance_rid .is_valid ()) {
1243+ const Transform3D octant_transform = new_xform * (Transform3D (Basis (), Vector3 (octant_key.x , octant_key.y , octant_key.z ) * octant_size * cell_size));
1244+ RS::get_singleton ()->instance_set_transform (octant_debug.debug_line_instance_rid , octant_transform);
1245+ }
1246+ }
1247+ #endif
10931248 } break ;
10941249
10951250 case NOTIFICATION_EXIT_WORLD : {
10961251 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
10971252 _octant_exit_world (E.key );
10981253 }
10991254
1100- // _queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
1101- // _update_octants_callback();
1102- // _update_area_instances();
11031255 for (int i = 0 ; i < baked_meshes.size (); i++) {
11041256 RS::get_singleton ()->instance_set_scenario (baked_meshes[i].instance , RID ());
11051257 }
@@ -1127,6 +1279,15 @@ void GridMap::_update_visibility() {
11271279 for (int i = 0 ; i < baked_meshes.size (); i++) {
11281280 RS::get_singleton ()->instance_set_visible (baked_meshes[i].instance , is_visible_in_tree ());
11291281 }
1282+
1283+ #ifdef DEBUG_ENABLED
1284+ for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1285+ OctantDebug &octant_debug = *E.value ;
1286+ if (octant_debug.debug_line_instance_rid .is_valid ()) {
1287+ RS::get_singleton ()->instance_set_visible (octant_debug.debug_line_instance_rid , is_visible_in_tree ());
1288+ }
1289+ }
1290+ #endif
11301291}
11311292
11321293void GridMap::_queue_octants_dirty () {
@@ -1140,12 +1301,17 @@ void GridMap::_queue_octants_dirty() {
11401301
11411302void GridMap::_recreate_octant_data () {
11421303 recreating_octants = true ;
1304+
11431305 HashMap<IndexKey, Cell, IndexKey> cell_copy (cell_map);
11441306 _clear_internal ();
11451307 for (const KeyValue<IndexKey, Cell> &E : cell_copy) {
11461308 set_cell_item (Vector3i (E.key ), E.value .item , E.value .rot );
11471309 }
1310+
11481311 recreating_octants = false ;
1312+ #ifdef DEBUG_ENABLED
1313+ _debug_update ();
1314+ #endif
11491315}
11501316
11511317void GridMap::_clear_internal () {
@@ -1160,6 +1326,10 @@ void GridMap::_clear_internal() {
11601326
11611327 octant_map.clear ();
11621328 cell_map.clear ();
1329+ #ifdef DEBUG_ENABLED
1330+ _debug_clear_octants ();
1331+ _debug_update ();
1332+ #endif
11631333}
11641334
11651335void GridMap::clear () {
@@ -1194,6 +1364,10 @@ void GridMap::_update_octants_callback() {
11941364
11951365 _update_visibility ();
11961366 awaiting_update = false ;
1367+
1368+ #ifdef DEBUG_ENABLED
1369+ _debug_update_octants ();
1370+ #endif
11971371}
11981372
11991373void GridMap::_bind_methods () {
@@ -1284,6 +1458,12 @@ void GridMap::_bind_methods() {
12841458 ClassDB::bind_method (D_METHOD (" clear_baked_meshes" ), &GridMap::clear_baked_meshes);
12851459 ClassDB::bind_method (D_METHOD (" make_baked_meshes" , " gen_lightmap_uv" , " lightmap_uv_texel_size" ), &GridMap::make_baked_meshes, DEFVAL (false ), DEFVAL (0.1 ));
12861460
1461+ ClassDB::bind_method (D_METHOD (" set_debug_show_octants" , " enable" ), &GridMap::set_debug_show_octants);
1462+ ClassDB::bind_method (D_METHOD (" get_debug_show_octants" ), &GridMap::get_debug_show_octants);
1463+
1464+ ClassDB::bind_method (D_METHOD (" set_debug_octant_color" , " color" ), &GridMap::set_debug_octant_color);
1465+ ClassDB::bind_method (D_METHOD (" get_debug_octant_color" ), &GridMap::get_debug_octant_color);
1466+
12871467 ADD_PROPERTY (PropertyInfo (Variant::OBJECT , " mesh_library" , PROPERTY_HINT_RESOURCE_TYPE , MeshLibrary::get_class_static ()), " set_mesh_library" , " get_mesh_library" );
12881468#ifndef PHYSICS_3D_DISABLED
12891469 ADD_PROPERTY (PropertyInfo (Variant::OBJECT , " physics_material" , PROPERTY_HINT_RESOURCE_TYPE , PhysicsMaterial::get_class_static ()), " set_physics_material" , " get_physics_material" );
@@ -1304,6 +1484,9 @@ void GridMap::_bind_methods() {
13041484#endif // PHYSICS_3D_DISABLED
13051485 ADD_GROUP (" Navigation" , " " );
13061486 ADD_PROPERTY (PropertyInfo (Variant::BOOL , " bake_navigation" ), " set_bake_navigation" , " is_baking_navigation" );
1487+ ADD_GROUP (" Debug" , " " );
1488+ ADD_PROPERTY (PropertyInfo (Variant::BOOL , " debug_show_octants" ), " set_debug_show_octants" , " get_debug_show_octants" );
1489+ ADD_PROPERTY (PropertyInfo (Variant::COLOR , " debug_octant_color" ), " set_debug_octant_color" , " get_debug_octant_color" );
13071490
13081491 BIND_CONSTANT (INVALID_CELL_ITEM );
13091492
@@ -1689,6 +1872,21 @@ RID GridMap::get_bake_mesh_instance(int p_idx) {
16891872 return baked_meshes[p_idx].instance ;
16901873}
16911874
1875+ void GridMap::set_debug_show_octants (bool p_enable) {
1876+ #ifdef DEBUG_ENABLED
1877+ if (debug_show_octants == p_enable) {
1878+ return ;
1879+ }
1880+
1881+ debug_show_octants = p_enable;
1882+ _debug_update ();
1883+ #endif
1884+ }
1885+
1886+ bool GridMap::get_debug_show_octants () const {
1887+ return debug_show_octants;
1888+ }
1889+
16921890GridMap::GridMap () {
16931891 set_notify_transform (true );
16941892#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
@@ -1857,10 +2055,16 @@ void GridMap::_navigation_map_changed(RID p_map) {
18572055
18582056GridMap::~GridMap () {
18592057 clear ();
1860- #if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
2058+
2059+ #ifdef DEBUG_ENABLED
2060+ _debug_clear_octants ();
2061+
2062+ #ifndef NAVIGATION_3D_DISABLED
18612063 NavigationServer3D::get_singleton ()->disconnect (" map_changed" , callable_mp (this , &GridMap::_navigation_map_changed));
18622064 NavigationServer3D::get_singleton ()->disconnect (" navigation_debug_changed" , callable_mp (this , &GridMap::_update_navigation_debug_edge_connections));
1863- #endif // defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
2065+ #endif // NAVIGATION_3D_DISABLED
2066+
2067+ #endif // DEBUG_ENABLED
18642068}
18652069
18662070#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
0 commit comments