Merge pull request #29118 from JFonS/improve_navmesh_generation
Various improvements to NavigationMesh generation
This commit is contained in:
commit
4c77332e32
6 changed files with 296 additions and 26 deletions
|
@ -54,26 +54,28 @@ void NavigationMeshEditor::_notification(int p_option) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigationMeshEditor::_bake_pressed() {
|
void NavigationMeshEditor::_bake_pressed() {
|
||||||
|
button_bake->set_pressed(false);
|
||||||
|
|
||||||
ERR_FAIL_COND(!node);
|
ERR_FAIL_COND(!node);
|
||||||
const String conf_warning = node->get_configuration_warning();
|
const String conf_warning = node->get_configuration_warning();
|
||||||
if (!conf_warning.empty()) {
|
if (!conf_warning.empty()) {
|
||||||
err_dialog->set_text(conf_warning);
|
err_dialog->set_text(conf_warning);
|
||||||
err_dialog->popup_centered_minsize();
|
err_dialog->popup_centered_minsize();
|
||||||
button_bake->set_pressed(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationMeshGenerator::clear(node->get_navigation_mesh());
|
EditorNavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh());
|
||||||
NavigationMeshGenerator::bake(node->get_navigation_mesh(), node);
|
EditorNavigationMeshGenerator::get_singleton()->bake(node->get_navigation_mesh(), node);
|
||||||
|
|
||||||
node->update_gizmo();
|
if (node) {
|
||||||
|
node->update_gizmo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigationMeshEditor::_clear_pressed() {
|
void NavigationMeshEditor::_clear_pressed() {
|
||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
NavigationMeshGenerator::clear(node->get_navigation_mesh());
|
EditorNavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh());
|
||||||
|
|
||||||
button_bake->set_pressed(false);
|
button_bake->set_pressed(false);
|
||||||
bake_info->set_text("");
|
bake_info->set_text("");
|
||||||
|
|
|
@ -29,14 +29,31 @@
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
#include "navigation_mesh_generator.h"
|
#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.x);
|
||||||
p_verticies.push_back(p_vec3.y);
|
p_verticies.push_back(p_vec3.y);
|
||||||
p_verticies.push_back(p_vec3.z);
|
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;
|
int current_vertex_count = 0;
|
||||||
|
|
||||||
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
|
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);
|
MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_node);
|
||||||
Ref<Mesh> mesh = mesh_instance->get_mesh();
|
Ref<Mesh> mesh = mesh_instance->get_mesh();
|
||||||
if (mesh.is_valid()) {
|
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++) {
|
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;
|
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,
|
rcHeightfield *hf, rcCompactHeightfield *chf, rcContourSet *cset, rcPolyMesh *poly_mesh, rcPolyMeshDetail *detail_mesh,
|
||||||
Vector<float> &vertices, Vector<int> &indices) {
|
Vector<float> &vertices, Vector<int> &indices) {
|
||||||
rcContext ctx;
|
rcContext ctx;
|
||||||
|
@ -257,7 +383,18 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(Ref<NavigationMesh>
|
||||||
detail_mesh = 0;
|
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());
|
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<float> vertices;
|
||||||
Vector<int> indices;
|
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) {
|
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);
|
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()) {
|
if (p_nav_mesh.is_valid()) {
|
||||||
p_nav_mesh->clear_polygons();
|
p_nav_mesh->clear_polygons();
|
||||||
p_nav_mesh->set_vertices(PoolVector<Vector3>());
|
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
|
#ifndef NAVIGATION_MESH_GENERATOR_H
|
||||||
#define NAVIGATION_MESH_GENERATOR_H
|
#define NAVIGATION_MESH_GENERATOR_H
|
||||||
|
|
||||||
#include "core/os/thread.h"
|
|
||||||
#include "editor/editor_node.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/3d/navigation_mesh.h"
|
||||||
#include "scene/resources/shape.h"
|
|
||||||
|
|
||||||
#include <Recast.h>
|
#include <Recast.h>
|
||||||
|
|
||||||
class NavigationMeshGenerator {
|
class EditorNavigationMeshGenerator : public Object {
|
||||||
|
GDCLASS(EditorNavigationMeshGenerator, Object);
|
||||||
|
|
||||||
|
static EditorNavigationMeshGenerator *singleton;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
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 _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 _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,
|
||||||
|
@ -52,8 +55,13 @@ protected:
|
||||||
rcPolyMeshDetail *detail_mesh, Vector<float> &vertices, Vector<int> &indices);
|
rcPolyMeshDetail *detail_mesh, Vector<float> &vertices, Vector<int> &indices);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node);
|
static EditorNavigationMeshGenerator *get_singleton();
|
||||||
static void clear(Ref<NavigationMesh> p_nav_mesh);
|
|
||||||
|
EditorNavigationMeshGenerator();
|
||||||
|
~EditorNavigationMeshGenerator();
|
||||||
|
|
||||||
|
void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node);
|
||||||
|
void clear(Ref<NavigationMesh> p_nav_mesh);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAVIGATION_MESH_GENERATOR_H
|
#endif // NAVIGATION_MESH_GENERATOR_H
|
||||||
|
|
|
@ -32,8 +32,23 @@
|
||||||
|
|
||||||
#include "navigation_mesh_editor_plugin.h"
|
#include "navigation_mesh_editor_plugin.h"
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
EditorNavigationMeshGenerator *_nav_mesh_generator = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
void register_recast_types() {
|
void register_recast_types() {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
EditorPlugins::add_by_type<NavigationMeshEditorPlugin>();
|
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);
|
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) {
|
void NavigationMesh::set_cell_size(float p_value) {
|
||||||
cell_size = 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) {
|
void NavigationMesh::set_vertices(const PoolVector<Vector3> &p_vertices) {
|
||||||
|
|
||||||
vertices = p_vertices;
|
vertices = p_vertices;
|
||||||
|
_change_notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolVector<Vector3> NavigationMesh::get_vertices() const {
|
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++) {
|
for (int i = 0; i < p_array.size(); i++) {
|
||||||
polygons.write[i].indices = p_array[i];
|
polygons.write[i].indices = p_array[i];
|
||||||
}
|
}
|
||||||
|
_change_notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
Array NavigationMesh::_get_polygons() const {
|
Array NavigationMesh::_get_polygons() const {
|
||||||
|
@ -235,6 +272,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) {
|
||||||
Polygon polygon;
|
Polygon polygon;
|
||||||
polygon.indices = p_polygon;
|
polygon.indices = p_polygon;
|
||||||
polygons.push_back(polygon);
|
polygons.push_back(polygon);
|
||||||
|
_change_notify();
|
||||||
}
|
}
|
||||||
int NavigationMesh::get_polygon_count() const {
|
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("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("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("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);
|
||||||
|
|
||||||
|
@ -405,10 +452,16 @@ void NavigationMesh::_bind_methods() {
|
||||||
BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE);
|
BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE);
|
||||||
BIND_CONSTANT(SAMPLE_PARTITION_LAYERS);
|
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::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::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, "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/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");
|
||||||
|
@ -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");
|
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() {
|
NavigationMesh::NavigationMesh() {
|
||||||
cell_size = 0.3f;
|
cell_size = 0.3f;
|
||||||
cell_height = 0.2f;
|
cell_height = 0.2f;
|
||||||
|
@ -445,7 +507,8 @@ NavigationMesh::NavigationMesh() {
|
||||||
detail_sample_max_error = 1.0f;
|
detail_sample_max_error = 1.0f;
|
||||||
|
|
||||||
partition_type = SAMPLE_PARTITION_WATERSHED;
|
partition_type = SAMPLE_PARTITION_WATERSHED;
|
||||||
|
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
|
||||||
|
collision_mask = 0xFFFFFFFF;
|
||||||
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;
|
||||||
|
@ -566,8 +629,17 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na
|
||||||
navigation->navmesh_remove(nav_id);
|
navigation->navmesh_remove(nav_id);
|
||||||
nav_id = -1;
|
nav_id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (navmesh.is_valid()) {
|
||||||
|
navmesh->remove_change_receptor(this);
|
||||||
|
}
|
||||||
|
|
||||||
navmesh = p_navmesh;
|
navmesh = p_navmesh;
|
||||||
|
|
||||||
|
if (navmesh.is_valid()) {
|
||||||
|
navmesh->add_change_receptor(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (navigation && navmesh.is_valid() && enabled) {
|
if (navigation && navmesh.is_valid() && enabled) {
|
||||||
nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
|
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");
|
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() {
|
NavigationMeshInstance::NavigationMeshInstance() {
|
||||||
|
|
||||||
debug_view = NULL;
|
debug_view = NULL;
|
||||||
|
@ -625,3 +702,8 @@ NavigationMeshInstance::NavigationMeshInstance() {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
set_notify_transform(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:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
virtual void _validate_property(PropertyInfo &property) const;
|
||||||
|
|
||||||
void _set_polygons(const Array &p_array);
|
void _set_polygons(const Array &p_array);
|
||||||
Array _get_polygons() const;
|
Array _get_polygons() const;
|
||||||
|
@ -69,6 +70,13 @@ public:
|
||||||
SAMPLE_PARTITION_MAX
|
SAMPLE_PARTITION_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ParsedGeometryType {
|
||||||
|
PARSED_GEOMETRY_MESH_INSTANCES = 0,
|
||||||
|
PARSED_GEOMETRY_STATIC_COLLIDERS,
|
||||||
|
PARSED_GEOMETRY_BOTH,
|
||||||
|
PARSED_GEOMETRY_MAX
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float cell_size;
|
float cell_size;
|
||||||
float cell_height;
|
float cell_height;
|
||||||
|
@ -85,6 +93,8 @@ protected:
|
||||||
float detail_sample_max_error;
|
float detail_sample_max_error;
|
||||||
|
|
||||||
SamplePartitionType partition_type;
|
SamplePartitionType partition_type;
|
||||||
|
ParsedGeometryType parsed_geometry_type;
|
||||||
|
uint32_t collision_mask;
|
||||||
|
|
||||||
bool filter_low_hanging_obstacles;
|
bool filter_low_hanging_obstacles;
|
||||||
bool filter_ledge_spans;
|
bool filter_ledge_spans;
|
||||||
|
@ -95,6 +105,15 @@ public:
|
||||||
void set_sample_partition_type(int p_value);
|
void set_sample_partition_type(int p_value);
|
||||||
int get_sample_partition_type() const;
|
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);
|
void set_cell_size(float p_value);
|
||||||
float get_cell_size() const;
|
float get_cell_size() const;
|
||||||
|
|
||||||
|
@ -174,6 +193,7 @@ class NavigationMeshInstance : public Spatial {
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
void _changed_callback(Object *p_changed, const char *p_prop);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set_enabled(bool p_enabled);
|
void set_enabled(bool p_enabled);
|
||||||
|
@ -185,6 +205,7 @@ public:
|
||||||
String get_configuration_warning() const;
|
String get_configuration_warning() const;
|
||||||
|
|
||||||
NavigationMeshInstance();
|
NavigationMeshInstance();
|
||||||
|
~NavigationMeshInstance();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAVIGATION_MESH_H
|
#endif // NAVIGATION_MESH_H
|
||||||
|
|
Loading…
Reference in a new issue