Skip to content

Commit 86002e1

Browse files
committedJan 16, 2025
Merge pull request godotengine#100882 from smix8/node_navmesh_geo_parsers
Make nodes handle their respective navigation source geometry
2 parents fd88acc + 0ed2cb0 commit 86002e1

40 files changed

+1528
-1124
lines changed
 

‎main/main.cpp

+12-48
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,8 @@ static DisplayServer *display_server = nullptr;
164164
static RenderingServer *rendering_server = nullptr;
165165
static TextServerManager *tsman = nullptr;
166166
static ThemeDB *theme_db = nullptr;
167-
static NavigationServer2D *navigation_server_2d = nullptr;
168167
static PhysicsServer2DManager *physics_server_2d_manager = nullptr;
169168
static PhysicsServer2D *physics_server_2d = nullptr;
170-
static NavigationServer3D *navigation_server_3d = nullptr;
171169
#ifndef _3D_DISABLED
172170
static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
173171
static PhysicsServer3D *physics_server_3d = nullptr;
@@ -378,44 +376,6 @@ void finalize_display() {
378376
memdelete(display_server);
379377
}
380378

381-
void initialize_navigation_server() {
382-
ERR_FAIL_COND(navigation_server_3d != nullptr);
383-
ERR_FAIL_COND(navigation_server_2d != nullptr);
384-
385-
// Init 3D Navigation Server
386-
navigation_server_3d = NavigationServer3DManager::new_default_server();
387-
388-
// Fall back to dummy if no default server has been registered.
389-
if (!navigation_server_3d) {
390-
navigation_server_3d = memnew(NavigationServer3DDummy);
391-
}
392-
393-
// Should be impossible, but make sure it's not null.
394-
ERR_FAIL_NULL_MSG(navigation_server_3d, "Failed to initialize NavigationServer3D.");
395-
navigation_server_3d->init();
396-
397-
// Init 2D Navigation Server
398-
navigation_server_2d = NavigationServer2DManager::new_default_server();
399-
if (!navigation_server_2d) {
400-
navigation_server_2d = memnew(NavigationServer2DDummy);
401-
}
402-
403-
ERR_FAIL_NULL_MSG(navigation_server_2d, "Failed to initialize NavigationServer2D.");
404-
navigation_server_2d->init();
405-
}
406-
407-
void finalize_navigation_server() {
408-
ERR_FAIL_NULL(navigation_server_3d);
409-
navigation_server_3d->finish();
410-
memdelete(navigation_server_3d);
411-
navigation_server_3d = nullptr;
412-
413-
ERR_FAIL_NULL(navigation_server_2d);
414-
navigation_server_2d->finish();
415-
memdelete(navigation_server_2d);
416-
navigation_server_2d = nullptr;
417-
}
418-
419379
void initialize_theme_db() {
420380
theme_db = memnew(ThemeDB);
421381
}
@@ -772,6 +732,9 @@ Error Main::test_setup() {
772732
// Default theme will be initialized later, after modules and ScriptServer are ready.
773733
initialize_theme_db();
774734

735+
NavigationServer3DManager::initialize_server(); // 3D server first because 2D depends on it.
736+
NavigationServer2DManager::initialize_server();
737+
775738
register_scene_types();
776739
register_driver_types();
777740

@@ -794,8 +757,6 @@ Error Main::test_setup() {
794757
// Theme needs modules to be initialized so that sub-resources can be loaded.
795758
theme_db->initialize_theme_noproject();
796759

797-
initialize_navigation_server();
798-
799760
ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE);
800761

801762
/* Use one with the most features available. */
@@ -856,7 +817,8 @@ void Main::test_cleanup() {
856817

857818
finalize_theme_db();
858819

859-
finalize_navigation_server();
820+
NavigationServer2DManager::finalize_server(); // 2D goes first as it uses the 3D server behind the scene.
821+
NavigationServer3DManager::finalize_server();
860822

861823
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
862824
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
@@ -3402,6 +3364,11 @@ Error Main::setup2(bool p_show_boot_logo) {
34023364
// Default theme will be initialized later, after modules and ScriptServer are ready.
34033365
initialize_theme_db();
34043366

3367+
MAIN_PRINT("Main: Load Navigation");
3368+
3369+
NavigationServer3DManager::initialize_server(); // 3D server first because 2D depends on it.
3370+
NavigationServer2DManager::initialize_server();
3371+
34053372
register_scene_types();
34063373
register_driver_types();
34073374

@@ -3472,10 +3439,6 @@ Error Main::setup2(bool p_show_boot_logo) {
34723439

34733440
initialize_physics();
34743441

3475-
MAIN_PRINT("Main: Load Navigation");
3476-
3477-
initialize_navigation_server();
3478-
34793442
register_server_singletons();
34803443

34813444
// This loads global classes, so it must happen before custom loaders and savers are registered
@@ -4716,7 +4679,8 @@ void Main::cleanup(bool p_force) {
47164679
finalize_theme_db();
47174680

47184681
// Before deinitializing server extensions, finalize servers which may be loaded as extensions.
4719-
finalize_navigation_server();
4682+
NavigationServer2DManager::finalize_server(); // 2D goes first as it uses the 3D server behind the scene.
4683+
NavigationServer3DManager::finalize_server();
47204684
finalize_physics();
47214685

47224686
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);

‎modules/csg/csg_shape.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,45 @@
3434
#include "core/io/json.h"
3535
#endif // DEV_ENABLED
3636
#include "core/math/geometry_2d.h"
37+
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
38+
#include "scene/resources/navigation_mesh.h"
39+
#include "servers/navigation_server_3d.h"
3740

3841
#include <manifold/manifold.h>
3942

43+
Callable CSGShape3D::_navmesh_source_geometry_parsing_callback;
44+
RID CSGShape3D::_navmesh_source_geometry_parser;
45+
46+
void CSGShape3D::navmesh_parse_init() {
47+
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
48+
if (!_navmesh_source_geometry_parser.is_valid()) {
49+
_navmesh_source_geometry_parsing_callback = callable_mp_static(&CSGShape3D::navmesh_parse_source_geometry);
50+
_navmesh_source_geometry_parser = NavigationServer3D::get_singleton()->source_geometry_parser_create();
51+
NavigationServer3D::get_singleton()->source_geometry_parser_set_callback(_navmesh_source_geometry_parser, _navmesh_source_geometry_parsing_callback);
52+
}
53+
}
54+
55+
void CSGShape3D::navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node) {
56+
CSGShape3D *csgshape3d = Object::cast_to<CSGShape3D>(p_node);
57+
58+
if (csgshape3d == nullptr) {
59+
return;
60+
}
61+
62+
NavigationMesh::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
63+
uint32_t parsed_collision_mask = p_navigation_mesh->get_collision_mask();
64+
65+
if (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES || (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS && csgshape3d->is_using_collision() && (csgshape3d->get_collision_layer() & parsed_collision_mask)) || parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_BOTH) {
66+
Array meshes = csgshape3d->get_meshes();
67+
if (!meshes.is_empty()) {
68+
Ref<Mesh> mesh = meshes[1];
69+
if (mesh.is_valid()) {
70+
p_source_geometry_data->add_mesh(mesh, csgshape3d->get_global_transform());
71+
}
72+
}
73+
}
74+
}
75+
4076
void CSGShape3D::set_use_collision(bool p_enable) {
4177
if (use_collision == p_enable) {
4278
return;

‎modules/csg/csg_shape.h

+11
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939

4040
#include "thirdparty/misc/mikktspace.h"
4141

42+
class NavigationMesh;
43+
class NavigationMeshSourceGeometryData3D;
44+
4245
class CSGShape3D : public GeometryInstance3D {
4346
GDCLASS(CSGShape3D, GeometryInstance3D);
4447

@@ -171,6 +174,14 @@ class CSGShape3D : public GeometryInstance3D {
171174

172175
virtual Ref<TriangleMesh> generate_triangle_mesh() const override;
173176

177+
private:
178+
static Callable _navmesh_source_geometry_parsing_callback;
179+
static RID _navmesh_source_geometry_parser;
180+
181+
public:
182+
static void navmesh_parse_init();
183+
static void navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node);
184+
174185
CSGShape3D();
175186
~CSGShape3D();
176187
};

‎modules/csg/register_types.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void initialize_csg_module(ModuleInitializationLevel p_level) {
4747
GDREGISTER_CLASS(CSGTorus3D);
4848
GDREGISTER_CLASS(CSGPolygon3D);
4949
GDREGISTER_CLASS(CSGCombiner3D);
50+
CSGShape3D::navmesh_parse_init();
5051
}
5152
#ifdef TOOLS_ENABLED
5253
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {

‎modules/gridmap/grid_map.cpp

+151
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,26 @@
3131
#include "grid_map.h"
3232

3333
#include "core/io/marshalls.h"
34+
#include "core/math/convex_hull.h"
35+
#include "scene/resources/3d/box_shape_3d.h"
36+
#include "scene/resources/3d/capsule_shape_3d.h"
37+
#include "scene/resources/3d/concave_polygon_shape_3d.h"
38+
#include "scene/resources/3d/convex_polygon_shape_3d.h"
39+
#include "scene/resources/3d/cylinder_shape_3d.h"
40+
#include "scene/resources/3d/height_map_shape_3d.h"
3441
#include "scene/resources/3d/mesh_library.h"
42+
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
43+
#include "scene/resources/3d/primitive_meshes.h"
44+
#include "scene/resources/3d/shape_3d.h"
45+
#include "scene/resources/3d/sphere_shape_3d.h"
3546
#include "scene/resources/physics_material.h"
3647
#include "scene/resources/surface_tool.h"
3748
#include "servers/navigation_server_3d.h"
3849
#include "servers/rendering_server.h"
3950

51+
Callable GridMap::_navmesh_source_geometry_parsing_callback;
52+
RID GridMap::_navmesh_source_geometry_parser;
53+
4054
bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
4155
String name = p_name;
4256

@@ -1336,6 +1350,143 @@ GridMap::GridMap() {
13361350
#endif // DEBUG_ENABLED
13371351
}
13381352

1353+
void GridMap::navmesh_parse_init() {
1354+
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
1355+
if (!_navmesh_source_geometry_parser.is_valid()) {
1356+
_navmesh_source_geometry_parsing_callback = callable_mp_static(&GridMap::navmesh_parse_source_geometry);
1357+
_navmesh_source_geometry_parser = NavigationServer3D::get_singleton()->source_geometry_parser_create();
1358+
NavigationServer3D::get_singleton()->source_geometry_parser_set_callback(_navmesh_source_geometry_parser, _navmesh_source_geometry_parsing_callback);
1359+
}
1360+
}
1361+
1362+
void GridMap::navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node) {
1363+
GridMap *gridmap = Object::cast_to<GridMap>(p_node);
1364+
1365+
if (gridmap == nullptr) {
1366+
return;
1367+
}
1368+
1369+
NavigationMesh::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
1370+
uint32_t parsed_collision_mask = p_navigation_mesh->get_collision_mask();
1371+
1372+
if (parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES || parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_BOTH) {
1373+
Array meshes = gridmap->get_meshes();
1374+
Transform3D xform = gridmap->get_global_transform();
1375+
for (int i = 0; i < meshes.size(); i += 2) {
1376+
Ref<Mesh> mesh = meshes[i + 1];
1377+
if (mesh.is_valid()) {
1378+
p_source_geometry_data->add_mesh(mesh, xform * (Transform3D)meshes[i]);
1379+
}
1380+
}
1381+
}
1382+
1383+
else if ((parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationMesh::PARSED_GEOMETRY_BOTH) && (gridmap->get_collision_layer() & parsed_collision_mask)) {
1384+
Array shapes = gridmap->get_collision_shapes();
1385+
for (int i = 0; i < shapes.size(); i += 2) {
1386+
RID shape = shapes[i + 1];
1387+
PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape);
1388+
Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape);
1389+
1390+
switch (type) {
1391+
case PhysicsServer3D::SHAPE_SPHERE: {
1392+
real_t radius = data;
1393+
Array arr;
1394+
arr.resize(RS::ARRAY_MAX);
1395+
SphereMesh::create_mesh_array(arr, radius, radius * 2.0);
1396+
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
1397+
} break;
1398+
case PhysicsServer3D::SHAPE_BOX: {
1399+
Vector3 extents = data;
1400+
Array arr;
1401+
arr.resize(RS::ARRAY_MAX);
1402+
BoxMesh::create_mesh_array(arr, extents * 2.0);
1403+
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
1404+
} break;
1405+
case PhysicsServer3D::SHAPE_CAPSULE: {
1406+
Dictionary dict = data;
1407+
real_t radius = dict["radius"];
1408+
real_t height = dict["height"];
1409+
Array arr;
1410+
arr.resize(RS::ARRAY_MAX);
1411+
CapsuleMesh::create_mesh_array(arr, radius, height);
1412+
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
1413+
} break;
1414+
case PhysicsServer3D::SHAPE_CYLINDER: {
1415+
Dictionary dict = data;
1416+
real_t radius = dict["radius"];
1417+
real_t height = dict["height"];
1418+
Array arr;
1419+
arr.resize(RS::ARRAY_MAX);
1420+
CylinderMesh::create_mesh_array(arr, radius, radius, height);
1421+
p_source_geometry_data->add_mesh_array(arr, shapes[i]);
1422+
} break;
1423+
case PhysicsServer3D::SHAPE_CONVEX_POLYGON: {
1424+
PackedVector3Array vertices = data;
1425+
Geometry3D::MeshData md;
1426+
1427+
Error err = ConvexHullComputer::convex_hull(vertices, md);
1428+
1429+
if (err == OK) {
1430+
PackedVector3Array faces;
1431+
1432+
for (const Geometry3D::MeshData::Face &face : md.faces) {
1433+
for (uint32_t k = 2; k < face.indices.size(); ++k) {
1434+
faces.push_back(md.vertices[face.indices[0]]);
1435+
faces.push_back(md.vertices[face.indices[k - 1]]);
1436+
faces.push_back(md.vertices[face.indices[k]]);
1437+
}
1438+
}
1439+
1440+
p_source_geometry_data->add_faces(faces, shapes[i]);
1441+
}
1442+
} break;
1443+
case PhysicsServer3D::SHAPE_CONCAVE_POLYGON: {
1444+
Dictionary dict = data;
1445+
PackedVector3Array faces = Variant(dict["faces"]);
1446+
p_source_geometry_data->add_faces(faces, shapes[i]);
1447+
} break;
1448+
case PhysicsServer3D::SHAPE_HEIGHTMAP: {
1449+
Dictionary dict = data;
1450+
///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights"
1451+
int heightmap_depth = dict["depth"];
1452+
int heightmap_width = dict["width"];
1453+
1454+
if (heightmap_depth >= 2 && heightmap_width >= 2) {
1455+
const Vector<real_t> &map_data = dict["heights"];
1456+
1457+
Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1);
1458+
Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5;
1459+
1460+
Vector<Vector3> vertex_array;
1461+
vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6);
1462+
Vector3 *vertex_array_ptrw = vertex_array.ptrw();
1463+
const real_t *map_data_ptr = map_data.ptr();
1464+
int vertex_index = 0;
1465+
1466+
for (int d = 0; d < heightmap_depth - 1; d++) {
1467+
for (int w = 0; w < heightmap_width - 1; w++) {
1468+
vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d);
1469+
vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
1470+
vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
1471+
vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d);
1472+
vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1);
1473+
vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1);
1474+
vertex_index += 6;
1475+
}
1476+
}
1477+
if (vertex_array.size() > 0) {
1478+
p_source_geometry_data->add_faces(vertex_array, shapes[i]);
1479+
}
1480+
}
1481+
} break;
1482+
default: {
1483+
WARN_PRINT("Unsupported collision shape type.");
1484+
} break;
1485+
}
1486+
}
1487+
}
1488+
}
1489+
13391490
#ifdef DEBUG_ENABLED
13401491
void GridMap::_update_navigation_debug_edge_connections() {
13411492
if (bake_navigation) {

‎modules/gridmap/grid_map.h

+10
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
//heh heh, godotsphir!! this shares no code and the design is completely different with previous projects i've done..
3939
//should scale better with hardware that supports instancing
4040

41+
class NavigationMesh;
42+
class NavigationMeshSourceGeometryData3D;
4143
class PhysicsMaterial;
4244

4345
class GridMap : public Node3D {
@@ -300,6 +302,14 @@ class GridMap : public Node3D {
300302
Array get_bake_meshes();
301303
RID get_bake_mesh_instance(int p_idx);
302304

305+
private:
306+
static Callable _navmesh_source_geometry_parsing_callback;
307+
static RID _navmesh_source_geometry_parser;
308+
309+
public:
310+
static void navmesh_parse_init();
311+
static void navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node);
312+
303313
GridMap();
304314
~GridMap();
305315
};

‎modules/gridmap/register_types.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
void initialize_gridmap_module(ModuleInitializationLevel p_level) {
4444
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
4545
GDREGISTER_CLASS(GridMap);
46+
GridMap::navmesh_parse_init();
4647
}
4748
#ifdef TOOLS_ENABLED
4849
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {

0 commit comments

Comments
 (0)
Please sign in to comment.