Skip to content

Commit c370141

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

3 files changed

Lines changed: 230 additions & 5 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: 197 additions & 5 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
@@ -992,6 +1120,8 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
9921120
}
9931121
}
9941122
#endif // DEBUG_ENABLED
1123+
1124+
_debug_clear_octants();
9951125
}
9961126

9971127
void GridMap::_octant_clean_up(const OctantKey &p_key) {
@@ -1049,6 +1179,8 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
10491179
RS::get_singleton()->free_rid(g.multimesh_instances[i].multimesh);
10501180
}
10511181
g.multimesh_instances.clear();
1182+
1183+
_debug_clear_octants();
10521184
}
10531185

10541186
void GridMap::_notification(int p_what) {
@@ -1072,7 +1204,13 @@ 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+
case NOTIFICATION_EXIT_TREE: {
1213+
_debug_clear_octants();
10761214
} break;
10771215

10781216
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -1090,16 +1228,24 @@ void GridMap::_notification(int p_what) {
10901228
for (int i = 0; i < baked_meshes.size(); i++) {
10911229
RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
10921230
}
1231+
1232+
#ifdef DEBUG_ENABLED
1233+
for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1234+
OctantKey octant_key = E.key;
1235+
OctantDebug &octant_debug = *E.value;
1236+
if (octant_debug.debug_line_instance_rid.is_valid()) {
1237+
const Transform3D octant_transform = new_xform * (Transform3D(Basis(), Vector3(octant_key.x, octant_key.y, octant_key.z) * octant_size * cell_size));
1238+
RS::get_singleton()->instance_set_transform(octant_debug.debug_line_instance_rid, octant_transform);
1239+
}
1240+
}
1241+
#endif
10931242
} break;
10941243

10951244
case NOTIFICATION_EXIT_WORLD: {
10961245
for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
10971246
_octant_exit_world(E.key);
10981247
}
10991248

1100-
//_queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
1101-
//_update_octants_callback();
1102-
//_update_area_instances();
11031249
for (int i = 0; i < baked_meshes.size(); i++) {
11041250
RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID());
11051251
}
@@ -1127,6 +1273,15 @@ void GridMap::_update_visibility() {
11271273
for (int i = 0; i < baked_meshes.size(); i++) {
11281274
RS::get_singleton()->instance_set_visible(baked_meshes[i].instance, is_visible_in_tree());
11291275
}
1276+
1277+
#ifdef DEBUG_ENABLED
1278+
for (const KeyValue<OctantKey, OctantDebug *> &E : debug_octant_map) {
1279+
OctantDebug &octant_debug = *E.value;
1280+
if (octant_debug.debug_line_instance_rid.is_valid()) {
1281+
RS::get_singleton()->instance_set_visible(octant_debug.debug_line_instance_rid, is_visible_in_tree());
1282+
}
1283+
}
1284+
#endif
11301285
}
11311286

11321287
void GridMap::_queue_octants_dirty() {
@@ -1140,12 +1295,15 @@ void GridMap::_queue_octants_dirty() {
11401295

11411296
void GridMap::_recreate_octant_data() {
11421297
recreating_octants = true;
1298+
11431299
HashMap<IndexKey, Cell, IndexKey> cell_copy(cell_map);
11441300
_clear_internal();
11451301
for (const KeyValue<IndexKey, Cell> &E : cell_copy) {
11461302
set_cell_item(Vector3i(E.key), E.value.item, E.value.rot);
11471303
}
1304+
11481305
recreating_octants = false;
1306+
_debug_update();
11491307
}
11501308

11511309
void GridMap::_clear_internal() {
@@ -1160,6 +1318,8 @@ void GridMap::_clear_internal() {
11601318

11611319
octant_map.clear();
11621320
cell_map.clear();
1321+
_debug_clear_octants();
1322+
_debug_update();
11631323
}
11641324

11651325
void GridMap::clear() {
@@ -1194,6 +1354,8 @@ void GridMap::_update_octants_callback() {
11941354

11951355
_update_visibility();
11961356
awaiting_update = false;
1357+
1358+
_debug_update_octants();
11971359
}
11981360

11991361
void GridMap::_bind_methods() {
@@ -1284,6 +1446,12 @@ void GridMap::_bind_methods() {
12841446
ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);
12851447
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
12861448

1449+
ClassDB::bind_method(D_METHOD("set_debug_show_octants", "enable"), &GridMap::set_debug_show_octants);
1450+
ClassDB::bind_method(D_METHOD("get_debug_show_octants"), &GridMap::get_debug_show_octants);
1451+
1452+
ClassDB::bind_method(D_METHOD("set_debug_octant_color", "color"), &GridMap::set_debug_octant_color);
1453+
ClassDB::bind_method(D_METHOD("get_debug_octant_color"), &GridMap::get_debug_octant_color);
1454+
12871455
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, MeshLibrary::get_class_static()), "set_mesh_library", "get_mesh_library");
12881456
#ifndef PHYSICS_3D_DISABLED
12891457
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, PhysicsMaterial::get_class_static()), "set_physics_material", "get_physics_material");
@@ -1304,6 +1472,9 @@ void GridMap::_bind_methods() {
13041472
#endif // PHYSICS_3D_DISABLED
13051473
ADD_GROUP("Navigation", "");
13061474
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation");
1475+
ADD_GROUP("Debug", "");
1476+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_show_octants"), "set_debug_show_octants", "get_debug_show_octants");
1477+
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_octant_color"), "set_debug_octant_color", "get_debug_octant_color");
13071478

13081479
BIND_CONSTANT(INVALID_CELL_ITEM);
13091480

@@ -1689,6 +1860,21 @@ RID GridMap::get_bake_mesh_instance(int p_idx) {
16891860
return baked_meshes[p_idx].instance;
16901861
}
16911862

1863+
void GridMap::set_debug_show_octants(bool p_enable) {
1864+
#ifdef DEBUG_ENABLED
1865+
if (debug_show_octants == p_enable) {
1866+
return;
1867+
}
1868+
1869+
debug_show_octants = p_enable;
1870+
_debug_update();
1871+
#endif
1872+
}
1873+
1874+
bool GridMap::get_debug_show_octants() const {
1875+
return debug_show_octants;
1876+
}
1877+
16921878
GridMap::GridMap() {
16931879
set_notify_transform(true);
16941880
#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
@@ -1857,10 +2043,16 @@ void GridMap::_navigation_map_changed(RID p_map) {
18572043

18582044
GridMap::~GridMap() {
18592045
clear();
1860-
#if defined(DEBUG_ENABLED) && !defined(NAVIGATION_3D_DISABLED)
2046+
2047+
#ifdef DEBUG_ENABLED
2048+
_debug_clear_octants();
2049+
2050+
#ifndef NAVIGATION_3D_DISABLED
18612051
NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed));
18622052
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)
2053+
#endif // NAVIGATION_3D_DISABLED
2054+
2055+
#endif // DEBUG_ENABLED
18642056
}
18652057

18662058
#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)