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:
parent
a1033aea51
commit
298bd3f88a
5 changed files with 76 additions and 5 deletions
|
@ -107,6 +107,10 @@
|
||||||
</member>
|
</member>
|
||||||
<member name="geometry/parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type" default="0">
|
<member name="geometry/parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type" default="0">
|
||||||
</member>
|
</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 name="polygon/verts_per_poly" type="float" setter="set_verts_per_poly" getter="get_verts_per_poly" default="6.0">
|
||||||
</member>
|
</member>
|
||||||
<member name="region/merge_size" type="float" setter="set_region_merge_size" getter="get_region_merge_size" default="20.0">
|
<member name="region/merge_size" type="float" setter="set_region_merge_size" getter="get_region_merge_size" default="20.0">
|
||||||
|
|
|
@ -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) {
|
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();
|
p_accumulated_transform = p_accumulated_transform * spatial->get_transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
if (p_recurse_children) {
|
||||||
_parse_geometry(p_accumulated_transform, p_node->get_child(i), p_verticies, p_indices, p_generate_from, p_collision_mask);
|
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<float> vertices;
|
||||||
Vector<int> indices;
|
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) {
|
if (vertices.size() > 0 && indices.size() > 0) {
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ protected:
|
||||||
static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies);
|
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_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 _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 _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,
|
static void _build_recast_navigation_mesh(Ref<NavigationMesh> p_nav_mesh, EditorProgress *ep,
|
||||||
|
|
|
@ -108,6 +108,24 @@ bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
|
||||||
return get_collision_mask() & (1 << p_bit);
|
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) {
|
void NavigationMesh::set_cell_size(float p_value) {
|
||||||
cell_size = 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("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("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("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size);
|
||||||
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_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, "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/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/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/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");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (property.name == "geometry/source_group_name") {
|
||||||
|
if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
|
||||||
|
property.usage = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationMesh::NavigationMesh() {
|
NavigationMesh::NavigationMesh() {
|
||||||
|
@ -509,6 +542,8 @@ NavigationMesh::NavigationMesh() {
|
||||||
partition_type = SAMPLE_PARTITION_WATERSHED;
|
partition_type = SAMPLE_PARTITION_WATERSHED;
|
||||||
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
|
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
|
||||||
collision_mask = 0xFFFFFFFF;
|
collision_mask = 0xFFFFFFFF;
|
||||||
|
source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
|
||||||
|
source_group_name = "navmesh";
|
||||||
filter_low_hanging_obstacles = false;
|
filter_low_hanging_obstacles = false;
|
||||||
filter_ledge_spans = false;
|
filter_ledge_spans = false;
|
||||||
filter_walkable_low_height_spans = false;
|
filter_walkable_low_height_spans = false;
|
||||||
|
|
|
@ -77,6 +77,13 @@ public:
|
||||||
PARSED_GEOMETRY_MAX
|
PARSED_GEOMETRY_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SourceGeometryMode {
|
||||||
|
SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0,
|
||||||
|
SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN,
|
||||||
|
SOURCE_GEOMETRY_GROUPS_EXPLICIT,
|
||||||
|
SOURCE_GEOMETRY_MAX
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float cell_size;
|
float cell_size;
|
||||||
float cell_height;
|
float cell_height;
|
||||||
|
@ -96,6 +103,9 @@ protected:
|
||||||
ParsedGeometryType parsed_geometry_type;
|
ParsedGeometryType parsed_geometry_type;
|
||||||
uint32_t collision_mask;
|
uint32_t collision_mask;
|
||||||
|
|
||||||
|
SourceGeometryMode source_geometry_mode;
|
||||||
|
StringName source_group_name;
|
||||||
|
|
||||||
bool filter_low_hanging_obstacles;
|
bool filter_low_hanging_obstacles;
|
||||||
bool filter_ledge_spans;
|
bool filter_ledge_spans;
|
||||||
bool filter_walkable_low_height_spans;
|
bool filter_walkable_low_height_spans;
|
||||||
|
@ -114,6 +124,12 @@ public:
|
||||||
void set_collision_mask_bit(int p_bit, bool p_value);
|
void set_collision_mask_bit(int p_bit, bool p_value);
|
||||||
bool get_collision_mask_bit(int p_bit) const;
|
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);
|
void set_cell_size(float p_value);
|
||||||
float get_cell_size() const;
|
float get_cell_size() const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue