Skip to content

Commit cf1bf73

Browse files
committed
Merge pull request #118583 from YeldhamDev/gridmap_show_octants
Add octant visualization to `GridMap`
2 parents 78b2935 + 157b16f commit cf1bf73

3 files changed

Lines changed: 246 additions & 9 deletions

File tree

modules/gridmap/doc_classes/GridMap.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@
268268
<member name="collision_visibility_mode" type="int" setter="set_collision_visibility_mode" getter="get_collision_visibility_mode" enum="GridMap.DebugVisibilityMode" default="0">
269269
Show or hide the [GridMap]'s collision shapes. If set to [constant DEBUG_VISIBILITY_MODE_DEFAULT], this depends on the show collision debug settings.
270270
</member>
271+
<member name="debug_octant_color" type="Color" setter="set_debug_octant_color" getter="get_debug_octant_color" default="Color(1, 1, 1, 1)">
272+
The [Color] used for rendering octant debug visuals when [member debug_show_octants] is enabled.
273+
</member>
274+
<member name="debug_show_octants" type="bool" setter="set_debug_show_octants" getter="get_debug_show_octants" default="false">
275+
If [code]true[/code], shows debug visuals for octants.
276+
</member>
271277
<member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library">
272278
The assigned [MeshLibrary].
273279
</member>

modules/gridmap/grid_map.cpp

Lines changed: 213 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
383511
void 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

11501311
void GridMap::_queue_octants_dirty() {
@@ -1158,12 +1319,17 @@ void GridMap::_queue_octants_dirty() {
11581319

11591320
void 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

11691335
void 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

11831353
void 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

12171391
void 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+
17101908
GridMap::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

19032101
GridMap::~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)

modules/gridmap/grid_map.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,27 @@ class GridMap : public Node3D {
233233

234234
Vector<BakedMesh> baked_meshes;
235235

236+
bool debug_show_octants = false;
237+
Color debug_octant_color = Color(1.0, 1.0, 1.0, 1.0);
238+
#ifdef DEBUG_ENABLED
239+
bool debug_dirty = false;
240+
Ref<StandardMaterial3D> debug_octant_line_material;
241+
242+
void _debug_update();
243+
void _debug_update_octants();
244+
void _debug_clear_octants();
245+
246+
RID debug_octant_line_mesh_rid;
247+
248+
struct OctantDebug {
249+
RID debug_line_mesh_rid;
250+
RID debug_line_instance_rid;
251+
};
252+
HashMap<OctantKey, OctantDebug *, OctantKey> debug_octant_map;
253+
254+
Array _build_octant_line_mesh_arrays() const;
255+
#endif // DEBUG_ENABLED
256+
236257
protected:
237258
bool _set(const StringName &p_name, const Variant &p_value);
238259
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -341,6 +362,12 @@ class GridMap : public Node3D {
341362
Array get_bake_meshes();
342363
RID get_bake_mesh_instance(int p_idx);
343364

365+
void set_debug_show_octants(bool p_enable);
366+
bool get_debug_show_octants() const;
367+
368+
void set_debug_octant_color(const Color &p_color);
369+
Color get_debug_octant_color() const;
370+
344371
#ifndef NAVIGATION_3D_DISABLED
345372
private:
346373
static Callable _navmesh_source_geometry_parsing_callback;

0 commit comments

Comments
 (0)