Add Mesh ConvexDecompositionSettings wrapper

Adds wrapper MeshConvexDecompositionSettings to control parameters for Mesh ConvexDecomposition operations.
This commit is contained in:
smix8 2023-01-26 16:10:26 +01:00
parent f38b540273
commit 1549aeaef8
13 changed files with 390 additions and 98 deletions

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MeshConvexDecompositionSettings" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Parameters to be used with a [Mesh] convex decomposition operation.
</brief_description>
<description>
Parameters to be used with a [Mesh] convex decomposition operation.
</description>
<tutorials>
</tutorials>
<members>
<member name="convex_hull_approximation" type="bool" setter="set_convex_hull_approximation" getter="get_convex_hull_approximation" default="true">
If enabled uses approximation for computing convex hulls.
</member>
<member name="convex_hull_downsampling" type="int" setter="set_convex_hull_downsampling" getter="get_convex_hull_downsampling" default="4">
Controls the precision of the convex-hull generation process during the clipping plane selection stage. Ranges from [code]1[/code] to [code]16[/code].
</member>
<member name="max_concavity" type="float" setter="set_max_concavity" getter="get_max_concavity" default="1.0">
Maximum concavity. Ranges from [code]0.0[/code] to [code]1.0[/code].
</member>
<member name="max_convex_hulls" type="int" setter="set_max_convex_hulls" getter="get_max_convex_hulls" default="1">
The maximum number of convex hulls to produce from the merge operation.
</member>
<member name="max_num_vertices_per_convex_hull" type="int" setter="set_max_num_vertices_per_convex_hull" getter="get_max_num_vertices_per_convex_hull" default="32">
Controls the maximum number of triangles per convex-hull. Ranges from [code]4[/code] to [code]1024[/code].
</member>
<member name="min_volume_per_convex_hull" type="float" setter="set_min_volume_per_convex_hull" getter="get_min_volume_per_convex_hull" default="0.0001">
Controls the adaptive sampling of the generated convex-hulls. Ranges from [code]0.0[/code] to [code]0.01[/code].
</member>
<member name="mode" type="int" setter="set_mode" getter="get_mode" enum="MeshConvexDecompositionSettings.Mode" default="0">
Mode for the approximate convex decomposition.
</member>
<member name="normalize_mesh" type="bool" setter="set_normalize_mesh" getter="get_normalize_mesh" default="false">
If enabled normalizes the mesh before applying the convex decomposition.
</member>
<member name="plane_downsampling" type="int" setter="set_plane_downsampling" getter="get_plane_downsampling" default="4">
Controls the granularity of the search for the "best" clipping plane. Ranges from [code]1[/code] to [code]16[/code].
</member>
<member name="project_hull_vertices" type="bool" setter="set_project_hull_vertices" getter="get_project_hull_vertices" default="true">
If enabled projects output convex hull vertices onto original source mesh to increase floating point accuracy of the results.
</member>
<member name="resolution" type="int" setter="set_resolution" getter="get_resolution" default="10000">
Maximum number of voxels generated during the voxelization stage.
</member>
<member name="revolution_axes_clipping_bias" type="float" setter="set_revolution_axes_clipping_bias" getter="get_revolution_axes_clipping_bias" default="0.05">
Controls the bias toward clipping along revolution axes. Ranges from [code]0.0[/code] to [code]1.0[/code].
</member>
<member name="symmetry_planes_clipping_bias" type="float" setter="set_symmetry_planes_clipping_bias" getter="get_symmetry_planes_clipping_bias" default="0.05">
Controls the bias toward clipping along symmetry planes. Ranges from [code]0.0[/code] to [code]1.0[/code].
</member>
</members>
<constants>
<constant name="CONVEX_DECOMPOSITION_MODE_VOXEL" value="0" enum="Mode">
Constant for voxel-based approximate convex decomposition.
</constant>
<constant name="CONVEX_DECOMPOSITION_MODE_TETRAHEDRON" value="1" enum="Mode">
Constant for tetrahedron-based approximate convex decomposition.
</constant>
</constants>
</class>

View File

@ -31,8 +31,9 @@
</method>
<method name="create_multiple_convex_collisions">
<return type="void" />
<param index="0" name="settings" type="MeshConvexDecompositionSettings" default="null" />
<description>
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].
</description>
</method>
<method name="create_trimesh_collision">

View File

@ -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<MeshConvexDecompositionSettings> decomposition_default = Ref<MeshConvexDecompositionSettings>();
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<int>(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<int>(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)));

View File

@ -323,7 +323,8 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Impor
}
if (generate_shape_type == SHAPE_TYPE_DECOMPOSE_CONVEX) {
Mesh::ConvexDecompositionSettings decomposition_settings;
Ref<MeshConvexDecompositionSettings> decomposition_settings = Ref<MeshConvexDecompositionSettings>();
decomposition_settings.instantiate();
bool advanced = false;
if (p_options.has(SNAME("decomposition/advanced"))) {
advanced = p_options[SNAME("decomposition/advanced")];
@ -331,55 +332,55 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Impor
if (advanced) {
if (p_options.has(SNAME("decomposition/max_concavity"))) {
decomposition_settings.max_concavity = p_options[SNAME("decomposition/max_concavity")];
decomposition_settings->set_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<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Impor
const real_t precision = real_t(precision_level - 1) / 9.0;
decomposition_settings.max_concavity = Math::lerp(real_t(1.0), real_t(0.001), precision);
decomposition_settings.min_volume_per_convex_hull = Math::lerp(real_t(0.01), real_t(0.0001), precision);
decomposition_settings.resolution = Math::lerp(10'000, 100'000, precision);
decomposition_settings.max_num_vertices_per_convex_hull = Math::lerp(32, 64, precision);
decomposition_settings.plane_downsampling = Math::lerp(3, 16, precision);
decomposition_settings.convexhull_downsampling = Math::lerp(3, 16, precision);
decomposition_settings.max_convex_hulls = Math::lerp(1, 32, precision);
decomposition_settings->set_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);

View File

@ -214,7 +214,11 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
return;
}
Mesh::ConvexDecompositionSettings settings;
Ref<MeshConvexDecompositionSettings> settings = Ref<MeshConvexDecompositionSettings>();
settings.instantiate();
settings->set_max_convex_hulls(32);
settings->set_max_concavity(0.001);
Vector<Ref<Shape3D>> shapes = mesh->convex_decompose(settings);
if (!shapes.size()) {

View File

@ -32,22 +32,22 @@
#include "scene/resources/mesh.h"
#include "thirdparty/vhacd/public/VHACD.h"
static Vector<Vector<Vector3>> 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<Vector<uint32_t>> *r_convex_indices) {
static Vector<Vector<Vector3>> convex_decompose(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Ref<MeshConvexDecompositionSettings> &p_settings, Vector<Vector<uint32_t>> *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);

View File

@ -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<MeshConvexDecompositionSettings> &p_settings) {
if (mesh.is_null()) {
return nullptr;
}
Mesh::ConvexDecompositionSettings settings;
Ref<MeshConvexDecompositionSettings> settings;
if (p_settings.is_valid()) {
settings = p_settings;
} else {
settings.instantiate();
}
Vector<Ref<Shape3D>> 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<StaticBody3D>(create_multiple_convex_collisions_node());
void MeshInstance3D::create_multiple_convex_collisions(const Ref<MeshConvexDecompositionSettings> &p_settings) {
StaticBody3D *static_body = Object::cast_to<StaticBody3D>(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<MeshConvexDecompositionSettings>()));
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);

View File

@ -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<MeshConvexDecompositionSettings> &p_settings = Ref<MeshConvexDecompositionSettings>());
void create_multiple_convex_collisions(const Ref<MeshConvexDecompositionSettings> &p_settings = Ref<MeshConvexDecompositionSettings>());
MeshInstance3D *create_debug_tangents_node();
void create_debug_tangents();

View File

@ -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);

View File

@ -938,7 +938,7 @@ Vector<Face3> ImporterMesh::get_faces() const {
return faces;
}
Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const {
Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Ref<MeshConvexDecompositionSettings> &p_settings) const {
ERR_FAIL_COND_V(!Mesh::convex_decomposition_function, Vector<Ref<Shape3D>>());
const Vector<Face3> faces = get_faces();
@ -987,8 +987,9 @@ Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Mesh::ConvexDecomposit
Ref<ConvexPolygonShape3D> ImporterMesh::create_convex_shape(bool p_clean, bool p_simplify) const {
if (p_simplify) {
Mesh::ConvexDecompositionSettings settings;
settings.max_convex_hulls = 1;
Ref<MeshConvexDecompositionSettings> settings;
settings.instantiate();
settings->set_max_convex_hulls(1);
Vector<Ref<Shape3D>> decomposed = convex_decompose(settings);
if (decomposed.size() == 1) {
return decomposed[0];

View File

@ -118,7 +118,7 @@ public:
Ref<ImporterMesh> get_shadow_mesh() const;
Vector<Face3> get_faces() const;
Vector<Ref<Shape3D>> convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const;
Vector<Ref<Shape3D>> convex_decompose(const Ref<MeshConvexDecompositionSettings> &p_settings) const;
Ref<ConvexPolygonShape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
Ref<ConcavePolygonShape3D> create_trimesh_shape() const;
Ref<NavigationMesh> create_navigation_mesh();

View File

@ -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<Face3> Mesh::get_surface_faces(int p_surface) const {
Ref<ConvexPolygonShape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
if (p_simplify) {
ConvexDecompositionSettings settings;
settings.max_convex_hulls = 1;
Ref<MeshConvexDecompositionSettings> settings = Ref<MeshConvexDecompositionSettings>();
settings.instantiate();
settings->set_max_convex_hulls(1);
settings->set_max_concavity(1.0);
Vector<Ref<Shape3D>> decomposed = convex_decompose(settings);
if (decomposed.size() == 1) {
return decomposed[0];
@ -725,7 +889,7 @@ void Mesh::clear_cache() const {
debug_lines.clear();
}
Vector<Ref<Shape3D>> Mesh::convex_decompose(const ConvexDecompositionSettings &p_settings) const {
Vector<Ref<Shape3D>> Mesh::convex_decompose(const Ref<MeshConvexDecompositionSettings> &p_settings) const {
ERR_FAIL_COND_V(!convex_decomposition_function, Vector<Ref<Shape3D>>());
Ref<TriangleMesh> tm = generate_triangle_mesh();

View File

@ -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<Vector<Vector3>> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const ConvexDecompositionSettings &p_settings, Vector<Vector<uint32_t>> *r_convex_indices);
typedef Vector<Vector<Vector3>> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Ref<MeshConvexDecompositionSettings> &p_settings, Vector<Vector<uint32_t>> *r_convex_indices);
static ConvexDecompositionFunc convex_decomposition_function;
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
Vector<Ref<Shape3D>> convex_decompose(const Ref<MeshConvexDecompositionSettings> &p_settings) const;
Ref<ConvexPolygonShape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
Ref<ConcavePolygonShape3D> 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");