diff options
Diffstat (limited to 'modules/navigation/navigation_mesh_generator.cpp')
-rw-r--r-- | modules/navigation/navigation_mesh_generator.cpp | 122 |
1 files changed, 116 insertions, 6 deletions
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index e430f5fd59..f0d3e329ce 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -42,6 +42,7 @@ #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" #include "scene/resources/cylinder_shape_3d.h" +#include "scene/resources/height_map_shape_3d.h" #include "scene/resources/primitive_meshes.h" #include "scene/resources/shape_3d.h" #include "scene/resources/sphere_shape_3d.h" @@ -208,6 +209,9 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans 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++) { + if (static_body->is_shape_owner_disabled(i)) { + continue; + } Ref<Shape3D> s = static_body->shape_owner_get_shape(shape_owner, i); if (s.is_null()) { continue; @@ -262,10 +266,10 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans if (err == OK) { PackedVector3Array faces; - for (int j = 0; j < md.faces.size(); ++j) { - Geometry3D::MeshData::Face face = md.faces[j]; + for (uint32_t j = 0; j < md.faces.size(); ++j) { + const Geometry3D::MeshData::Face &face = md.faces[j]; - for (int k = 2; k < face.indices.size(); ++k) { + for (uint32_t 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]]); @@ -275,6 +279,50 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans _add_faces(faces, transform, p_vertices, p_indices); } } + + HeightMapShape3D *heightmap_shape = Object::cast_to<HeightMapShape3D>(*s); + if (heightmap_shape) { + int heightmap_depth = heightmap_shape->get_map_depth(); + int heightmap_width = heightmap_shape->get_map_width(); + + if (heightmap_depth >= 2 && heightmap_width >= 2) { + const Vector<real_t> &map_data = heightmap_shape->get_map_data(); + + Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1); + Vector2 start = heightmap_gridsize * -0.5; + + Vector<Vector3> vertex_array; + vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6); + int map_data_current_index = 0; + + for (int d = 0; d < heightmap_depth - 1; d++) { + for (int w = 0; w < heightmap_width - 1; w++) { + if (map_data_current_index + 1 + heightmap_depth < map_data.size()) { + float top_left_height = map_data[map_data_current_index]; + float top_right_height = map_data[map_data_current_index + 1]; + float bottom_left_height = map_data[map_data_current_index + heightmap_depth]; + float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth]; + + Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d); + Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d); + Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0); + Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0); + + vertex_array.push_back(top_right); + vertex_array.push_back(bottom_left); + vertex_array.push_back(top_left); + vertex_array.push_back(top_right); + vertex_array.push_back(bottom_right); + vertex_array.push_back(bottom_left); + } + map_data_current_index += 1; + } + } + if (vertex_array.size() > 0) { + _add_faces(vertex_array, transform, p_vertices, p_indices); + } + } + } } } } @@ -344,10 +392,10 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans if (err == OK) { PackedVector3Array faces; - for (int j = 0; j < md.faces.size(); ++j) { - Geometry3D::MeshData::Face face = md.faces[j]; + for (uint32_t j = 0; j < md.faces.size(); ++j) { + const Geometry3D::MeshData::Face &face = md.faces[j]; - for (int k = 2; k < face.indices.size(); ++k) { + for (uint32_t 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]]); @@ -362,6 +410,50 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans PackedVector3Array faces = Variant(dict["faces"]); _add_faces(faces, shapes[i], p_vertices, p_indices); } break; + case PhysicsServer3D::SHAPE_HEIGHTMAP: { + Dictionary dict = data; + ///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights" + int heightmap_depth = dict["depth"]; + int heightmap_width = dict["width"]; + + if (heightmap_depth >= 2 && heightmap_width >= 2) { + const Vector<real_t> &map_data = dict["heights"]; + + Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1); + Vector2 start = heightmap_gridsize * -0.5; + + Vector<Vector3> vertex_array; + vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6); + int map_data_current_index = 0; + + for (int d = 0; d < heightmap_depth - 1; d++) { + for (int w = 0; w < heightmap_width - 1; w++) { + if (map_data_current_index + 1 + heightmap_depth < map_data.size()) { + float top_left_height = map_data[map_data_current_index]; + float top_right_height = map_data[map_data_current_index + 1]; + float bottom_left_height = map_data[map_data_current_index + heightmap_depth]; + float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth]; + + Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d); + Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d); + Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0); + Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0); + + vertex_array.push_back(top_right); + vertex_array.push_back(bottom_left); + vertex_array.push_back(top_left); + vertex_array.push_back(top_right); + vertex_array.push_back(bottom_right); + vertex_array.push_back(bottom_left); + } + map_data_current_index += 1; + } + } + if (vertex_array.size() > 0) { + _add_faces(vertex_array, shapes[i], p_vertices, p_indices); + } + } + } break; default: { WARN_PRINT("Unsupported collision shape type."); } break; @@ -482,6 +574,17 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( cfg.bmax[1] = bmax[1]; cfg.bmax[2] = bmax[2]; + AABB baking_aabb = p_nav_mesh->get_filter_baking_aabb(); + if (baking_aabb.has_volume()) { + Vector3 baking_aabb_offset = p_nav_mesh->get_filter_baking_aabb_offset(); + cfg.bmin[0] = baking_aabb.position[0] + baking_aabb_offset.x; + cfg.bmin[1] = baking_aabb.position[1] + baking_aabb_offset.y; + cfg.bmin[2] = baking_aabb.position[2] + baking_aabb_offset.z; + cfg.bmax[0] = cfg.bmin[0] + baking_aabb.size[0]; + cfg.bmax[1] = cfg.bmin[1] + baking_aabb.size[1]; + cfg.bmax[2] = cfg.bmin[2] + baking_aabb.size[2]; + } + #ifdef TOOLS_ENABLED if (ep) { ep->step(TTR("Calculating grid size..."), 2); @@ -631,6 +734,13 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) #ifdef TOOLS_ENABLED EditorProgress *ep(nullptr); + // FIXME +#endif +#if 0 + // After discussion on devchat disabled EditorProgress for now as it is not thread-safe and uses hacks and Main::iteration() for steps. + // EditorProgress randomly crashes the Engine when the bake function is used with a thread e.g. inside Editor with a tool script and procedural navigation + // This was not a problem in older versions as previously Godot was unable to (re)bake NavigationMesh at runtime. + // If EditorProgress is fixed and made thread-safe this should be enabled again. if (Engine::get_singleton()->is_editor_hint()) { ep = memnew(EditorProgress("bake", TTR("Navigation Mesh Generator Setup:"), 11)); } |