Skip to content

Commit e13d8ed

Browse files
authored
Merge pull request #52266 from AndreaCatania/coll
2 parents 0f7fe55 + e3a06c3 commit e13d8ed

11 files changed

+494
-53
lines changed

editor/import/resource_importer_scene.cpp

+156-33
Large diffs are not rendered by default.

editor/import/resource_importer_scene.h

+198-4
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ class EditorSceneImporter : public RefCounted {
6363
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 4,
6464
IMPORT_GENERATE_TANGENT_ARRAYS = 8,
6565
IMPORT_USE_NAMED_SKIN_BINDS = 16,
66-
6766
};
6867

6968
virtual uint32_t get_import_flags() const;
@@ -125,9 +124,25 @@ class ResourceImporterScene : public ResourceImporter {
125124
MESH_OVERRIDE_DISABLE,
126125
};
127126

127+
enum BodyType {
128+
BODY_TYPE_STATIC,
129+
BODY_TYPE_DYNAMIC,
130+
BODY_TYPE_AREA
131+
};
132+
133+
enum ShapeType {
134+
SHAPE_TYPE_DECOMPOSE_CONVEX,
135+
SHAPE_TYPE_SIMPLE_CONVEX,
136+
SHAPE_TYPE_TRIMESH,
137+
SHAPE_TYPE_BOX,
138+
SHAPE_TYPE_SPHERE,
139+
SHAPE_TYPE_CYLINDER,
140+
SHAPE_TYPE_CAPSULE,
141+
};
142+
128143
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
129144
void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
130-
void _add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes);
145+
void _add_shapes(Node *p_node, const Vector<Ref<Shape3D>> &p_shapes);
131146

132147
public:
133148
static ResourceImporterScene *get_singleton() { return singleton; }
@@ -159,14 +174,15 @@ class ResourceImporterScene : public ResourceImporter {
159174

160175
void get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const;
161176
bool get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const;
177+
bool get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const;
162178

163179
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
164180
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
165181
// Import scenes *after* everything else (such as textures).
166182
virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; }
167183

168-
Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map);
169-
Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
184+
Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map);
185+
Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
170186

171187
Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
172188
void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
@@ -184,6 +200,12 @@ class ResourceImporterScene : public ResourceImporter {
184200
virtual bool can_import_threaded() const override { return false; }
185201

186202
ResourceImporterScene();
203+
204+
template <class M>
205+
static Vector<Ref<Shape3D>> get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options);
206+
207+
template <class M>
208+
static Transform3D get_collision_shapes_transform(const M &p_options);
187209
};
188210

189211
class EditorSceneImporterESCN : public EditorSceneImporter {
@@ -196,4 +218,176 @@ class EditorSceneImporterESCN : public EditorSceneImporter {
196218
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override;
197219
};
198220

221+
#include "scene/resources/box_shape_3d.h"
222+
#include "scene/resources/capsule_shape_3d.h"
223+
#include "scene/resources/cylinder_shape_3d.h"
224+
#include "scene/resources/sphere_shape_3d.h"
225+
226+
template <class M>
227+
Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options) {
228+
ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX;
229+
if (p_options.has(SNAME("physics/shape_type"))) {
230+
generate_shape_type = (ShapeType)p_options[SNAME("physics/shape_type")].operator int();
231+
}
232+
233+
if (generate_shape_type == SHAPE_TYPE_DECOMPOSE_CONVEX) {
234+
Mesh::ConvexDecompositionSettings decomposition_settings;
235+
bool advanced = false;
236+
if (p_options.has(SNAME("decomposition/advanced"))) {
237+
advanced = p_options[SNAME("decomposition/advanced")];
238+
}
239+
240+
if (advanced) {
241+
if (p_options.has(SNAME("decomposition/max_concavity"))) {
242+
decomposition_settings.max_concavity = p_options[SNAME("decomposition/max_concavity")];
243+
}
244+
245+
if (p_options.has(SNAME("decomposition/symmetry_planes_clipping_bias"))) {
246+
decomposition_settings.symmetry_planes_clipping_bias = p_options[SNAME("decomposition/symmetry_planes_clipping_bias")];
247+
}
248+
249+
if (p_options.has(SNAME("decomposition/revolution_axes_clipping_bias"))) {
250+
decomposition_settings.revolution_axes_clipping_bias = p_options[SNAME("decomposition/revolution_axes_clipping_bias")];
251+
}
252+
253+
if (p_options.has(SNAME("decomposition/min_volume_per_convex_hull"))) {
254+
decomposition_settings.min_volume_per_convex_hull = p_options[SNAME("decomposition/min_volume_per_convex_hull")];
255+
}
256+
257+
if (p_options.has(SNAME("decomposition/resolution"))) {
258+
decomposition_settings.resolution = p_options[SNAME("decomposition/resolution")];
259+
}
260+
261+
if (p_options.has(SNAME("decomposition/max_num_vertices_per_convex_hull"))) {
262+
decomposition_settings.max_num_vertices_per_convex_hull = p_options[SNAME("decomposition/max_num_vertices_per_convex_hull")];
263+
}
264+
265+
if (p_options.has(SNAME("decomposition/plane_downsampling"))) {
266+
decomposition_settings.plane_downsampling = p_options[SNAME("decomposition/plane_downsampling")];
267+
}
268+
269+
if (p_options.has(SNAME("decomposition/convexhull_downsampling"))) {
270+
decomposition_settings.convexhull_downsampling = p_options[SNAME("decomposition/convexhull_downsampling")];
271+
}
272+
273+
if (p_options.has(SNAME("decomposition/normalize_mesh"))) {
274+
decomposition_settings.normalize_mesh = p_options[SNAME("decomposition/normalize_mesh")];
275+
}
276+
277+
if (p_options.has(SNAME("decomposition/mode"))) {
278+
decomposition_settings.mode = (Mesh::ConvexDecompositionSettings::Mode)p_options[SNAME("decomposition/mode")].operator int();
279+
}
280+
281+
if (p_options.has(SNAME("decomposition/convexhull_approximation"))) {
282+
decomposition_settings.convexhull_approximation = p_options[SNAME("decomposition/convexhull_approximation")];
283+
}
284+
285+
if (p_options.has(SNAME("decomposition/max_convex_hulls"))) {
286+
decomposition_settings.max_convex_hulls = p_options[SNAME("decomposition/max_convex_hulls")];
287+
}
288+
289+
if (p_options.has(SNAME("decomposition/project_hull_vertices"))) {
290+
decomposition_settings.project_hull_vertices = p_options[SNAME("decomposition/project_hull_vertices")];
291+
}
292+
} else {
293+
int precision_level = 5;
294+
if (p_options.has(SNAME("decomposition/precision"))) {
295+
precision_level = p_options[SNAME("decomposition/precision")];
296+
}
297+
298+
const real_t precision = real_t(precision_level - 1) / 9.0;
299+
300+
decomposition_settings.max_concavity = Math::lerp(real_t(1.0), real_t(0.001), precision);
301+
decomposition_settings.min_volume_per_convex_hull = Math::lerp(real_t(0.01), real_t(0.0001), precision);
302+
decomposition_settings.resolution = Math::lerp(10'000, 100'000, precision);
303+
decomposition_settings.max_num_vertices_per_convex_hull = Math::lerp(32, 64, precision);
304+
decomposition_settings.plane_downsampling = Math::lerp(3, 16, precision);
305+
decomposition_settings.convexhull_downsampling = Math::lerp(3, 16, precision);
306+
decomposition_settings.max_convex_hulls = Math::lerp(1, 32, precision);
307+
}
308+
309+
return p_mesh->convex_decompose(decomposition_settings);
310+
} else if (generate_shape_type == SHAPE_TYPE_SIMPLE_CONVEX) {
311+
Vector<Ref<Shape3D>> shapes;
312+
shapes.push_back(p_mesh->create_convex_shape(true, /*Passing false, otherwise VHACD will be used to simplify (Decompose) the Mesh.*/ false));
313+
return shapes;
314+
} else if (generate_shape_type == SHAPE_TYPE_TRIMESH) {
315+
Vector<Ref<Shape3D>> shapes;
316+
shapes.push_back(p_mesh->create_trimesh_shape());
317+
return shapes;
318+
} else if (generate_shape_type == SHAPE_TYPE_BOX) {
319+
Ref<BoxShape3D> box;
320+
box.instantiate();
321+
if (p_options.has(SNAME("primitive/size"))) {
322+
box->set_size(p_options[SNAME("primitive/size")]);
323+
}
324+
325+
Vector<Ref<Shape3D>> shapes;
326+
shapes.push_back(box);
327+
return shapes;
328+
329+
} else if (generate_shape_type == SHAPE_TYPE_SPHERE) {
330+
Ref<SphereShape3D> sphere;
331+
sphere.instantiate();
332+
if (p_options.has(SNAME("primitive/radius"))) {
333+
sphere->set_radius(p_options[SNAME("primitive/radius")]);
334+
}
335+
336+
Vector<Ref<Shape3D>> shapes;
337+
shapes.push_back(sphere);
338+
return shapes;
339+
} else if (generate_shape_type == SHAPE_TYPE_CYLINDER) {
340+
Ref<CylinderShape3D> cylinder;
341+
cylinder.instantiate();
342+
if (p_options.has(SNAME("primitive/height"))) {
343+
cylinder->set_height(p_options[SNAME("primitive/height")]);
344+
}
345+
if (p_options.has(SNAME("primitive/radius"))) {
346+
cylinder->set_radius(p_options[SNAME("primitive/radius")]);
347+
}
348+
349+
Vector<Ref<Shape3D>> shapes;
350+
shapes.push_back(cylinder);
351+
return shapes;
352+
} else if (generate_shape_type == SHAPE_TYPE_CAPSULE) {
353+
Ref<CapsuleShape3D> capsule;
354+
capsule.instantiate();
355+
if (p_options.has(SNAME("primitive/height"))) {
356+
capsule->set_height(p_options[SNAME("primitive/height")]);
357+
}
358+
if (p_options.has(SNAME("primitive/radius"))) {
359+
capsule->set_radius(p_options[SNAME("primitive/radius")]);
360+
}
361+
362+
Vector<Ref<Shape3D>> shapes;
363+
shapes.push_back(capsule);
364+
return shapes;
365+
}
366+
return Vector<Ref<Shape3D>>();
367+
}
368+
369+
template <class M>
370+
Transform3D ResourceImporterScene::get_collision_shapes_transform(const M &p_options) {
371+
Transform3D transform;
372+
373+
ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX;
374+
if (p_options.has(SNAME("physics/shape_type"))) {
375+
generate_shape_type = (ShapeType)p_options[SNAME("physics/shape_type")].operator int();
376+
}
377+
378+
if (generate_shape_type == SHAPE_TYPE_BOX ||
379+
generate_shape_type == SHAPE_TYPE_SPHERE ||
380+
generate_shape_type == SHAPE_TYPE_CYLINDER ||
381+
generate_shape_type == SHAPE_TYPE_CAPSULE) {
382+
if (p_options.has(SNAME("primitive/position"))) {
383+
transform.origin = p_options[SNAME("primitive/position")];
384+
}
385+
386+
if (p_options.has(SNAME("primitive/rotation"))) {
387+
transform.basis.set_euler((p_options[SNAME("primitive/rotation")].operator Vector3() / 180.0) * Math_PI);
388+
}
389+
}
390+
return transform;
391+
}
392+
199393
#endif // RESOURCEIMPORTERSCENE_H

editor/import/scene_import_settings.cpp

+74
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class SceneImportSettingsData : public Object {
5353
}
5454

5555
current[p_name] = p_value;
56+
57+
if (ResourceImporterScene::get_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
58+
SceneImportSettings::get_singleton()->update_view();
59+
}
60+
5661
return true;
5762
}
5863
return false;
@@ -317,6 +322,13 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
317322
if (mesh_node && mesh_node->get_mesh().is_valid()) {
318323
_fill_mesh(scene_tree, mesh_node->get_mesh(), item);
319324

325+
// Add the collider view.
326+
MeshInstance3D *collider_view = memnew(MeshInstance3D);
327+
collider_view->set_name("collider_view");
328+
collider_view->set_visible(false);
329+
mesh_node->add_child(collider_view);
330+
collider_view->set_owner(mesh_node);
331+
320332
Transform3D accum_xform;
321333
Node3D *base = mesh_node;
322334
while (base) {
@@ -346,6 +358,54 @@ void SceneImportSettings::_update_scene() {
346358
_fill_scene(scene, nullptr);
347359
}
348360

361+
void SceneImportSettings::_update_view_gizmos() {
362+
for (const KeyValue<String, NodeData> &e : node_map) {
363+
bool generate_collider = false;
364+
if (e.value.settings.has(SNAME("generate/physics"))) {
365+
generate_collider = e.value.settings[SNAME("generate/physics")];
366+
}
367+
368+
MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(e.value.node);
369+
if (mesh_node == nullptr || mesh_node->get_mesh().is_null()) {
370+
// Nothing to do
371+
continue;
372+
}
373+
374+
MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(mesh_node->find_node("collider_view"));
375+
CRASH_COND_MSG(collider_view == nullptr, "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`.");
376+
377+
collider_view->set_visible(generate_collider);
378+
if (generate_collider) {
379+
// This collider_view doesn't have a mesh so we need to generate a new one.
380+
381+
// Generate the mesh collider.
382+
Vector<Ref<Shape3D>> shapes = ResourceImporterScene::get_collision_shapes(mesh_node->get_mesh(), e.value.settings);
383+
const Transform3D transform = ResourceImporterScene::get_collision_shapes_transform(e.value.settings);
384+
385+
Ref<ArrayMesh> collider_view_mesh;
386+
collider_view_mesh.instantiate();
387+
for (Ref<Shape3D> shape : shapes) {
388+
Ref<ArrayMesh> debug_shape_mesh;
389+
if (shape.is_valid()) {
390+
debug_shape_mesh = shape->get_debug_mesh();
391+
}
392+
if (debug_shape_mesh.is_valid()) {
393+
collider_view_mesh->add_surface_from_arrays(
394+
debug_shape_mesh->surface_get_primitive_type(0),
395+
debug_shape_mesh->surface_get_arrays(0));
396+
397+
collider_view_mesh->surface_set_material(
398+
collider_view_mesh->get_surface_count() - 1,
399+
collider_mat);
400+
}
401+
}
402+
403+
collider_view->set_mesh(collider_view_mesh);
404+
collider_view->set_transform(transform);
405+
}
406+
}
407+
}
408+
349409
void SceneImportSettings::_update_camera() {
350410
AABB camera_aabb;
351411

@@ -404,11 +464,16 @@ void SceneImportSettings::_load_default_subresource_settings(Map<StringName, Var
404464
}
405465
}
406466

467+
void SceneImportSettings::update_view() {
468+
_update_view_gizmos();
469+
}
470+
407471
void SceneImportSettings::open_settings(const String &p_path) {
408472
if (scene) {
409473
memdelete(scene);
410474
scene = nullptr;
411475
}
476+
scene_import_settings_data->settings = nullptr;
412477
scene = ResourceImporterScene::get_singleton()->pre_import(p_path);
413478
if (scene == nullptr) {
414479
EditorNode::get_singleton()->show_warning(TTR("Error opening scene"));
@@ -463,6 +528,7 @@ void SceneImportSettings::open_settings(const String &p_path) {
463528
}
464529

465530
popup_centered_ratio();
531+
_update_view_gizmos();
466532
_update_camera();
467533

468534
set_title(vformat(TTR("Advanced Import Settings for '%s'"), base_path.get_file()));
@@ -629,6 +695,7 @@ void SceneImportSettings::_material_tree_selected() {
629695

630696
_select(material_tree, type, import_id);
631697
}
698+
632699
void SceneImportSettings::_mesh_tree_selected() {
633700
if (selecting) {
634701
return;
@@ -640,6 +707,7 @@ void SceneImportSettings::_mesh_tree_selected() {
640707

641708
_select(mesh_tree, type, import_id);
642709
}
710+
643711
void SceneImportSettings::_scene_tree_selected() {
644712
if (selecting) {
645713
return;
@@ -1144,6 +1212,12 @@ SceneImportSettings::SceneImportSettings() {
11441212
material_preview.instantiate();
11451213
}
11461214

1215+
{
1216+
collider_mat.instantiate();
1217+
collider_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
1218+
collider_mat->set_albedo(Color(0.5, 0.5, 1.0));
1219+
}
1220+
11471221
inspector = memnew(EditorInspector);
11481222
inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
11491223

0 commit comments

Comments
 (0)