summaryrefslogtreecommitdiff
path: root/modules/navigation/navigation_mesh_generator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/navigation/navigation_mesh_generator.cpp')
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp222
1 files changed, 159 insertions, 63 deletions
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 0bce0fc9f0..1bc7cd7cdc 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,6 @@
#include "core/math/convex_hull.h"
#include "core/os/thread.h"
-#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/physics_body_3d.h"
@@ -50,7 +49,6 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
#endif
#include "modules/modules_enabled.gen.h" // For csg, gridmap.
@@ -125,6 +123,28 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform
}
}
+void NavigationMeshGenerator::_add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) {
+ Vector<Vector3> mesh_vertices = p_array[Mesh::ARRAY_VERTEX];
+ const Vector3 *vr = mesh_vertices.ptr();
+
+ Vector<int> mesh_indices = p_array[Mesh::ARRAY_INDEX];
+ const int *ir = mesh_indices.ptr();
+
+ const int face_count = mesh_indices.size() / 3;
+ const int current_vertex_count = p_vertices.size() / 3;
+
+ for (int j = 0; j < mesh_vertices.size(); j++) {
+ _add_vertex(p_xform.xform(vr[j]), p_vertices);
+ }
+
+ for (int j = 0; j < face_count; j++) {
+ // CCW
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
+ }
+}
+
void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) {
int face_count = p_faces.size() / 3;
int current_vertex_count = p_vertices.size() / 3;
@@ -140,26 +160,28 @@ void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, cons
}
}
-void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
+void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
if (Object::cast_to<MeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mesh_instance->get_mesh();
if (mesh.is_valid()) {
- _add_mesh(mesh, p_accumulated_transform * mesh_instance->get_transform(), p_vertices, p_indices);
+ _add_mesh(mesh, p_navmesh_transform * mesh_instance->get_global_transform(), p_vertices, p_indices);
}
}
if (Object::cast_to<MultiMeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
MultiMeshInstance3D *multimesh_instance = Object::cast_to<MultiMeshInstance3D>(p_node);
Ref<MultiMesh> multimesh = multimesh_instance->get_multimesh();
- Ref<Mesh> mesh = multimesh->get_mesh();
- if (mesh.is_valid()) {
- int n = multimesh->get_visible_instance_count();
- if (n == -1) {
- n = multimesh->get_instance_count();
- }
- for (int i = 0; i < n; i++) {
- _add_mesh(mesh, p_accumulated_transform * multimesh->get_instance_transform(i), p_vertices, p_indices);
+ if (multimesh.is_valid()) {
+ Ref<Mesh> mesh = multimesh->get_mesh();
+ if (mesh.is_valid()) {
+ int n = multimesh->get_visible_instance_count();
+ if (n == -1) {
+ n = multimesh->get_instance_count();
+ }
+ for (int i = 0; i < n; i++) {
+ _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices);
+ }
}
}
}
@@ -171,7 +193,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor
if (!meshes.is_empty()) {
Ref<Mesh> mesh = meshes[1];
if (mesh.is_valid()) {
- _add_mesh(mesh, p_accumulated_transform * csg_shape->get_transform(), p_vertices, p_indices);
+ _add_mesh(mesh, p_navmesh_transform * csg_shape->get_global_transform(), p_vertices, p_indices);
}
}
}
@@ -181,50 +203,48 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor
StaticBody3D *static_body = Object::cast_to<StaticBody3D>(p_node);
if (static_body->get_collision_layer() & p_collision_mask) {
- for (int i = 0; i < p_node->get_child_count(); ++i) {
- Node *child = p_node->get_child(i);
- if (Object::cast_to<CollisionShape3D>(child)) {
- CollisionShape3D *col_shape = Object::cast_to<CollisionShape3D>(child);
-
- Transform3D transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform();
+ List<uint32_t> shape_owners;
+ static_body->get_shape_owners(&shape_owners);
+ for (uint32_t shape_owner : shape_owners) {
+ const int shape_count = static_body->shape_owner_get_shape_count(shape_owner);
+ for (int i = 0; i < shape_count; i++) {
+ Ref<Shape3D> s = static_body->shape_owner_get_shape(shape_owner, i);
+ if (s.is_null()) {
+ continue;
+ }
- Ref<Mesh> mesh;
- Ref<Shape3D> s = col_shape->get_shape();
+ const Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * static_body->shape_owner_get_transform(shape_owner);
BoxShape3D *box = Object::cast_to<BoxShape3D>(*s);
if (box) {
- Ref<BoxMesh> box_mesh;
- box_mesh.instantiate();
- box_mesh->set_size(box->get_size());
- mesh = box_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, box->get_size());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s);
if (capsule) {
- Ref<CapsuleMesh> capsule_mesh;
- capsule_mesh.instantiate();
- capsule_mesh->set_radius(capsule->get_radius());
- capsule_mesh->set_height(capsule->get_height());
- mesh = capsule_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(arr, capsule->get_radius(), capsule->get_height());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s);
if (cylinder) {
- Ref<CylinderMesh> cylinder_mesh;
- cylinder_mesh.instantiate();
- cylinder_mesh->set_height(cylinder->get_height());
- cylinder_mesh->set_bottom_radius(cylinder->get_radius());
- cylinder_mesh->set_top_radius(cylinder->get_radius());
- mesh = cylinder_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(arr, cylinder->get_radius(), cylinder->get_radius(), cylinder->get_height());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s);
if (sphere) {
- Ref<SphereMesh> sphere_mesh;
- sphere_mesh.instantiate();
- sphere_mesh->set_radius(sphere->get_radius());
- sphere_mesh->set_height(sphere->get_radius() * 2.0);
- mesh = sphere_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(arr, sphere->get_radius(), sphere->get_radius() * 2.0);
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
ConcavePolygonShape3D *concave_polygon = Object::cast_to<ConcavePolygonShape3D>(*s);
@@ -255,37 +275,105 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor
_add_faces(faces, transform, p_vertices, p_indices);
}
}
-
- if (mesh.is_valid()) {
- _add_mesh(mesh, transform, p_vertices, p_indices);
- }
}
}
}
}
#ifdef MODULE_GRIDMAP_ENABLED
- if (Object::cast_to<GridMap>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
- GridMap *gridmap_instance = Object::cast_to<GridMap>(p_node);
- Array meshes = gridmap_instance->get_meshes();
- Transform3D xform = gridmap_instance->get_transform();
- for (int i = 0; i < meshes.size(); i += 2) {
- Ref<Mesh> mesh = meshes[i + 1];
- if (mesh.is_valid()) {
- _add_mesh(mesh, p_accumulated_transform * xform * (Transform3D)meshes[i], p_vertices, p_indices);
+ GridMap *gridmap = Object::cast_to<GridMap>(p_node);
+
+ if (gridmap) {
+ if (p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
+ Array meshes = gridmap->get_meshes();
+ Transform3D xform = gridmap->get_global_transform();
+ for (int i = 0; i < meshes.size(); i += 2) {
+ Ref<Mesh> mesh = meshes[i + 1];
+ if (mesh.is_valid()) {
+ _add_mesh(mesh, p_navmesh_transform * xform * (Transform3D)meshes[i], p_vertices, p_indices);
+ }
}
}
- }
-#endif
- if (Object::cast_to<Node3D>(p_node)) {
- Node3D *spatial = Object::cast_to<Node3D>(p_node);
- p_accumulated_transform = p_accumulated_transform * spatial->get_transform();
+ if (p_generate_from != NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES && (gridmap->get_collision_layer() & p_collision_mask)) {
+ Array shapes = gridmap->get_collision_shapes();
+ for (int i = 0; i < shapes.size(); i += 2) {
+ RID shape = shapes[i + 1];
+ PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape);
+ Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape);
+
+ switch (type) {
+ case PhysicsServer3D::SHAPE_SPHERE: {
+ real_t radius = data;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(arr, radius, radius * 2.0);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
+ } break;
+ case PhysicsServer3D::SHAPE_BOX: {
+ Vector3 extents = data;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, extents * 2.0);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
+ } break;
+ case PhysicsServer3D::SHAPE_CAPSULE: {
+ Dictionary dict = data;
+ real_t radius = dict["radius"];
+ real_t height = dict["height"];
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(arr, radius, height);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
+ } break;
+ case PhysicsServer3D::SHAPE_CYLINDER: {
+ Dictionary dict = data;
+ real_t radius = dict["radius"];
+ real_t height = dict["height"];
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(arr, radius, radius, height);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
+ } break;
+ case PhysicsServer3D::SHAPE_CONVEX_POLYGON: {
+ PackedVector3Array vertices = data;
+ Geometry3D::MeshData md;
+
+ Error err = ConvexHullComputer::convex_hull(vertices, md);
+
+ if (err == OK) {
+ PackedVector3Array faces;
+
+ for (int j = 0; j < md.faces.size(); ++j) {
+ Geometry3D::MeshData::Face face = md.faces[j];
+
+ for (int k = 2; k < face.indices.size(); ++k) {
+ faces.push_back(md.vertices[face.indices[0]]);
+ faces.push_back(md.vertices[face.indices[k - 1]]);
+ faces.push_back(md.vertices[face.indices[k]]);
+ }
+ }
+
+ _add_faces(faces, shapes[i], p_vertices, p_indices);
+ }
+ } break;
+ case PhysicsServer3D::SHAPE_CONCAVE_POLYGON: {
+ Dictionary dict = data;
+ PackedVector3Array faces = Variant(dict["faces"]);
+ _add_faces(faces, shapes[i], p_vertices, p_indices);
+ } break;
+ default: {
+ WARN_PRINT("Unsupported collision shape type.");
+ } break;
+ }
+ }
+ }
}
+#endif
if (p_recurse_children) {
for (int i = 0; i < p_node->get_child_count(); i++) {
- _parse_geometry(p_accumulated_transform, p_node->get_child(i), p_vertices, p_indices, p_generate_from, p_collision_mask, p_recurse_children);
+ _parse_geometry(p_navmesh_transform, p_node->get_child(i), p_vertices, p_indices, p_generate_from, p_collision_mask, p_recurse_children);
}
}
}
@@ -359,7 +447,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.minRegionArea = (int)(p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size());
cfg.mergeRegionArea = (int)(p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size());
cfg.maxVertsPerPoly = (int)p_nav_mesh->get_verts_per_poly();
- cfg.detailSampleDist = p_nav_mesh->get_detail_sample_distance() < 0.9f ? 0 : p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance();
+ cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f);
cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error();
cfg.bmin[0] = bmin[0];
@@ -376,6 +464,14 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
#endif
rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
+ // ~30000000 seems to be around sweetspot where Editor baking breaks
+ if ((cfg.width * cfg.height) > 30000000) {
+ WARN_PRINT("NavigationMesh baking process will likely fail."
+ "\nSource geometry is suspiciously big for the current Cell Size and Cell Height in the NavMesh Resource bake settings."
+ "\nIf baking does not fail, the resulting NavigationMesh will create serious pathfinding performance issues."
+ "\nIt is advised to increase Cell Size and/or Cell Height in the NavMesh Resource bake settings or reduce the size / scale of the source geometry.");
+ }
+
#ifdef TOOLS_ENABLED
if (ep) {
ep->step(TTR("Creating heightfield..."), 3);
@@ -530,7 +626,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
p_node->get_tree()->get_nodes_in_group(p_nav_mesh->get_source_group_name(), &parse_nodes);
}
- Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse();
+ Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_global_transform().affine_inverse();
for (Node *E : parse_nodes) {
NavigationMesh::ParsedGeometryType geometry_type = p_nav_mesh->get_parsed_geometry_type();
uint32_t collision_mask = p_nav_mesh->get_collision_mask();