diff --git a/doc/classes/MeshConvexDecompositionSettings.xml b/doc/classes/MeshConvexDecompositionSettings.xml new file mode 100644 index 00000000000..a2784c4485a --- /dev/null +++ b/doc/classes/MeshConvexDecompositionSettings.xml @@ -0,0 +1,60 @@ + + + + Parameters to be used with a [Mesh] convex decomposition operation. + + + Parameters to be used with a [Mesh] convex decomposition operation. + + + + + + If enabled uses approximation for computing convex hulls. + + + Controls the precision of the convex-hull generation process during the clipping plane selection stage. Ranges from [code]1[/code] to [code]16[/code]. + + + Maximum concavity. Ranges from [code]0.0[/code] to [code]1.0[/code]. + + + The maximum number of convex hulls to produce from the merge operation. + + + Controls the maximum number of triangles per convex-hull. Ranges from [code]4[/code] to [code]1024[/code]. + + + Controls the adaptive sampling of the generated convex-hulls. Ranges from [code]0.0[/code] to [code]0.01[/code]. + + + Mode for the approximate convex decomposition. + + + If enabled normalizes the mesh before applying the convex decomposition. + + + Controls the granularity of the search for the "best" clipping plane. Ranges from [code]1[/code] to [code]16[/code]. + + + If enabled projects output convex hull vertices onto original source mesh to increase floating point accuracy of the results. + + + Maximum number of voxels generated during the voxelization stage. + + + Controls the bias toward clipping along revolution axes. Ranges from [code]0.0[/code] to [code]1.0[/code]. + + + Controls the bias toward clipping along symmetry planes. Ranges from [code]0.0[/code] to [code]1.0[/code]. + + + + + Constant for voxel-based approximate convex decomposition. + + + Constant for tetrahedron-based approximate convex decomposition. + + + diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml index 187f2510c5b..fb6702263eb 100644 --- a/doc/classes/MeshInstance3D.xml +++ b/doc/classes/MeshInstance3D.xml @@ -31,8 +31,9 @@ + - This helper creates a [StaticBody3D] child node with multiple [ConvexPolygonShape3D] collision shapes calculated from the mesh geometry via convex decomposition. It's mainly used for testing. + This helper creates a [StaticBody3D] child node with multiple [ConvexPolygonShape3D] collision shapes calculated from the mesh geometry via convex decomposition. The convex decomposition operation can be controlled with parameters from the optional [param settings]. diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 038a16f566c..c052f925081 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1604,22 +1604,23 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/shape_type", PROPERTY_HINT_ENUM, "Decompose Convex,Simple Convex,Trimesh,Box,Sphere,Cylinder,Capsule", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); // Decomposition - Mesh::ConvexDecompositionSettings decomposition_default; + Ref decomposition_default = Ref(); + decomposition_default.instantiate(); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/advanced", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/precision", PROPERTY_HINT_RANGE, "1,10,1"), 5)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/max_concavity", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.max_concavity)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/symmetry_planes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.symmetry_planes_clipping_bias)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/revolution_axes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.revolution_axes_clipping_bias)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/min_volume_per_convex_hull", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.min_volume_per_convex_hull)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/resolution", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.resolution)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_num_vertices_per_convex_hull", PROPERTY_HINT_RANGE, "5,512,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.max_num_vertices_per_convex_hull)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/plane_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.plane_downsampling)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/convexhull_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.convexhull_downsampling)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/normalize_mesh", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.normalize_mesh)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/mode", PROPERTY_HINT_ENUM, "Voxel,Tetrahedron", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), static_cast(decomposition_default.mode))); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/convexhull_approximation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.convexhull_approximation)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_convex_hulls", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.max_convex_hulls)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/project_hull_vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default.project_hull_vertices)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/max_concavity", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_max_concavity())); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/symmetry_planes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_symmetry_planes_clipping_bias())); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/revolution_axes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_revolution_axes_clipping_bias())); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/min_volume_per_convex_hull", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_min_volume_per_convex_hull())); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/resolution", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_resolution())); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_num_vertices_per_convex_hull", PROPERTY_HINT_RANGE, "5,512,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_max_num_vertices_per_convex_hull())); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/plane_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_plane_downsampling())); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/convexhull_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_convex_hull_downsampling())); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/normalize_mesh", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_normalize_mesh())); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/mode", PROPERTY_HINT_ENUM, "Voxel,Tetrahedron", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), static_cast(decomposition_default->get_mode()))); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/convexhull_approximation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_convex_hull_approximation())); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_convex_hulls", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_max_convex_hulls())); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/project_hull_vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), decomposition_default->get_project_hull_vertices())); // Primitives: Box, Sphere, Cylinder, Capsule. r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Vector3(2.0, 2.0, 2.0))); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 520ccd10708..a66fd034f82 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -323,7 +323,8 @@ Vector> ResourceImporterScene::get_collision_shapes(const Ref decomposition_settings = Ref(); + decomposition_settings.instantiate(); bool advanced = false; if (p_options.has(SNAME("decomposition/advanced"))) { advanced = p_options[SNAME("decomposition/advanced")]; @@ -331,55 +332,55 @@ Vector> ResourceImporterScene::get_collision_shapes(const Refset_max_concavity(p_options[SNAME("decomposition/max_concavity")]); } if (p_options.has(SNAME("decomposition/symmetry_planes_clipping_bias"))) { - decomposition_settings.symmetry_planes_clipping_bias = p_options[SNAME("decomposition/symmetry_planes_clipping_bias")]; + decomposition_settings->set_symmetry_planes_clipping_bias(p_options[SNAME("decomposition/symmetry_planes_clipping_bias")]); } if (p_options.has(SNAME("decomposition/revolution_axes_clipping_bias"))) { - decomposition_settings.revolution_axes_clipping_bias = p_options[SNAME("decomposition/revolution_axes_clipping_bias")]; + decomposition_settings->set_revolution_axes_clipping_bias(p_options[SNAME("decomposition/revolution_axes_clipping_bias")]); } if (p_options.has(SNAME("decomposition/min_volume_per_convex_hull"))) { - decomposition_settings.min_volume_per_convex_hull = p_options[SNAME("decomposition/min_volume_per_convex_hull")]; + decomposition_settings->set_min_volume_per_convex_hull(p_options[SNAME("decomposition/min_volume_per_convex_hull")]); } if (p_options.has(SNAME("decomposition/resolution"))) { - decomposition_settings.resolution = p_options[SNAME("decomposition/resolution")]; + decomposition_settings->set_resolution(p_options[SNAME("decomposition/resolution")]); } if (p_options.has(SNAME("decomposition/max_num_vertices_per_convex_hull"))) { - decomposition_settings.max_num_vertices_per_convex_hull = p_options[SNAME("decomposition/max_num_vertices_per_convex_hull")]; + decomposition_settings->set_max_num_vertices_per_convex_hull(p_options[SNAME("decomposition/max_num_vertices_per_convex_hull")]); } if (p_options.has(SNAME("decomposition/plane_downsampling"))) { - decomposition_settings.plane_downsampling = p_options[SNAME("decomposition/plane_downsampling")]; + decomposition_settings->set_plane_downsampling(p_options[SNAME("decomposition/plane_downsampling")]); } if (p_options.has(SNAME("decomposition/convexhull_downsampling"))) { - decomposition_settings.convexhull_downsampling = p_options[SNAME("decomposition/convexhull_downsampling")]; + decomposition_settings->set_convex_hull_downsampling(p_options[SNAME("decomposition/convexhull_downsampling")]); } if (p_options.has(SNAME("decomposition/normalize_mesh"))) { - decomposition_settings.normalize_mesh = p_options[SNAME("decomposition/normalize_mesh")]; + decomposition_settings->set_normalize_mesh(p_options[SNAME("decomposition/normalize_mesh")]); } if (p_options.has(SNAME("decomposition/mode"))) { - decomposition_settings.mode = (Mesh::ConvexDecompositionSettings::Mode)p_options[SNAME("decomposition/mode")].operator int(); + decomposition_settings->set_mode((MeshConvexDecompositionSettings::Mode)p_options[SNAME("decomposition/mode")].operator int()); } if (p_options.has(SNAME("decomposition/convexhull_approximation"))) { - decomposition_settings.convexhull_approximation = p_options[SNAME("decomposition/convexhull_approximation")]; + decomposition_settings->set_convex_hull_approximation(p_options[SNAME("decomposition/convexhull_approximation")]); } if (p_options.has(SNAME("decomposition/max_convex_hulls"))) { - decomposition_settings.max_convex_hulls = MAX(1, (int)p_options[SNAME("decomposition/max_convex_hulls")]); + decomposition_settings->set_max_convex_hulls(MAX(1, (int)p_options[SNAME("decomposition/max_convex_hulls")])); } if (p_options.has(SNAME("decomposition/project_hull_vertices"))) { - decomposition_settings.project_hull_vertices = p_options[SNAME("decomposition/project_hull_vertices")]; + decomposition_settings->set_project_hull_vertices(p_options[SNAME("decomposition/project_hull_vertices")]); } } else { int precision_level = 5; @@ -389,13 +390,13 @@ Vector> ResourceImporterScene::get_collision_shapes(const Refset_max_concavity(Math::lerp(real_t(1.0), real_t(0.001), precision)); + decomposition_settings->set_min_volume_per_convex_hull(Math::lerp(real_t(0.01), real_t(0.0001), precision)); + decomposition_settings->set_resolution(Math::lerp(10'000, 100'000, precision)); + decomposition_settings->set_max_num_vertices_per_convex_hull(Math::lerp(32, 64, precision)); + decomposition_settings->set_plane_downsampling(Math::lerp(3, 16, precision)); + decomposition_settings->set_convex_hull_downsampling(Math::lerp(3, 16, precision)); + decomposition_settings->set_max_convex_hulls(Math::lerp(1, 32, precision)); } return p_mesh->convex_decompose(decomposition_settings); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index e8976667dd5..2ebb4d29c5e 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -214,7 +214,11 @@ void MeshInstance3DEditor::_menu_option(int p_option) { return; } - Mesh::ConvexDecompositionSettings settings; + Ref settings = Ref(); + settings.instantiate(); + settings->set_max_convex_hulls(32); + settings->set_max_concavity(0.001); + Vector> shapes = mesh->convex_decompose(settings); if (!shapes.size()) { diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp index 6310becf1b6..088f03ebe85 100644 --- a/modules/vhacd/register_types.cpp +++ b/modules/vhacd/register_types.cpp @@ -32,22 +32,22 @@ #include "scene/resources/mesh.h" #include "thirdparty/vhacd/public/VHACD.h" -static Vector> convex_decompose(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Mesh::ConvexDecompositionSettings &p_settings, Vector> *r_convex_indices) { +static Vector> convex_decompose(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Ref &p_settings, Vector> *r_convex_indices) { VHACD::IVHACD::Parameters params; - params.m_concavity = p_settings.max_concavity; - params.m_alpha = p_settings.symmetry_planes_clipping_bias; - params.m_beta = p_settings.revolution_axes_clipping_bias; - params.m_minVolumePerCH = p_settings.min_volume_per_convex_hull; - params.m_resolution = p_settings.resolution; - params.m_maxNumVerticesPerCH = p_settings.max_num_vertices_per_convex_hull; - params.m_planeDownsampling = p_settings.plane_downsampling; - params.m_convexhullDownsampling = p_settings.convexhull_downsampling; - params.m_pca = p_settings.normalize_mesh; - params.m_mode = p_settings.mode; - params.m_convexhullApproximation = p_settings.convexhull_approximation; + params.m_concavity = p_settings->get_max_concavity(); + params.m_alpha = p_settings->get_symmetry_planes_clipping_bias(); + params.m_beta = p_settings->get_revolution_axes_clipping_bias(); + params.m_minVolumePerCH = p_settings->get_min_volume_per_convex_hull(); + params.m_resolution = p_settings->get_resolution(); + params.m_maxNumVerticesPerCH = p_settings->get_max_num_vertices_per_convex_hull(); + params.m_planeDownsampling = p_settings->get_plane_downsampling(); + params.m_convexhullDownsampling = p_settings->get_convex_hull_downsampling(); + params.m_pca = p_settings->get_normalize_mesh(); + params.m_mode = p_settings->get_mode(); + params.m_convexhullApproximation = p_settings->get_convex_hull_approximation(); params.m_oclAcceleration = true; - params.m_maxConvexHulls = p_settings.max_convex_hulls; - params.m_projectHullVertices = p_settings.project_hull_vertices; + params.m_maxConvexHulls = p_settings->get_max_convex_hulls(); + params.m_projectHullVertices = p_settings->get_project_hull_vertices(); VHACD::IVHACD *decomposer = VHACD::CreateVHACD(); decomposer->Compute(p_vertices, p_vertex_count, p_triangles, p_triangle_count, params); diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index 86301ee53f7..0f7db64f5c4 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -284,12 +284,18 @@ void MeshInstance3D::create_convex_collision(bool p_clean, bool p_simplify) { } } -Node *MeshInstance3D::create_multiple_convex_collisions_node() { +Node *MeshInstance3D::create_multiple_convex_collisions_node(const Ref &p_settings) { if (mesh.is_null()) { return nullptr; } - Mesh::ConvexDecompositionSettings settings; + Ref settings; + if (p_settings.is_valid()) { + settings = p_settings; + } else { + settings.instantiate(); + } + Vector> shapes = mesh->convex_decompose(settings); if (!shapes.size()) { return nullptr; @@ -304,8 +310,8 @@ Node *MeshInstance3D::create_multiple_convex_collisions_node() { return static_body; } -void MeshInstance3D::create_multiple_convex_collisions() { - StaticBody3D *static_body = Object::cast_to(create_multiple_convex_collisions_node()); +void MeshInstance3D::create_multiple_convex_collisions(const Ref &p_settings) { + StaticBody3D *static_body = Object::cast_to(create_multiple_convex_collisions_node(p_settings)); ERR_FAIL_COND(!static_body); static_body->set_name(String(get_name()) + "_col"); @@ -504,7 +510,7 @@ void MeshInstance3D::_bind_methods() { ClassDB::set_method_flags("MeshInstance3D", "create_trimesh_collision", METHOD_FLAGS_DEFAULT); ClassDB::bind_method(D_METHOD("create_convex_collision", "clean", "simplify"), &MeshInstance3D::create_convex_collision, DEFVAL(true), DEFVAL(false)); ClassDB::set_method_flags("MeshInstance3D", "create_convex_collision", METHOD_FLAGS_DEFAULT); - ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions"), &MeshInstance3D::create_multiple_convex_collisions); + ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions", "settings"), &MeshInstance3D::create_multiple_convex_collisions, DEFVAL(Ref())); ClassDB::set_method_flags("MeshInstance3D", "create_multiple_convex_collisions", METHOD_FLAGS_DEFAULT); ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &MeshInstance3D::get_blend_shape_count); diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h index 4a6d7dd95dd..0a7ffa0beed 100644 --- a/scene/3d/mesh_instance_3d.h +++ b/scene/3d/mesh_instance_3d.h @@ -88,8 +88,8 @@ public: Node *create_convex_collision_node(bool p_clean = true, bool p_simplify = false); void create_convex_collision(bool p_clean = true, bool p_simplify = false); - Node *create_multiple_convex_collisions_node(); - void create_multiple_convex_collisions(); + Node *create_multiple_convex_collisions_node(const Ref &p_settings = Ref()); + void create_multiple_convex_collisions(const Ref &p_settings = Ref()); MeshInstance3D *create_debug_tangents_node(); void create_debug_tangents(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index b13b8a41af9..feff4a6dc9b 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -781,6 +781,7 @@ void register_scene_types() { ParticleProcessMaterial::init_shaders(); GDREGISTER_VIRTUAL_CLASS(Mesh); + GDREGISTER_CLASS(MeshConvexDecompositionSettings); GDREGISTER_CLASS(ArrayMesh); GDREGISTER_CLASS(PlaceholderMesh); GDREGISTER_CLASS(ImmediateMesh); diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 0fc72ca90f6..09738757fd4 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -938,7 +938,7 @@ Vector ImporterMesh::get_faces() const { return faces; } -Vector> ImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const { +Vector> ImporterMesh::convex_decompose(const Ref &p_settings) const { ERR_FAIL_COND_V(!Mesh::convex_decomposition_function, Vector>()); const Vector faces = get_faces(); @@ -987,8 +987,9 @@ Vector> ImporterMesh::convex_decompose(const Mesh::ConvexDecomposit Ref ImporterMesh::create_convex_shape(bool p_clean, bool p_simplify) const { if (p_simplify) { - Mesh::ConvexDecompositionSettings settings; - settings.max_convex_hulls = 1; + Ref settings; + settings.instantiate(); + settings->set_max_convex_hulls(1); Vector> decomposed = convex_decompose(settings); if (decomposed.size() == 1) { return decomposed[0]; diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h index 33d08643428..69becc46a34 100644 --- a/scene/resources/importer_mesh.h +++ b/scene/resources/importer_mesh.h @@ -118,7 +118,7 @@ public: Ref get_shadow_mesh() const; Vector get_faces() const; - Vector> convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const; + Vector> convex_decompose(const Ref &p_settings) const; Ref create_convex_shape(bool p_clean = true, bool p_simplify = false) const; Ref create_trimesh_shape() const; Ref create_navigation_mesh(); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index a7b53244e24..8a91e9f6e02 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -37,6 +37,168 @@ #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" +void MeshConvexDecompositionSettings::set_max_concavity(real_t p_max_concavity) { + max_concavity = CLAMP(p_max_concavity, 0.001, 1.0); +} + +real_t MeshConvexDecompositionSettings::get_max_concavity() const { + return max_concavity; +}; + +void MeshConvexDecompositionSettings::set_symmetry_planes_clipping_bias(real_t p_symmetry_planes_clipping_bias) { + symmetry_planes_clipping_bias = CLAMP(p_symmetry_planes_clipping_bias, 0.0, 1.0); +}; + +real_t MeshConvexDecompositionSettings::get_symmetry_planes_clipping_bias() const { + return symmetry_planes_clipping_bias; +}; + +void MeshConvexDecompositionSettings::set_revolution_axes_clipping_bias(real_t p_revolution_axes_clipping_bias) { + revolution_axes_clipping_bias = CLAMP(p_revolution_axes_clipping_bias, 0.0, 1.0); +}; + +real_t MeshConvexDecompositionSettings::get_revolution_axes_clipping_bias() const { + return revolution_axes_clipping_bias; +}; + +void MeshConvexDecompositionSettings::set_min_volume_per_convex_hull(real_t p_min_volume_per_convex_hull) { + min_volume_per_convex_hull = CLAMP(p_min_volume_per_convex_hull, 0.0001, 0.01); +} + +real_t MeshConvexDecompositionSettings::get_min_volume_per_convex_hull() const { + return min_volume_per_convex_hull; +} + +void MeshConvexDecompositionSettings::set_resolution(uint32_t p_resolution) { + resolution = p_resolution < 10'000 ? 10'000 : (p_resolution > 100'000 ? 100'000 : p_resolution); +} + +uint32_t MeshConvexDecompositionSettings::get_resolution() const { + return resolution; +} + +void MeshConvexDecompositionSettings::set_max_num_vertices_per_convex_hull(uint32_t p_max_num_vertices_per_convex_hull) { + max_num_vertices_per_convex_hull = p_max_num_vertices_per_convex_hull < 4 ? 4 : (p_max_num_vertices_per_convex_hull > 1024 ? 1024 : p_max_num_vertices_per_convex_hull); +} + +uint32_t MeshConvexDecompositionSettings::get_max_num_vertices_per_convex_hull() const { + return max_num_vertices_per_convex_hull; +} + +void MeshConvexDecompositionSettings::set_plane_downsampling(uint32_t p_plane_downsampling) { + plane_downsampling = p_plane_downsampling < 1 ? 1 : (p_plane_downsampling > 16 ? 16 : p_plane_downsampling); +} + +uint32_t MeshConvexDecompositionSettings::get_plane_downsampling() const { + return plane_downsampling; +} + +void MeshConvexDecompositionSettings::set_convex_hull_downsampling(uint32_t p_convex_hull_downsampling) { + convex_hull_downsampling = p_convex_hull_downsampling < 1 ? 1 : (p_convex_hull_downsampling > 16 ? 16 : p_convex_hull_downsampling); +} + +uint32_t MeshConvexDecompositionSettings::get_convex_hull_downsampling() const { + return convex_hull_downsampling; +} + +void MeshConvexDecompositionSettings::set_normalize_mesh(bool p_normalize_mesh) { + normalize_mesh = p_normalize_mesh; +} + +bool MeshConvexDecompositionSettings::get_normalize_mesh() const { + return normalize_mesh; +} + +void MeshConvexDecompositionSettings::set_mode(Mode p_mode) { + mode = p_mode; +} + +MeshConvexDecompositionSettings::Mode MeshConvexDecompositionSettings::get_mode() const { + return mode; +} + +void MeshConvexDecompositionSettings::set_convex_hull_approximation(bool p_convex_hull_approximation) { + convex_hull_approximation = p_convex_hull_approximation; +} + +bool MeshConvexDecompositionSettings::get_convex_hull_approximation() const { + return convex_hull_approximation; +} + +void MeshConvexDecompositionSettings::set_max_convex_hulls(uint32_t p_max_convex_hulls) { + max_convex_hulls = p_max_convex_hulls < 1 ? 1 : (p_max_convex_hulls > 32 ? 32 : p_max_convex_hulls); +} + +uint32_t MeshConvexDecompositionSettings::get_max_convex_hulls() const { + return max_convex_hulls; +} + +void MeshConvexDecompositionSettings::set_project_hull_vertices(bool p_project_hull_vertices) { + project_hull_vertices = p_project_hull_vertices; +} + +bool MeshConvexDecompositionSettings::get_project_hull_vertices() const { + return project_hull_vertices; +} + +void MeshConvexDecompositionSettings::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_max_concavity", "max_concavity"), &MeshConvexDecompositionSettings::set_max_concavity); + ClassDB::bind_method(D_METHOD("get_max_concavity"), &MeshConvexDecompositionSettings::get_max_concavity); + + ClassDB::bind_method(D_METHOD("set_symmetry_planes_clipping_bias", "symmetry_planes_clipping_bias"), &MeshConvexDecompositionSettings::set_symmetry_planes_clipping_bias); + ClassDB::bind_method(D_METHOD("get_symmetry_planes_clipping_bias"), &MeshConvexDecompositionSettings::get_symmetry_planes_clipping_bias); + + ClassDB::bind_method(D_METHOD("set_revolution_axes_clipping_bias", "revolution_axes_clipping_bias"), &MeshConvexDecompositionSettings::set_revolution_axes_clipping_bias); + ClassDB::bind_method(D_METHOD("get_revolution_axes_clipping_bias"), &MeshConvexDecompositionSettings::get_revolution_axes_clipping_bias); + + ClassDB::bind_method(D_METHOD("set_min_volume_per_convex_hull", "min_volume_per_convex_hull"), &MeshConvexDecompositionSettings::set_min_volume_per_convex_hull); + ClassDB::bind_method(D_METHOD("get_min_volume_per_convex_hull"), &MeshConvexDecompositionSettings::get_min_volume_per_convex_hull); + + ClassDB::bind_method(D_METHOD("set_resolution", "min_volume_per_convex_hull"), &MeshConvexDecompositionSettings::set_resolution); + ClassDB::bind_method(D_METHOD("get_resolution"), &MeshConvexDecompositionSettings::get_resolution); + + ClassDB::bind_method(D_METHOD("set_max_num_vertices_per_convex_hull", "max_num_vertices_per_convex_hull"), &MeshConvexDecompositionSettings::set_max_num_vertices_per_convex_hull); + ClassDB::bind_method(D_METHOD("get_max_num_vertices_per_convex_hull"), &MeshConvexDecompositionSettings::get_max_num_vertices_per_convex_hull); + + ClassDB::bind_method(D_METHOD("set_plane_downsampling", "plane_downsampling"), &MeshConvexDecompositionSettings::set_plane_downsampling); + ClassDB::bind_method(D_METHOD("get_plane_downsampling"), &MeshConvexDecompositionSettings::get_plane_downsampling); + + ClassDB::bind_method(D_METHOD("set_convex_hull_downsampling", "convex_hull_downsampling"), &MeshConvexDecompositionSettings::set_convex_hull_downsampling); + ClassDB::bind_method(D_METHOD("get_convex_hull_downsampling"), &MeshConvexDecompositionSettings::get_convex_hull_downsampling); + + ClassDB::bind_method(D_METHOD("set_normalize_mesh", "normalize_mesh"), &MeshConvexDecompositionSettings::set_normalize_mesh); + ClassDB::bind_method(D_METHOD("get_normalize_mesh"), &MeshConvexDecompositionSettings::get_normalize_mesh); + + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &MeshConvexDecompositionSettings::set_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &MeshConvexDecompositionSettings::get_mode); + + ClassDB::bind_method(D_METHOD("set_convex_hull_approximation", "convex_hull_approximation"), &MeshConvexDecompositionSettings::set_convex_hull_approximation); + ClassDB::bind_method(D_METHOD("get_convex_hull_approximation"), &MeshConvexDecompositionSettings::get_convex_hull_approximation); + + ClassDB::bind_method(D_METHOD("set_max_convex_hulls", "max_convex_hulls"), &MeshConvexDecompositionSettings::set_max_convex_hulls); + ClassDB::bind_method(D_METHOD("get_max_convex_hulls"), &MeshConvexDecompositionSettings::get_max_convex_hulls); + + ClassDB::bind_method(D_METHOD("set_project_hull_vertices", "project_hull_vertices"), &MeshConvexDecompositionSettings::set_project_hull_vertices); + ClassDB::bind_method(D_METHOD("get_project_hull_vertices"), &MeshConvexDecompositionSettings::get_project_hull_vertices); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_concavity", PROPERTY_HINT_RANGE, "0.001,1.0,0.001"), "set_max_concavity", "get_max_concavity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "symmetry_planes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_symmetry_planes_clipping_bias", "get_symmetry_planes_clipping_bias"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "revolution_axes_clipping_bias", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_revolution_axes_clipping_bias", "get_revolution_axes_clipping_bias"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min_volume_per_convex_hull", PROPERTY_HINT_RANGE, "0.0001,0.01,0.0001"), "set_min_volume_per_convex_hull", "get_min_volume_per_convex_hull"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution"), "set_resolution", "get_resolution"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_num_vertices_per_convex_hull"), "set_max_num_vertices_per_convex_hull", "get_max_num_vertices_per_convex_hull"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "plane_downsampling", PROPERTY_HINT_RANGE, "1,16,1"), "set_plane_downsampling", "get_plane_downsampling"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "convex_hull_downsampling", PROPERTY_HINT_RANGE, "1,16,1"), "set_convex_hull_downsampling", "get_convex_hull_downsampling"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "normalize_mesh"), "set_normalize_mesh", "get_normalize_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Voxel,Tetrahedron"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "convex_hull_approximation"), "set_convex_hull_approximation", "get_convex_hull_approximation"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_convex_hulls"), "set_max_convex_hulls", "get_max_convex_hulls"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "project_hull_vertices"), "set_project_hull_vertices", "get_project_hull_vertices"); + + BIND_ENUM_CONSTANT(CONVEX_DECOMPOSITION_MODE_VOXEL); + BIND_ENUM_CONSTANT(CONVEX_DECOMPOSITION_MODE_TETRAHEDRON); +} + Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr; int Mesh::get_surface_count() const { @@ -355,8 +517,10 @@ Vector Mesh::get_surface_faces(int p_surface) const { Ref Mesh::create_convex_shape(bool p_clean, bool p_simplify) const { if (p_simplify) { - ConvexDecompositionSettings settings; - settings.max_convex_hulls = 1; + Ref settings = Ref(); + settings.instantiate(); + settings->set_max_convex_hulls(1); + settings->set_max_concavity(1.0); Vector> decomposed = convex_decompose(settings); if (decomposed.size() == 1) { return decomposed[0]; @@ -725,7 +889,7 @@ void Mesh::clear_cache() const { debug_lines.clear(); } -Vector> Mesh::convex_decompose(const ConvexDecompositionSettings &p_settings) const { +Vector> Mesh::convex_decompose(const Ref &p_settings) const { ERR_FAIL_COND_V(!convex_decomposition_function, Vector>()); Ref tm = generate_triangle_mesh(); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 1b870d996ae..4d9b9b40871 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -39,6 +39,7 @@ class ConcavePolygonShape3D; class ConvexPolygonShape3D; +class MeshConvexDecompositionSettings; class Shape3D; class Mesh : public Resource { @@ -178,42 +179,11 @@ public: Size2i get_lightmap_size_hint() const; void clear_cache() const; - struct ConvexDecompositionSettings { - enum Mode : int { - CONVEX_DECOMPOSITION_MODE_VOXEL = 0, - CONVEX_DECOMPOSITION_MODE_TETRAHEDRON - }; - - /// Maximum concavity. [Range: 0.0 -> 1.0] - real_t max_concavity = 1.0; - /// Controls the bias toward clipping along symmetry planes. [Range: 0.0 -> 1.0] - real_t symmetry_planes_clipping_bias = 0.05; - /// Controls the bias toward clipping along revolution axes. [Range: 0.0 -> 1.0] - real_t revolution_axes_clipping_bias = 0.05; - real_t min_volume_per_convex_hull = 0.0001; - /// Maximum number of voxels generated during the voxelization stage. - uint32_t resolution = 10'000; - uint32_t max_num_vertices_per_convex_hull = 32; - /// Controls the granularity of the search for the "best" clipping plane. - /// [Range: 1 -> 16] - uint32_t plane_downsampling = 4; - /// Controls the precision of the convex-hull generation process during the - /// clipping plane selection stage. - /// [Range: 1 -> 16] - uint32_t convexhull_downsampling = 4; - /// enable/disable normalizing the mesh before applying the convex decomposition. - bool normalize_mesh = false; - Mode mode = CONVEX_DECOMPOSITION_MODE_VOXEL; - bool convexhull_approximation = true; - /// This is the maximum number of convex hulls to produce from the merge operation. - uint32_t max_convex_hulls = 1; - bool project_hull_vertices = true; - }; - typedef Vector> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const ConvexDecompositionSettings &p_settings, Vector> *r_convex_indices); + typedef Vector> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Ref &p_settings, Vector> *r_convex_indices); static ConvexDecompositionFunc convex_decomposition_function; - Vector> convex_decompose(const ConvexDecompositionSettings &p_settings) const; + Vector> convex_decompose(const Ref &p_settings) const; Ref create_convex_shape(bool p_clean = true, bool p_simplify = false) const; Ref create_trimesh_shape() const; @@ -225,6 +195,89 @@ public: Mesh(); }; +class MeshConvexDecompositionSettings : public RefCounted { + GDCLASS(MeshConvexDecompositionSettings, RefCounted); + +public: + enum Mode : int { + CONVEX_DECOMPOSITION_MODE_VOXEL = 0, + CONVEX_DECOMPOSITION_MODE_TETRAHEDRON = 1 + }; + +private: + Mode mode = CONVEX_DECOMPOSITION_MODE_VOXEL; + + /// Maximum concavity. [Range: 0.0 -> 1.0] + real_t max_concavity = 1.0; + /// Controls the bias toward clipping along symmetry planes. [Range: 0.0 -> 1.0] + real_t symmetry_planes_clipping_bias = 0.05; + /// Controls the bias toward clipping along revolution axes. [Range: 0.0 -> 1.0] + real_t revolution_axes_clipping_bias = 0.05; + real_t min_volume_per_convex_hull = 0.0001; + /// Maximum number of voxels generated during the voxelization stage. + uint32_t resolution = 10'000; + uint32_t max_num_vertices_per_convex_hull = 32; + /// Controls the granularity of the search for the "best" clipping plane. + /// [Range: 1 -> 16] + uint32_t plane_downsampling = 4; + /// Controls the precision of the convex-hull generation process during the + /// clipping plane selection stage. + /// [Range: 1 -> 16] + uint32_t convex_hull_downsampling = 4; + /// enable/disable normalizing the mesh before applying the convex decomposition. + bool normalize_mesh = false; + + bool convex_hull_approximation = true; + /// This is the maximum number of convex hulls to produce from the merge operation. + uint32_t max_convex_hulls = 1; + bool project_hull_vertices = true; + +protected: + static void _bind_methods(); + +public: + void set_max_concavity(real_t p_max_concavity); + real_t get_max_concavity() const; + + void set_symmetry_planes_clipping_bias(real_t p_symmetry_planes_clipping_bias); + real_t get_symmetry_planes_clipping_bias() const; + + void set_revolution_axes_clipping_bias(real_t p_revolution_axes_clipping_bias); + real_t get_revolution_axes_clipping_bias() const; + + void set_min_volume_per_convex_hull(real_t p_min_volume_per_convex_hull); + real_t get_min_volume_per_convex_hull() const; + + void set_resolution(uint32_t p_resolution); + uint32_t get_resolution() const; + + void set_max_num_vertices_per_convex_hull(uint32_t p_max_num_vertices_per_convex_hull); + uint32_t get_max_num_vertices_per_convex_hull() const; + + void set_plane_downsampling(uint32_t p_plane_downsampling); + uint32_t get_plane_downsampling() const; + + void set_convex_hull_downsampling(uint32_t p_convex_hull_downsampling); + uint32_t get_convex_hull_downsampling() const; + + void set_normalize_mesh(bool p_normalize_mesh); + bool get_normalize_mesh() const; + + void set_mode(Mode p_mode); + Mode get_mode() const; + + void set_convex_hull_approximation(bool p_convex_hull_approximation); + bool get_convex_hull_approximation() const; + + void set_max_convex_hulls(uint32_t p_max_convex_hulls); + uint32_t get_max_convex_hulls() const; + + void set_project_hull_vertices(bool p_project_hull_vertices); + bool get_project_hull_vertices() const; +}; + +VARIANT_ENUM_CAST(MeshConvexDecompositionSettings::Mode); + class ArrayMesh : public Mesh { GDCLASS(ArrayMesh, Mesh); RES_BASE_EXTENSION("mesh");