From f4a6737eed440d0d28aeecebdd0ffe2fa7ce9d5e Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Wed, 11 Aug 2021 16:22:44 +0800 Subject: [PATCH] Improve NavigationMesh typing, parameter validation and documentation --- doc/classes/NavigationMesh.xml | 83 +++++++++++++++++--- doc/classes/NavigationMeshInstance.xml | 4 + modules/recast/navigation_mesh_generator.cpp | 4 +- modules/recast/navigation_mesh_generator.h | 2 +- scene/3d/navigation_mesh.cpp | 60 +++++++++----- scene/3d/navigation_mesh.h | 16 ++-- 6 files changed, 131 insertions(+), 38 deletions(-) diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml index 9a077d3fb20..df2743a823c 100644 --- a/doc/classes/NavigationMesh.xml +++ b/doc/classes/NavigationMesh.xml @@ -1,8 +1,10 @@ + A mesh to approximate the walkable areas and obstacles. + A navigation mesh is a collection of polygons that define which areas of an environment are traversable to aid agents in pathfinding through complicated spaces. https://godotengine.org/asset-library/asset/124 @@ -12,39 +14,46 @@ + Adds a polygon using the indices of the vertices you get when calling [method get_vertices]. + Clears the array of polygons, but it doesn't clear the array of vertices. + Initializes the navigation mesh by setting the vertices and indices according to a [Mesh]. + Returns whether the specified [code]bit[/code] of the [member geometry/collision_mask] is set. + Returns a [PoolIntArray] containing the indices of the vertices of a created polygon. + Returns the number of polygons in the navigation mesh. + Returns a [PoolVector3Array] containing all the vertices being used to create the polygons. @@ -52,71 +61,127 @@ + If [code]value[/code] is [code]true[/code], sets the specified [code]bit[/code] in the [member geometry/collision_mask]. + If [code]value[/code] is [code]false[/code], clears the specified [code]bit[/code] in the [member geometry/collision_mask]. + Sets the vertices that can be then indexed to create polygons with the [method add_polygon] method. + The minimum floor to ceiling height that will still allow the floor area to be considered walkable. + [b]Note:[/b] While baking, this value will be rounded up to the nearest multiple of [member cell/height]. + The minimum ledge height that is considered to still be traversable. + [b]Note:[/b] While baking, this value will be rounded down to the nearest multiple of [member cell/height]. + The maximum slope that is considered walkable, in degrees. + The distance to erode/shrink the walkable area of the heightfield away from obstructions. + [b]Note:[/b] While baking, this value will be rounded up to the nearest multiple of [member cell/size]. + The Y axis cell size to use for fields. + The XZ plane cell size to use for fields. + The sampling distance to use when generating the detail mesh, in cell unit. + The maximum distance the detail mesh surface should deviate from heightfield, in cell unit. + The maximum distance a simplfied contour's border edges should deviate the original raw contour. + The maximum allowed length for contour edges along the border of the mesh. + [b]Note:[/b] While baking, this value will be rounded up to the nearest multiple of [member cell/size]. + If [code]true[/code], marks walkable spans as not walkable if the clearance above the span is less than [member agent/height]. + If [code]true[/code], marks spans that are ledges as non-walkable. + If [code]true[/code], marks non-walkable spans as walkable if their maximum is within [member agent/max_climb] of a walkable neighbor. + The physics layers to scan for static colliders. + Only used when [member geometry/parsed_geometry_type] is [constant PARSED_GEOMETRY_STATIC_COLLIDERS] or [constant PARSED_GEOMETRY_BOTH]. - + + Determines which type of nodes will be parsed as geometry. See [enum ParsedGeometryType] for possible values. - + + The source of the geometry used when baking. See [enum SourceGeometryMode] for possible values. + The name of the group to scan for geometry. + Only used when [member geometry/source_geometry_mode] is [constant SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN] or [constant SOURCE_GEOMETRY_GROUPS_EXPLICIT]. + The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process. + Any regions with a size smaller than this will be merged with larger regions if possible. + [b]Note:[/b] This value will be squared to calculate the number of cells. For example, a value of 20 will set the number of cells to 400. + The minimum size of a region for it to be created. + [b]Note:[/b] This value will be squared to calculate the minimum number of cells allowed to form isolated island areas. For example, a value of 8 will set the number of cells to 64. - + + Partitioning algorithm for creating the navigation mesh polys. See [enum SamplePartitionType] for possible values. - + + Watershed partitioning. Generally the best choice if you precompute the navigation mesh, use this if you have large open areas. - + + Monotone partitioning. Use this if you want fast navigation mesh generation. - + + Layer partitioning. Good choice to use for tiled navigation mesh with medium and small sized tiles. - + + Represents the size of the [enum SamplePartitionType] enum. - + + Parses mesh instances as geometry. This includes [MeshInstance], [CSGShape], and [GridMap] nodes. - + + Parses [StaticBody] colliders as geometry. The collider should be in any of the layers specified by [member geometry/collision_mask]. + + + Both [constant PARSED_GEOMETRY_MESH_INSTANCES] and [constant PARSED_GEOMETRY_STATIC_COLLIDERS]. + + + Represents the size of the [enum ParsedGeometryType] enum. + + + Scans the child nodes of [NavigationMeshInstance] recursively for geometry. + + + Scans nodes in a group and their child nodes recursively for geometry. The group is specified by [member geometry/source_group_name]. + + + Uses nodes in a group for geometry. The group is specified by [member geometry/source_group_name]. + + + Represents the size of the [enum SourceGeometryMode] enum. diff --git a/doc/classes/NavigationMeshInstance.xml b/doc/classes/NavigationMeshInstance.xml index 38d7ad32154..2a78d5cadaa 100644 --- a/doc/classes/NavigationMeshInstance.xml +++ b/doc/classes/NavigationMeshInstance.xml @@ -1,8 +1,10 @@ + Node that instances navigation meshes into a scenario. + NavigationMeshInstance is a node that takes a [NavigationMesh] resource and adds it to the current scenario by creating an instance of it. @@ -10,8 +12,10 @@ + If [code]true[/code], the navigation mesh will be used by [Navigation]. + The [NavigationMesh] resource for the instance. diff --git a/modules/recast/navigation_mesh_generator.cpp b/modules/recast/navigation_mesh_generator.cpp index 69417d6ae3c..118ee9d0c2e 100644 --- a/modules/recast/navigation_mesh_generator.cpp +++ b/modules/recast/navigation_mesh_generator.cpp @@ -132,7 +132,7 @@ void EditorNavigationMeshGenerator::_add_faces(const PoolVector3Array &p_faces, } } -void EditorNavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector &p_verticies, Vector &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) { +void EditorNavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector &p_verticies, Vector &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) { if (Object::cast_to(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { MeshInstance *mesh_instance = Object::cast_to(p_node); Ref mesh = mesh_instance->get_mesh(); @@ -454,7 +454,7 @@ void EditorNavigationMeshGenerator::bake(Ref p_nav_mesh, Node *p Transform navmesh_xform = Object::cast_to(p_node)->get_transform().affine_inverse(); for (const List::Element *E = parse_nodes.front(); E; E = E->next()) { - int geometry_type = p_nav_mesh->get_parsed_geometry_type(); + NavigationMesh::ParsedGeometryType geometry_type = p_nav_mesh->get_parsed_geometry_type(); uint32_t collision_mask = p_nav_mesh->get_collision_mask(); bool recurse_children = p_nav_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT; _parse_geometry(navmesh_xform, E->get(), vertices, indices, geometry_type, collision_mask, recurse_children); diff --git a/modules/recast/navigation_mesh_generator.h b/modules/recast/navigation_mesh_generator.h index 022519b0224..afddb9fd89e 100644 --- a/modules/recast/navigation_mesh_generator.h +++ b/modules/recast/navigation_mesh_generator.h @@ -47,7 +47,7 @@ protected: static void _add_vertex(const Vector3 &p_vec3, Vector &p_verticies); static void _add_mesh(const Ref &p_mesh, const Transform &p_xform, Vector &p_verticies, Vector &p_indices); static void _add_faces(const PoolVector3Array &p_faces, const Transform &p_xform, Vector &p_verticies, Vector &p_indices); - static void _parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector &p_verticies, Vector &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); + static void _parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector &p_verticies, Vector &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref p_nav_mesh); static void _build_recast_navigation_mesh(Ref p_nav_mesh, EditorProgress *ep, diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 1ac5b4fc2bf..fca94afcea3 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -66,22 +66,22 @@ void NavigationMesh::create_from_mesh(const Ref &p_mesh) { } } -void NavigationMesh::set_sample_partition_type(int p_value) { - ERR_FAIL_COND(p_value >= SAMPLE_PARTITION_MAX); - partition_type = static_cast(p_value); +void NavigationMesh::set_sample_partition_type(SamplePartitionType p_value) { + ERR_FAIL_INDEX(p_value, SAMPLE_PARTITION_MAX); + partition_type = p_value; } -int NavigationMesh::get_sample_partition_type() const { - return static_cast(partition_type); +NavigationMesh::SamplePartitionType NavigationMesh::get_sample_partition_type() const { + return partition_type; } -void NavigationMesh::set_parsed_geometry_type(int p_value) { - ERR_FAIL_COND(p_value >= PARSED_GEOMETRY_MAX); - parsed_geometry_type = static_cast(p_value); +void NavigationMesh::set_parsed_geometry_type(ParsedGeometryType p_value) { + ERR_FAIL_INDEX(p_value, PARSED_GEOMETRY_MAX); + parsed_geometry_type = p_value; _change_notify(); } -int NavigationMesh::get_parsed_geometry_type() const { +NavigationMesh::ParsedGeometryType NavigationMesh::get_parsed_geometry_type() const { return parsed_geometry_type; } @@ -109,13 +109,13 @@ bool NavigationMesh::get_collision_mask_bit(int p_bit) const { return get_collision_mask() & (1 << p_bit); } -void NavigationMesh::set_source_geometry_mode(int p_geometry_mode) { +void NavigationMesh::set_source_geometry_mode(SourceGeometryMode p_geometry_mode) { ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX); - source_geometry_mode = static_cast(p_geometry_mode); + source_geometry_mode = p_geometry_mode; _change_notify(); } -int NavigationMesh::get_source_geometry_mode() const { +NavigationMesh::SourceGeometryMode NavigationMesh::get_source_geometry_mode() const { return source_geometry_mode; } @@ -128,6 +128,7 @@ StringName NavigationMesh::get_source_group_name() const { } void NavigationMesh::set_cell_size(float p_value) { + ERR_FAIL_COND(p_value <= 0); cell_size = p_value; } @@ -136,6 +137,7 @@ float NavigationMesh::get_cell_size() const { } void NavigationMesh::set_cell_height(float p_value) { + ERR_FAIL_COND(p_value <= 0); cell_height = p_value; } @@ -144,6 +146,7 @@ float NavigationMesh::get_cell_height() const { } void NavigationMesh::set_agent_height(float p_value) { + ERR_FAIL_COND(p_value < 0); agent_height = p_value; } @@ -152,6 +155,7 @@ float NavigationMesh::get_agent_height() const { } void NavigationMesh::set_agent_radius(float p_value) { + ERR_FAIL_COND(p_value < 0); agent_radius = p_value; } @@ -160,6 +164,7 @@ float NavigationMesh::get_agent_radius() { } void NavigationMesh::set_agent_max_climb(float p_value) { + ERR_FAIL_COND(p_value < 0); agent_max_climb = p_value; } @@ -168,6 +173,7 @@ float NavigationMesh::get_agent_max_climb() const { } void NavigationMesh::set_agent_max_slope(float p_value) { + ERR_FAIL_COND(p_value < 0 || p_value > 90); agent_max_slope = p_value; } @@ -176,6 +182,7 @@ float NavigationMesh::get_agent_max_slope() const { } void NavigationMesh::set_region_min_size(float p_value) { + ERR_FAIL_COND(p_value < 0); region_min_size = p_value; } @@ -184,6 +191,7 @@ float NavigationMesh::get_region_min_size() const { } void NavigationMesh::set_region_merge_size(float p_value) { + ERR_FAIL_COND(p_value < 0); region_merge_size = p_value; } @@ -192,6 +200,7 @@ float NavigationMesh::get_region_merge_size() const { } void NavigationMesh::set_edge_max_length(float p_value) { + ERR_FAIL_COND(p_value < 0); edge_max_length = p_value; } @@ -200,6 +209,7 @@ float NavigationMesh::get_edge_max_length() const { } void NavigationMesh::set_edge_max_error(float p_value) { + ERR_FAIL_COND(p_value < 0); edge_max_error = p_value; } @@ -208,6 +218,7 @@ float NavigationMesh::get_edge_max_error() const { } void NavigationMesh::set_verts_per_poly(float p_value) { + ERR_FAIL_COND(p_value < 3); verts_per_poly = p_value; } @@ -216,6 +227,7 @@ float NavigationMesh::get_verts_per_poly() const { } void NavigationMesh::set_detail_sample_distance(float p_value) { + ERR_FAIL_COND(p_value < 0); detail_sample_distance = p_value; } @@ -224,6 +236,7 @@ float NavigationMesh::get_detail_sample_distance() const { } void NavigationMesh::set_detail_sample_max_error(float p_value) { + ERR_FAIL_COND(p_value < 0); detail_sample_max_error = p_value; } @@ -461,14 +474,6 @@ void NavigationMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationMesh::_set_polygons); ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationMesh::_get_polygons); - BIND_CONSTANT(SAMPLE_PARTITION_WATERSHED); - BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE); - BIND_CONSTANT(SAMPLE_PARTITION_LAYERS); - - BIND_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES); - BIND_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS); - BIND_CONSTANT(PARSED_GEOMETRY_BOTH); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); @@ -495,6 +500,21 @@ void NavigationMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans"); + + BIND_ENUM_CONSTANT(SAMPLE_PARTITION_WATERSHED); + BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MONOTONE); + BIND_ENUM_CONSTANT(SAMPLE_PARTITION_LAYERS); + BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MAX); + + BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES); + BIND_ENUM_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS); + BIND_ENUM_CONSTANT(PARSED_GEOMETRY_BOTH); + BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MAX); + + BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_NAVMESH_CHILDREN); + BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN); + BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_EXPLICIT); + BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX); } void NavigationMesh::_validate_property(PropertyInfo &property) const { diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h index 85d6a2370ba..8bac3578618 100644 --- a/scene/3d/navigation_mesh.h +++ b/scene/3d/navigation_mesh.h @@ -110,11 +110,11 @@ protected: public: // Recast settings - void set_sample_partition_type(int p_value); - int get_sample_partition_type() const; + void set_sample_partition_type(SamplePartitionType p_value); + SamplePartitionType get_sample_partition_type() const; - void set_parsed_geometry_type(int p_value); - int get_parsed_geometry_type() const; + void set_parsed_geometry_type(ParsedGeometryType p_value); + ParsedGeometryType get_parsed_geometry_type() const; void set_collision_mask(uint32_t p_mask); uint32_t get_collision_mask() const; @@ -122,8 +122,8 @@ public: void set_collision_mask_bit(int p_bit, bool p_value); bool get_collision_mask_bit(int p_bit) const; - void set_source_geometry_mode(int p_geometry_mode); - int get_source_geometry_mode() const; + void set_source_geometry_mode(SourceGeometryMode p_geometry_mode); + SourceGeometryMode get_source_geometry_mode() const; void set_source_group_name(StringName p_group_name); StringName get_source_group_name() const; @@ -191,6 +191,10 @@ public: NavigationMesh(); }; +VARIANT_ENUM_CAST(NavigationMesh::SamplePartitionType); +VARIANT_ENUM_CAST(NavigationMesh::ParsedGeometryType); +VARIANT_ENUM_CAST(NavigationMesh::SourceGeometryMode); + class Navigation; class NavigationMeshInstance : public Spatial {