Add option to create navmesh from objects in group

Adds a new NavigationMesh property to select which objects will be taken
into account for the generation.

By default it will use all the NavigationMeshInstance children to keep
compatibility. The new modes allow to build the NavigationMesh from
all the nodes belonging to a specific group, and optionally include
their children too.
This commit is contained in:
jfons 2019-10-16 11:33:47 +02:00
parent a1033aea51
commit 298bd3f88a
5 changed files with 76 additions and 5 deletions

View file

@ -107,6 +107,10 @@
</member>
<member name="geometry/parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type" default="0">
</member>
<member name="geometry/source_geometry_mode" type="int" setter="set_source_geometry_mode" getter="get_source_geometry_mode" default="0">
</member>
<member name="geometry/source_group_name" type="String" setter="set_source_group_name" getter="get_source_group_name">
</member>
<member name="polygon/verts_per_poly" type="float" setter="set_verts_per_poly" getter="get_verts_per_poly" default="6.0">
</member>
<member name="region/merge_size" type="float" setter="set_region_merge_size" getter="get_region_merge_size" default="20.0">

View file

@ -131,7 +131,7 @@ void EditorNavigationMeshGenerator::_add_faces(const PoolVector3Array &p_faces,
}
}
void EditorNavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask) {
void EditorNavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
if (Object::cast_to<MeshInstance>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
@ -263,8 +263,10 @@ void EditorNavigationMeshGenerator::_parse_geometry(Transform p_accumulated_tran
p_accumulated_transform = p_accumulated_transform * spatial->get_transform();
}
for (int i = 0; i < p_node->get_child_count(); i++) {
_parse_geometry(p_accumulated_transform, p_node->get_child(i), p_verticies, p_indices, p_generate_from, p_collision_mask);
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_verticies, p_indices, p_generate_from, p_collision_mask, p_recurse_children);
}
}
}
@ -439,7 +441,21 @@ void EditorNavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p
Vector<float> vertices;
Vector<int> indices;
_parse_geometry(Object::cast_to<Spatial>(p_node)->get_transform().affine_inverse(), p_node, vertices, indices, p_nav_mesh->get_parsed_geometry_type(), p_nav_mesh->get_collision_mask());
List<Node *> parse_nodes;
if (p_nav_mesh->get_source_geometry_mode() == NavigationMesh::SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
parse_nodes.push_back(p_node);
} else {
p_node->get_tree()->get_nodes_in_group(p_nav_mesh->get_source_group_name(), &parse_nodes);
}
Transform navmesh_xform = Object::cast_to<Spatial>(p_node)->get_transform().affine_inverse();
for (const List<Node *>::Element *E = parse_nodes.front(); E; E = E->next()) {
int 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);
}
if (vertices.size() > 0 && indices.size() > 0) {

View file

@ -47,7 +47,7 @@ protected:
static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies);
static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
static void _add_faces(const PoolVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
static void _parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask);
static void _parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int 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<NavigationMesh> p_nav_mesh);
static void _build_recast_navigation_mesh(Ref<NavigationMesh> p_nav_mesh, EditorProgress *ep,

View file

@ -108,6 +108,24 @@ 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) {
ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX);
source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode);
_change_notify();
}
int NavigationMesh::get_source_geometry_mode() const {
return source_geometry_mode;
}
void NavigationMesh::set_source_group_name(StringName p_group_name) {
source_group_name = p_group_name;
}
StringName NavigationMesh::get_source_group_name() const {
return source_group_name;
}
void NavigationMesh::set_cell_size(float p_value) {
cell_size = p_value;
}
@ -387,6 +405,12 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_source_geometry_mode", "mask"), &NavigationMesh::set_source_geometry_mode);
ClassDB::bind_method(D_METHOD("get_source_geometry_mode"), &NavigationMesh::get_source_geometry_mode);
ClassDB::bind_method(D_METHOD("set_source_group_name", "mask"), &NavigationMesh::set_source_group_name);
ClassDB::bind_method(D_METHOD("get_source_group_name"), &NavigationMesh::get_source_group_name);
ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size);
@ -462,6 +486,8 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/source_geometry_mode", PROPERTY_HINT_ENUM, "Navmesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry/source_group_name"), "set_source_group_name", "get_source_group_name");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
@ -489,6 +515,13 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const {
return;
}
}
if (property.name == "geometry/source_group_name") {
if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
property.usage = 0;
return;
}
}
}
NavigationMesh::NavigationMesh() {
@ -509,6 +542,8 @@ NavigationMesh::NavigationMesh() {
partition_type = SAMPLE_PARTITION_WATERSHED;
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
collision_mask = 0xFFFFFFFF;
source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
source_group_name = "navmesh";
filter_low_hanging_obstacles = false;
filter_ledge_spans = false;
filter_walkable_low_height_spans = false;

View file

@ -77,6 +77,13 @@ public:
PARSED_GEOMETRY_MAX
};
enum SourceGeometryMode {
SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0,
SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN,
SOURCE_GEOMETRY_GROUPS_EXPLICIT,
SOURCE_GEOMETRY_MAX
};
protected:
float cell_size;
float cell_height;
@ -96,6 +103,9 @@ protected:
ParsedGeometryType parsed_geometry_type;
uint32_t collision_mask;
SourceGeometryMode source_geometry_mode;
StringName source_group_name;
bool filter_low_hanging_obstacles;
bool filter_ledge_spans;
bool filter_walkable_low_height_spans;
@ -114,6 +124,12 @@ 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_source_mode);
int get_source_geometry_mode() const;
void set_source_group_name(StringName p_group_name);
StringName get_source_group_name() const;
void set_cell_size(float p_value);
float get_cell_size() const;