Skip to content

Commit 4721ffe

Browse files
committed
Add octant visualization to GridMap
1 parent 3f63a40 commit 4721ffe

3 files changed

Lines changed: 236 additions & 7 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: 203 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
365493
void 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);
@@ -1072,15 +1204,23 @@ void GridMap::_notification(int p_what) {
10721204
_update_navigation_debug_edge_connections();
10731205
}
10741206
#endif // defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
1207+
10751208
_update_visibility();
1209+
_debug_update();
1210+
} break;
1211+
1212+
#ifdef DEBUG_ENABLED
1213+
case NOTIFICATION_EXIT_TREE: {
1214+
_debug_clear_octants();
10761215
} break;
1216+
#endif
10771217

10781218
case NOTIFICATION_TRANSFORM_CHANGED: {
10791219
Transform3D new_xform = get_global_transform();
10801220
if (new_xform == last_transform) {
10811221
break;
10821222
}
1083-
//update run
1223+
10841224
for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
10851225
_octant_transform(E.key);
10861226
}
@@ -1090,16 +1230,24 @@ void GridMap::_notification(int p_what) {
10901230
for (int i = 0; i < baked_meshes.size(); i++) {
10911231
RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
10921232
}
1233+
1234+
#ifdef DEBUG_ENABLED
1235+
for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1236+
OctantKey octant_key = E.key;
1237+
OctantDebug &octant_debug = *E.value;
1238+
if (octant_debug.debug_line_instance_rid.is_valid()) {
1239+
const Transform3D octant_transform = new_xform * (Transform3D(Basis(), Vector3(octant_key.x, octant_key.y, octant_key.z) * octant_size * cell_size));
1240+
RS::get_singleton()->instance_set_transform(octant_debug.debug_line_instance_rid, octant_transform);
1241+
}
1242+
}
1243+
#endif
10931244
} break;
10941245

10951246
case NOTIFICATION_EXIT_WORLD: {
10961247
for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
10971248
_octant_exit_world(E.key);
10981249
}
10991250

1100-
//_queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
1101-
//_update_octants_callback();
1102-
//_update_area_instances();
11031251
for (int i = 0; i < baked_meshes.size(); i++) {
11041252
RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID());
11051253
}
@@ -1127,6 +1275,15 @@ void GridMap::_update_visibility() {
11271275
for (int i = 0; i < baked_meshes.size(); i++) {
11281276
RS::get_singleton()->instance_set_visible(baked_meshes[i].instance, is_visible_in_tree());
11291277
}
1278+
1279+
#ifdef DEBUG_ENABLED
1280+
for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1281+
OctantDebug &octant_debug = *E.value;
1282+
if (octant_debug.debug_line_instance_rid.is_valid()) {
1283+
RS::get_singleton()->instance_set_visible(octant_debug.debug_line_instance_rid, is_visible_in_tree());
1284+
}
1285+
}
1286+
#endif
11301287
}
11311288

11321289
void GridMap::_queue_octants_dirty() {
@@ -1140,12 +1297,15 @@ void GridMap::_queue_octants_dirty() {
11401297

11411298
void GridMap::_recreate_octant_data() {
11421299
recreating_octants = true;
1300+
11431301
HashMap<IndexKey, Cell, IndexKey> cell_copy(cell_map);
11441302
_clear_internal();
11451303
for (const KeyValue<IndexKey, Cell> &E : cell_copy) {
11461304
set_cell_item(Vector3i(E.key), E.value.item, E.value.rot);
11471305
}
1306+
11481307
recreating_octants = false;
1308+
_debug_update();
11491309
}
11501310

11511311
void GridMap::_clear_internal() {
@@ -1160,6 +1320,10 @@ void GridMap::_clear_internal() {
11601320

11611321
octant_map.clear();
11621322
cell_map.clear();
1323+
#ifdef DEBUG_ENABLED
1324+
_debug_clear_octants();
1325+
_debug_update();
1326+
#endif
11631327
}
11641328

11651329
void GridMap::clear() {
@@ -1194,6 +1358,8 @@ void GridMap::_update_octants_callback() {
11941358

11951359
_update_visibility();
11961360
awaiting_update = false;
1361+
1362+
_debug_update_octants();
11971363
}
11981364

11991365
void GridMap::_bind_methods() {
@@ -1284,6 +1450,12 @@ void GridMap::_bind_methods() {
12841450
ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);
12851451
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
12861452

1453+
ClassDB::bind_method(D_METHOD("set_debug_show_octants", "enable"), &GridMap::set_debug_show_octants);
1454+
ClassDB::bind_method(D_METHOD("get_debug_show_octants"), &GridMap::get_debug_show_octants);
1455+
1456+
ClassDB::bind_method(D_METHOD("set_debug_octant_color", "color"), &GridMap::set_debug_octant_color);
1457+
ClassDB::bind_method(D_METHOD("get_debug_octant_color"), &GridMap::get_debug_octant_color);
1458+
12871459
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, MeshLibrary::get_class_static()), "set_mesh_library", "get_mesh_library");
12881460
#ifndef PHYSICS_3D_DISABLED
12891461
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, PhysicsMaterial::get_class_static()), "set_physics_material", "get_physics_material");
@@ -1304,6 +1476,9 @@ void GridMap::_bind_methods() {
13041476
#endif // PHYSICS_3D_DISABLED
13051477
ADD_GROUP("Navigation", "");
13061478
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation");
1479+
ADD_GROUP("Debug", "");
1480+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_show_octants"), "set_debug_show_octants", "get_debug_show_octants");
1481+
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_octant_color"), "set_debug_octant_color", "get_debug_octant_color");
13071482

13081483
BIND_CONSTANT(INVALID_CELL_ITEM);
13091484

@@ -1689,6 +1864,21 @@ RID GridMap::get_bake_mesh_instance(int p_idx) {
16891864
return baked_meshes[p_idx].instance;
16901865
}
16911866

1867+
void GridMap::set_debug_show_octants(bool p_enable) {
1868+
#ifdef DEBUG_ENABLED
1869+
if (debug_show_octants == p_enable) {
1870+
return;
1871+
}
1872+
1873+
debug_show_octants = p_enable;
1874+
_debug_update();
1875+
#endif
1876+
}
1877+
1878+
bool GridMap::get_debug_show_octants() const {
1879+
return debug_show_octants;
1880+
}
1881+
16921882
GridMap::GridMap() {
16931883
set_notify_transform(true);
16941884
#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
@@ -1857,10 +2047,16 @@ void GridMap::_navigation_map_changed(RID p_map) {
18572047

18582048
GridMap::~GridMap() {
18592049
clear();
1860-
#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
2050+
2051+
#ifdef DEBUG_ENABLED
2052+
_debug_clear_octants();
2053+
2054+
#ifndef NAVIGATION_3D_DISABLED
18612055
NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed));
18622056
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)
2057+
#endif // NAVIGATION_3D_DISABLED
2058+
2059+
#endif // DEBUG_ENABLED
18642060
}
18652061

18662062
#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;
@@ -337,6 +358,12 @@ class GridMap : public Node3D {
337358
Array get_bake_meshes();
338359
RID get_bake_mesh_instance(int p_idx);
339360

361+
void set_debug_show_octants(bool p_enable);
362+
bool get_debug_show_octants() const;
363+
364+
void set_debug_octant_color(const Color &p_color);
365+
Color get_debug_octant_color() const;
366+
340367
#ifndef NAVIGATION_3D_DISABLED
341368
private:
342369
static Callable _navmesh_source_geometry_parsing_callback;

0 commit comments

Comments
 (0)