Various improvements to NavigationMesh generation
* Expose EditorNavigationMeshGenerator as an engine singleton so users can generate navmesehes from `tool` scripts. * Add support for generating navmeshes from static colliders. All collision shapes are supported except for Plane (since Plane is an infinite collider and navmeshes need to have finite geometry). * When using static colliders as a geometry source, a layer mask can be specified to ignore certain colliders. * Don't rely on global transform. It still should give the exact same results but allows for building navmeshes on nodes that are not in the tree (useful in `tool` scripts). * Update navigation gizmos after every new bake. This work has been kindly sponsored by IMVU.
This commit is contained in:
parent
e2375f487c
commit
1add4c15ab
6 changed files with 296 additions and 26 deletions
|
@ -54,26 +54,28 @@ void NavigationMeshEditor::_notification(int p_option) {
|
|||
}
|
||||
|
||||
void NavigationMeshEditor::_bake_pressed() {
|
||||
button_bake->set_pressed(false);
|
||||
|
||||
ERR_FAIL_COND(!node);
|
||||
const String conf_warning = node->get_configuration_warning();
|
||||
if (!conf_warning.empty()) {
|
||||
err_dialog->set_text(conf_warning);
|
||||
err_dialog->popup_centered_minsize();
|
||||
button_bake->set_pressed(false);
|
||||
return;
|
||||
}
|
||||
|
||||
NavigationMeshGenerator::clear(node->get_navigation_mesh());
|
||||
NavigationMeshGenerator::bake(node->get_navigation_mesh(), node);
|
||||
EditorNavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh());
|
||||
EditorNavigationMeshGenerator::get_singleton()->bake(node->get_navigation_mesh(), node);
|
||||
|
||||
node->update_gizmo();
|
||||
if (node) {
|
||||
node->update_gizmo();
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationMeshEditor::_clear_pressed() {
|
||||
|
||||
if (node)
|
||||
NavigationMeshGenerator::clear(node->get_navigation_mesh());
|
||||
EditorNavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh());
|
||||
|
||||
button_bake->set_pressed(false);
|
||||
bake_info->set_text("");
|
||||
|
|
|
@ -29,14 +29,31 @@
|
|||
/*************************************************************************/
|
||||
|
||||
#include "navigation_mesh_generator.h"
|
||||
#include "core/math/quick_hull.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "scene/3d/collision_shape.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "scene/3d/physics_body.h"
|
||||
#include "scene/resources/box_shape.h"
|
||||
#include "scene/resources/capsule_shape.h"
|
||||
#include "scene/resources/concave_polygon_shape.h"
|
||||
#include "scene/resources/convex_polygon_shape.h"
|
||||
#include "scene/resources/cylinder_shape.h"
|
||||
#include "scene/resources/plane_shape.h"
|
||||
#include "scene/resources/primitive_meshes.h"
|
||||
#include "scene/resources/shape.h"
|
||||
#include "scene/resources/sphere_shape.h"
|
||||
|
||||
void NavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies) {
|
||||
EditorNavigationMeshGenerator *EditorNavigationMeshGenerator::singleton = NULL;
|
||||
|
||||
void EditorNavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies) {
|
||||
p_verticies.push_back(p_vec3.x);
|
||||
p_verticies.push_back(p_vec3.y);
|
||||
p_verticies.push_back(p_vec3.z);
|
||||
}
|
||||
|
||||
void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) {
|
||||
void EditorNavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) {
|
||||
int current_vertex_count = 0;
|
||||
|
||||
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
|
||||
|
@ -91,23 +108,132 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform
|
|||
}
|
||||
}
|
||||
|
||||
void NavigationMeshGenerator::_parse_geometry(const Transform &p_base_inverse, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices) {
|
||||
void EditorNavigationMeshGenerator::_add_faces(const PoolVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) {
|
||||
int face_count = p_faces.size() / 3;
|
||||
int current_vertex_count = p_verticies.size() / 3;
|
||||
|
||||
if (Object::cast_to<MeshInstance>(p_node)) {
|
||||
for (int j = 0; j < face_count; j++) {
|
||||
_add_vertex(p_xform.xform(p_faces[j * 3 + 0]), p_verticies);
|
||||
_add_vertex(p_xform.xform(p_faces[j * 3 + 1]), p_verticies);
|
||||
_add_vertex(p_xform.xform(p_faces[j * 3 + 2]), p_verticies);
|
||||
|
||||
p_indices.push_back(current_vertex_count + (j * 3 + 0));
|
||||
p_indices.push_back(current_vertex_count + (j * 3 + 2));
|
||||
p_indices.push_back(current_vertex_count + (j * 3 + 1));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
if (Object::cast_to<MeshInstance>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
|
||||
|
||||
MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_node);
|
||||
Ref<Mesh> mesh = mesh_instance->get_mesh();
|
||||
if (mesh.is_valid()) {
|
||||
_add_mesh(mesh, p_base_inverse * mesh_instance->get_global_transform(), p_verticies, p_indices);
|
||||
_add_mesh(mesh, p_accumulated_transform * mesh_instance->get_transform(), p_verticies, p_indices);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object::cast_to<StaticBody>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES) {
|
||||
StaticBody *static_body = Object::cast_to<StaticBody>(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<CollisionShape>(child)) {
|
||||
CollisionShape *col_shape = Object::cast_to<CollisionShape>(child);
|
||||
|
||||
Transform transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform();
|
||||
|
||||
Ref<Mesh> mesh;
|
||||
Ref<Shape> s = col_shape->get_shape();
|
||||
|
||||
BoxShape *box = Object::cast_to<BoxShape>(*s);
|
||||
if (box) {
|
||||
Ref<CubeMesh> cube_mesh;
|
||||
cube_mesh.instance();
|
||||
cube_mesh->set_size(box->get_extents() * 2.0);
|
||||
mesh = cube_mesh;
|
||||
}
|
||||
|
||||
CapsuleShape *capsule = Object::cast_to<CapsuleShape>(*s);
|
||||
if (capsule) {
|
||||
Ref<CapsuleMesh> capsule_mesh;
|
||||
capsule_mesh.instance();
|
||||
capsule_mesh->set_radius(capsule->get_radius());
|
||||
capsule_mesh->set_mid_height(capsule->get_height() / 2.0);
|
||||
mesh = capsule_mesh;
|
||||
}
|
||||
|
||||
CylinderShape *cylinder = Object::cast_to<CylinderShape>(*s);
|
||||
if (cylinder) {
|
||||
Ref<CylinderMesh> cylinder_mesh;
|
||||
cylinder_mesh.instance();
|
||||
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;
|
||||
}
|
||||
|
||||
SphereShape *sphere = Object::cast_to<SphereShape>(*s);
|
||||
if (sphere) {
|
||||
Ref<SphereMesh> sphere_mesh;
|
||||
sphere_mesh.instance();
|
||||
sphere_mesh->set_radius(sphere->get_radius());
|
||||
sphere_mesh->set_height(sphere->get_radius() * 2.0);
|
||||
mesh = sphere_mesh;
|
||||
}
|
||||
|
||||
ConcavePolygonShape *concave_polygon = Object::cast_to<ConcavePolygonShape>(*s);
|
||||
if (concave_polygon) {
|
||||
_add_faces(concave_polygon->get_faces(), transform, p_verticies, p_indices);
|
||||
}
|
||||
|
||||
ConvexPolygonShape *convex_polygon = Object::cast_to<ConvexPolygonShape>(*s);
|
||||
if (convex_polygon) {
|
||||
Vector<Vector3> varr = Variant(convex_polygon->get_points());
|
||||
Geometry::MeshData md;
|
||||
|
||||
Error err = QuickHull::build(varr, md);
|
||||
|
||||
if (err == OK) {
|
||||
PoolVector3Array faces;
|
||||
|
||||
for (int j = 0; j < md.faces.size(); ++j) {
|
||||
Geometry::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, transform, p_verticies, p_indices);
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh.is_valid()) {
|
||||
_add_mesh(mesh, transform, p_verticies, p_indices);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object::cast_to<Spatial>(p_node)) {
|
||||
|
||||
Spatial *spatial = Object::cast_to<Spatial>(p_node);
|
||||
p_accumulated_transform = p_accumulated_transform * spatial->get_transform();
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
_parse_geometry(p_base_inverse, p_node->get_child(i), p_verticies, p_indices);
|
||||
_parse_geometry(p_accumulated_transform, p_node->get_child(i), p_verticies, p_indices, p_generate_from, p_collision_mask);
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh) {
|
||||
void EditorNavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh) {
|
||||
|
||||
PoolVector<Vector3> nav_vertices;
|
||||
|
||||
|
@ -135,7 +261,7 @@ void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(con
|
|||
}
|
||||
}
|
||||
|
||||
void NavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh> p_nav_mesh, EditorProgress *ep,
|
||||
void EditorNavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh> p_nav_mesh, EditorProgress *ep,
|
||||
rcHeightfield *hf, rcCompactHeightfield *chf, rcContourSet *cset, rcPolyMesh *poly_mesh, rcPolyMeshDetail *detail_mesh,
|
||||
Vector<float> &vertices, Vector<int> &indices) {
|
||||
rcContext ctx;
|
||||
|
@ -257,7 +383,18 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh>
|
|||
detail_mesh = 0;
|
||||
}
|
||||
|
||||
void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) {
|
||||
EditorNavigationMeshGenerator *EditorNavigationMeshGenerator::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
EditorNavigationMeshGenerator::EditorNavigationMeshGenerator() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
EditorNavigationMeshGenerator::~EditorNavigationMeshGenerator() {
|
||||
}
|
||||
|
||||
void EditorNavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) {
|
||||
|
||||
ERR_FAIL_COND(!p_nav_mesh.is_valid());
|
||||
|
||||
|
@ -267,7 +404,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
|
|||
Vector<float> vertices;
|
||||
Vector<int> indices;
|
||||
|
||||
_parse_geometry(Object::cast_to<Spatial>(p_node)->get_global_transform().affine_inverse(), p_node, vertices, 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());
|
||||
|
||||
if (vertices.size() > 0 && indices.size() > 0) {
|
||||
|
||||
|
@ -297,9 +434,14 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
|
|||
ep.step(TTR("Done!"), 11);
|
||||
}
|
||||
|
||||
void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_nav_mesh) {
|
||||
void EditorNavigationMeshGenerator::clear(Ref<NavigationMesh> p_nav_mesh) {
|
||||
if (p_nav_mesh.is_valid()) {
|
||||
p_nav_mesh->clear_polygons();
|
||||
p_nav_mesh->set_vertices(PoolVector<Vector3>());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorNavigationMeshGenerator::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("bake", "nav_mesh", "root_node"), &EditorNavigationMeshGenerator::bake);
|
||||
ClassDB::bind_method(D_METHOD("clear", "nav_mesh"), &EditorNavigationMeshGenerator::clear);
|
||||
}
|
||||
|
|
|
@ -31,20 +31,23 @@
|
|||
#ifndef NAVIGATION_MESH_GENERATOR_H
|
||||
#define NAVIGATION_MESH_GENERATOR_H
|
||||
|
||||
#include "core/os/thread.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "scene/3d/mesh_instance.h"
|
||||
#include "scene/3d/navigation_mesh.h"
|
||||
#include "scene/resources/shape.h"
|
||||
|
||||
#include <Recast.h>
|
||||
|
||||
class NavigationMeshGenerator {
|
||||
class EditorNavigationMeshGenerator : public Object {
|
||||
GDCLASS(EditorNavigationMeshGenerator, Object);
|
||||
|
||||
static EditorNavigationMeshGenerator *singleton;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
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 _parse_geometry(const Transform &p_base_inverse, Node *p_node, 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 _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,
|
||||
|
@ -52,8 +55,13 @@ protected:
|
|||
rcPolyMeshDetail *detail_mesh, Vector<float> &vertices, Vector<int> &indices);
|
||||
|
||||
public:
|
||||
static void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node);
|
||||
static void clear(Ref<NavigationMesh> p_nav_mesh);
|
||||
static EditorNavigationMeshGenerator *get_singleton();
|
||||
|
||||
EditorNavigationMeshGenerator();
|
||||
~EditorNavigationMeshGenerator();
|
||||
|
||||
void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node);
|
||||
void clear(Ref<NavigationMesh> p_nav_mesh);
|
||||
};
|
||||
|
||||
#endif // NAVIGATION_MESH_GENERATOR_H
|
||||
|
|
|
@ -32,8 +32,23 @@
|
|||
|
||||
#include "navigation_mesh_editor_plugin.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
EditorNavigationMeshGenerator *_nav_mesh_generator = NULL;
|
||||
#endif
|
||||
|
||||
void register_recast_types() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
EditorPlugins::add_by_type<NavigationMeshEditorPlugin>();
|
||||
_nav_mesh_generator = memnew(EditorNavigationMeshGenerator);
|
||||
ClassDB::register_class<EditorNavigationMeshGenerator>();
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", EditorNavigationMeshGenerator::get_singleton()));
|
||||
#endif
|
||||
}
|
||||
|
||||
void unregister_recast_types() {}
|
||||
void unregister_recast_types() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (_nav_mesh_generator) {
|
||||
memdelete(_nav_mesh_generator);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -73,6 +73,41 @@ int NavigationMesh::get_sample_partition_type() const {
|
|||
return static_cast<int>(partition_type);
|
||||
}
|
||||
|
||||
void NavigationMesh::set_parsed_geometry_type(int p_value) {
|
||||
ERR_FAIL_COND(p_value >= PARSED_GEOMETRY_MAX);
|
||||
parsed_geometry_type = static_cast<ParsedGeometryType>(p_value);
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
int NavigationMesh::get_parsed_geometry_type() const {
|
||||
return parsed_geometry_type;
|
||||
}
|
||||
|
||||
void NavigationMesh::set_collision_mask(uint32_t p_mask) {
|
||||
|
||||
collision_mask = p_mask;
|
||||
}
|
||||
|
||||
uint32_t NavigationMesh::get_collision_mask() const {
|
||||
|
||||
return collision_mask;
|
||||
}
|
||||
|
||||
void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) {
|
||||
|
||||
uint32_t mask = get_collision_mask();
|
||||
if (p_value)
|
||||
mask |= 1 << p_bit;
|
||||
else
|
||||
mask &= ~(1 << p_bit);
|
||||
set_collision_mask(mask);
|
||||
}
|
||||
|
||||
bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
|
||||
|
||||
return get_collision_mask() & (1 << p_bit);
|
||||
}
|
||||
|
||||
void NavigationMesh::set_cell_size(float p_value) {
|
||||
cell_size = p_value;
|
||||
}
|
||||
|
@ -204,6 +239,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const {
|
|||
void NavigationMesh::set_vertices(const PoolVector<Vector3> &p_vertices) {
|
||||
|
||||
vertices = p_vertices;
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
PoolVector<Vector3> NavigationMesh::get_vertices() const {
|
||||
|
@ -217,6 +253,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) {
|
|||
for (int i = 0; i < p_array.size(); i++) {
|
||||
polygons.write[i].indices = p_array[i];
|
||||
}
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
Array NavigationMesh::_get_polygons() const {
|
||||
|
@ -235,6 +272,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) {
|
|||
Polygon polygon;
|
||||
polygon.indices = p_polygon;
|
||||
polygons.push_back(polygon);
|
||||
_change_notify();
|
||||
}
|
||||
int NavigationMesh::get_polygon_count() const {
|
||||
|
||||
|
@ -340,6 +378,15 @@ void NavigationMesh::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type);
|
||||
ClassDB::bind_method(D_METHOD("get_sample_partition_type"), &NavigationMesh::get_sample_partition_type);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_parsed_geometry_type", "geometry_type"), &NavigationMesh::set_parsed_geometry_type);
|
||||
ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationMesh::get_parsed_geometry_type);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &NavigationMesh::set_collision_mask);
|
||||
ClassDB::bind_method(D_METHOD("get_collision_mask"), &NavigationMesh::get_collision_mask);
|
||||
|
||||
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_cell_size", "cell_size"), &NavigationMesh::set_cell_size);
|
||||
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size);
|
||||
|
||||
|
@ -405,10 +452,16 @@ void NavigationMesh::_bind_methods() {
|
|||
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");
|
||||
|
||||
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::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");
|
||||
|
@ -429,6 +482,15 @@ void NavigationMesh::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans");
|
||||
}
|
||||
|
||||
void NavigationMesh::_validate_property(PropertyInfo &property) const {
|
||||
if (property.name == "geometry/collision_mask") {
|
||||
if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) {
|
||||
property.usage = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NavigationMesh::NavigationMesh() {
|
||||
cell_size = 0.3f;
|
||||
cell_height = 0.2f;
|
||||
|
@ -445,7 +507,8 @@ NavigationMesh::NavigationMesh() {
|
|||
detail_sample_max_error = 1.0f;
|
||||
|
||||
partition_type = SAMPLE_PARTITION_WATERSHED;
|
||||
|
||||
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
|
||||
collision_mask = 0xFFFFFFFF;
|
||||
filter_low_hanging_obstacles = false;
|
||||
filter_ledge_spans = false;
|
||||
filter_walkable_low_height_spans = false;
|
||||
|
@ -566,8 +629,17 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na
|
|||
navigation->navmesh_remove(nav_id);
|
||||
nav_id = -1;
|
||||
}
|
||||
|
||||
if (navmesh.is_valid()) {
|
||||
navmesh->remove_change_receptor(this);
|
||||
}
|
||||
|
||||
navmesh = p_navmesh;
|
||||
|
||||
if (navmesh.is_valid()) {
|
||||
navmesh->add_change_receptor(this);
|
||||
}
|
||||
|
||||
if (navigation && navmesh.is_valid() && enabled) {
|
||||
nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
|
||||
}
|
||||
|
@ -617,6 +689,11 @@ void NavigationMeshInstance::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
|
||||
}
|
||||
|
||||
void NavigationMeshInstance::_changed_callback(Object *p_changed, const char *p_prop) {
|
||||
update_gizmo();
|
||||
update_configuration_warning();
|
||||
}
|
||||
|
||||
NavigationMeshInstance::NavigationMeshInstance() {
|
||||
|
||||
debug_view = NULL;
|
||||
|
@ -625,3 +702,8 @@ NavigationMeshInstance::NavigationMeshInstance() {
|
|||
enabled = true;
|
||||
set_notify_transform(true);
|
||||
}
|
||||
|
||||
NavigationMeshInstance::~NavigationMeshInstance() {
|
||||
if (navmesh.is_valid())
|
||||
navmesh->remove_change_receptor(this);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ class NavigationMesh : public Resource {
|
|||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
virtual void _validate_property(PropertyInfo &property) const;
|
||||
|
||||
void _set_polygons(const Array &p_array);
|
||||
Array _get_polygons() const;
|
||||
|
@ -69,6 +70,13 @@ public:
|
|||
SAMPLE_PARTITION_MAX
|
||||
};
|
||||
|
||||
enum ParsedGeometryType {
|
||||
PARSED_GEOMETRY_MESH_INSTANCES = 0,
|
||||
PARSED_GEOMETRY_STATIC_COLLIDERS,
|
||||
PARSED_GEOMETRY_BOTH,
|
||||
PARSED_GEOMETRY_MAX
|
||||
};
|
||||
|
||||
protected:
|
||||
float cell_size;
|
||||
float cell_height;
|
||||
|
@ -85,6 +93,8 @@ protected:
|
|||
float detail_sample_max_error;
|
||||
|
||||
SamplePartitionType partition_type;
|
||||
ParsedGeometryType parsed_geometry_type;
|
||||
uint32_t collision_mask;
|
||||
|
||||
bool filter_low_hanging_obstacles;
|
||||
bool filter_ledge_spans;
|
||||
|
@ -95,6 +105,15 @@ public:
|
|||
void set_sample_partition_type(int p_value);
|
||||
int get_sample_partition_type() const;
|
||||
|
||||
void set_parsed_geometry_type(int p_value);
|
||||
int get_parsed_geometry_type() const;
|
||||
|
||||
void set_collision_mask(uint32_t p_mask);
|
||||
uint32_t get_collision_mask() const;
|
||||
|
||||
void set_collision_mask_bit(int p_bit, bool p_value);
|
||||
bool get_collision_mask_bit(int p_bit) const;
|
||||
|
||||
void set_cell_size(float p_value);
|
||||
float get_cell_size() const;
|
||||
|
||||
|
@ -174,6 +193,7 @@ class NavigationMeshInstance : public Spatial {
|
|||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
void _changed_callback(Object *p_changed, const char *p_prop);
|
||||
|
||||
public:
|
||||
void set_enabled(bool p_enabled);
|
||||
|
@ -185,6 +205,7 @@ public:
|
|||
String get_configuration_warning() const;
|
||||
|
||||
NavigationMeshInstance();
|
||||
~NavigationMeshInstance();
|
||||
};
|
||||
|
||||
#endif // NAVIGATION_MESH_H
|
||||
|
|
Loading…
Reference in a new issue