From 51a4fe1d530be9894e56db20a271773eb63053b2 Mon Sep 17 00:00:00 2001 From: Lyuma Date: Thu, 23 Feb 2023 11:07:48 +0100 Subject: [PATCH] import: Fix uv2 by avoiding premature ImporterMesh::get_mesh() Implements create_convex_shape in ImpoterMesh. Note: ImporterMeshInstance3D::get_mesh() is safe. The only dangerous function with side effects is ImpoterMesh::get_mesh() --- editor/import/resource_importer_scene.cpp | 5 ++- editor/import/resource_importer_scene.h | 6 ++-- editor/import/scene_import_settings.cpp | 38 ++++++++++++++++++++++- scene/resources/importer_mesh.cpp | 38 +++++++++++++++++++++++ scene/resources/importer_mesh.h | 1 + 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 32c16255dd18..f24759ace6d4 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -353,13 +353,12 @@ static String _fixstr(const String &p_what, const String &p_str) { static void _pre_gen_shape_list(Ref &mesh, Vector> &r_shape_list, bool p_convex) { ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value"); - ERR_FAIL_NULL_MSG(mesh->get_mesh(), "Cannot generate shape list with null mesh value"); if (!p_convex) { Ref shape = mesh->create_trimesh_shape(); r_shape_list.push_back(shape); } else { Vector> cd; - cd.push_back(mesh->get_mesh()->create_convex_shape(true, /*Passing false, otherwise VHACD will be used to simplify (Decompose) the Mesh.*/ false)); + cd.push_back(mesh->create_convex_shape(true, /*Passing false, otherwise VHACD will be used to simplify (Decompose) the Mesh.*/ false)); if (cd.size()) { for (int i = 0; i < cd.size(); i++) { r_shape_list.push_back(cd[i]); @@ -1230,7 +1229,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< shapes = collision_map[m]; } else { shapes = get_collision_shapes( - m->get_mesh(), + m, node_settings, p_applied_root_scale); } diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index d6d83a45d351..7a1fd72f6860 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -39,6 +39,7 @@ #include "scene/resources/box_shape_3d.h" #include "scene/resources/capsule_shape_3d.h" #include "scene/resources/cylinder_shape_3d.h" +#include "scene/resources/importer_mesh.h" #include "scene/resources/mesh.h" #include "scene/resources/shape_3d.h" #include "scene/resources/sphere_shape_3d.h" @@ -298,7 +299,7 @@ class ResourceImporterScene : public ResourceImporter { ResourceImporterScene(bool p_animation_import = false); template - static Vector> get_collision_shapes(const Ref &p_mesh, const M &p_options, float p_applied_root_scale); + static Vector> get_collision_shapes(const Ref &p_mesh, const M &p_options, float p_applied_root_scale); template static Transform3D get_collision_shapes_transform(const M &p_options); @@ -314,7 +315,8 @@ class EditorSceneFormatImporterESCN : public EditorSceneFormatImporter { }; template -Vector> ResourceImporterScene::get_collision_shapes(const Ref &p_mesh, const M &p_options, float p_applied_root_scale) { +Vector> ResourceImporterScene::get_collision_shapes(const Ref &p_mesh, const M &p_options, float p_applied_root_scale) { + ERR_FAIL_COND_V(p_mesh.is_null(), Vector>()); ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX; if (p_options.has(SNAME("physics/shape_type"))) { generate_shape_type = (ShapeType)p_options[SNAME("physics/shape_type")].operator int(); diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 348aad1162df..a09e0e740804 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -444,9 +444,45 @@ void SceneImportSettings::_update_view_gizmos() { collider_view->set_visible(show_collider_view); if (generate_collider) { // This collider_view doesn't have a mesh so we need to generate a new one. + Ref mesh; + mesh.instantiate(); + // ResourceImporterScene::get_collision_shapes() expects ImporterMesh, not Mesh. + // TODO: Duplicate code with EditorSceneFormatImporterESCN::import_scene() + // Consider making a utility function to convert from Mesh to ImporterMesh. + Ref mesh_3d_mesh = mesh_node->get_mesh(); + Ref array_mesh_3d_mesh = mesh_3d_mesh; + if (array_mesh_3d_mesh.is_valid()) { + // For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially. + mesh->set_name(array_mesh_3d_mesh->get_name()); + for (int32_t blend_i = 0; blend_i < array_mesh_3d_mesh->get_blend_shape_count(); blend_i++) { + mesh->add_blend_shape(array_mesh_3d_mesh->get_blend_shape_name(blend_i)); + } + for (int32_t surface_i = 0; surface_i < array_mesh_3d_mesh->get_surface_count(); surface_i++) { + mesh->add_surface(array_mesh_3d_mesh->surface_get_primitive_type(surface_i), + array_mesh_3d_mesh->surface_get_arrays(surface_i), + array_mesh_3d_mesh->surface_get_blend_shape_arrays(surface_i), + array_mesh_3d_mesh->surface_get_lods(surface_i), + array_mesh_3d_mesh->surface_get_material(surface_i), + array_mesh_3d_mesh->surface_get_name(surface_i), + array_mesh_3d_mesh->surface_get_format(surface_i)); + } + mesh->set_blend_shape_mode(array_mesh_3d_mesh->get_blend_shape_mode()); + } else if (mesh_3d_mesh.is_valid()) { + // For the MeshInstance3D nodes, we need to convert the Mesh to an ImporterMesh specially. + mesh->set_name(mesh_3d_mesh->get_name()); + for (int32_t surface_i = 0; surface_i < mesh_3d_mesh->get_surface_count(); surface_i++) { + mesh->add_surface(mesh_3d_mesh->surface_get_primitive_type(surface_i), + mesh_3d_mesh->surface_get_arrays(surface_i), + Array(), + mesh_3d_mesh->surface_get_lods(surface_i), + mesh_3d_mesh->surface_get_material(surface_i), + mesh_3d_mesh->surface_get_material(surface_i).is_valid() ? mesh_3d_mesh->surface_get_material(surface_i)->get_name() : String(), + mesh_3d_mesh->surface_get_format(surface_i)); + } + } // Generate the mesh collider. - Vector> shapes = ResourceImporterScene::get_collision_shapes(mesh_node->get_mesh(), e.value.settings, 1.0); + Vector> shapes = ResourceImporterScene::get_collision_shapes(mesh, e.value.settings, 1.0); const Transform3D transform = ResourceImporterScene::get_collision_shapes_transform(e.value.settings); Ref collider_view_mesh; diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 672581bbe25d..0fc72ca90f61 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -31,6 +31,7 @@ #include "importer_mesh.h" #include "core/io/marshalls.h" +#include "core/math/convex_hull.h" #include "core/math/random_pcg.h" #include "core/math/static_raycaster.h" #include "scene/resources/surface_tool.h" @@ -984,6 +985,43 @@ Vector> ImporterMesh::convex_decompose(const Mesh::ConvexDecomposit return ret; } +Ref ImporterMesh::create_convex_shape(bool p_clean, bool p_simplify) const { + if (p_simplify) { + Mesh::ConvexDecompositionSettings settings; + settings.max_convex_hulls = 1; + Vector> decomposed = convex_decompose(settings); + if (decomposed.size() == 1) { + return decomposed[0]; + } else { + ERR_PRINT("Convex shape simplification failed, falling back to simpler process."); + } + } + + Vector vertices; + for (int i = 0; i < get_surface_count(); i++) { + Array a = get_surface_arrays(i); + ERR_FAIL_COND_V(a.is_empty(), Ref()); + Vector v = a[Mesh::ARRAY_VERTEX]; + vertices.append_array(v); + } + + Ref shape = memnew(ConvexPolygonShape3D); + + if (p_clean) { + Geometry3D::MeshData md; + Error err = ConvexHullComputer::convex_hull(vertices, md); + if (err == OK) { + shape->set_points(md.vertices); + return shape; + } else { + ERR_PRINT("Convex shape cleaning failed, falling back to simpler process."); + } + } + + shape->set_points(vertices); + return shape; +} + Ref ImporterMesh::create_trimesh_shape() const { Vector faces = get_faces(); if (faces.size() == 0) { diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h index 900a8851c01d..33d08643428a 100644 --- a/scene/resources/importer_mesh.h +++ b/scene/resources/importer_mesh.h @@ -119,6 +119,7 @@ class ImporterMesh : public Resource { Vector get_faces() const; Vector> convex_decompose(const Mesh::ConvexDecompositionSettings &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(); Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector &p_src_cache, Vector &r_dst_cache);