1 | /**************************************************************************/ |
2 | /* resource_importer_scene.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #ifndef RESOURCE_IMPORTER_SCENE_H |
32 | #define RESOURCE_IMPORTER_SCENE_H |
33 | |
34 | #include "core/error/error_macros.h" |
35 | #include "core/io/resource_importer.h" |
36 | #include "core/variant/dictionary.h" |
37 | #include "scene/3d/importer_mesh_instance_3d.h" |
38 | #include "scene/resources/animation.h" |
39 | #include "scene/resources/box_shape_3d.h" |
40 | #include "scene/resources/capsule_shape_3d.h" |
41 | #include "scene/resources/cylinder_shape_3d.h" |
42 | #include "scene/resources/importer_mesh.h" |
43 | #include "scene/resources/mesh.h" |
44 | #include "scene/resources/shape_3d.h" |
45 | #include "scene/resources/sphere_shape_3d.h" |
46 | |
47 | class Material; |
48 | class AnimationPlayer; |
49 | |
50 | class ImporterMesh; |
51 | class EditorSceneFormatImporter : public RefCounted { |
52 | GDCLASS(EditorSceneFormatImporter, RefCounted); |
53 | |
54 | protected: |
55 | static void _bind_methods(); |
56 | |
57 | Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); |
58 | Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); |
59 | |
60 | GDVIRTUAL0RC(uint32_t, _get_import_flags) |
61 | GDVIRTUAL0RC(Vector<String>, _get_extensions) |
62 | GDVIRTUAL3R(Object *, _import_scene, String, uint32_t, Dictionary) |
63 | GDVIRTUAL1(_get_import_options, String) |
64 | GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String) |
65 | |
66 | public: |
67 | enum ImportFlags { |
68 | IMPORT_SCENE = 1, |
69 | IMPORT_ANIMATION = 2, |
70 | IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 4, |
71 | IMPORT_GENERATE_TANGENT_ARRAYS = 8, |
72 | IMPORT_USE_NAMED_SKIN_BINDS = 16, |
73 | IMPORT_DISCARD_MESHES_AND_MATERIALS = 32, //used for optimizing animation import |
74 | }; |
75 | |
76 | virtual uint32_t get_import_flags() const; |
77 | virtual void get_extensions(List<String> *r_extensions) const; |
78 | virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr); |
79 | virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options); |
80 | virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options); |
81 | |
82 | EditorSceneFormatImporter() {} |
83 | }; |
84 | |
85 | class EditorScenePostImport : public RefCounted { |
86 | GDCLASS(EditorScenePostImport, RefCounted); |
87 | |
88 | String source_file; |
89 | |
90 | protected: |
91 | static void _bind_methods(); |
92 | |
93 | GDVIRTUAL1R(Object *, _post_import, Node *) |
94 | |
95 | public: |
96 | String get_source_file() const; |
97 | virtual Node *post_import(Node *p_scene); |
98 | virtual void init(const String &p_source_file); |
99 | EditorScenePostImport(); |
100 | }; |
101 | |
102 | class EditorScenePostImportPlugin : public RefCounted { |
103 | GDCLASS(EditorScenePostImportPlugin, RefCounted); |
104 | |
105 | public: |
106 | enum InternalImportCategory { |
107 | INTERNAL_IMPORT_CATEGORY_NODE, |
108 | INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE, |
109 | INTERNAL_IMPORT_CATEGORY_MESH, |
110 | INTERNAL_IMPORT_CATEGORY_MATERIAL, |
111 | INTERNAL_IMPORT_CATEGORY_ANIMATION, |
112 | INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, |
113 | INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE, |
114 | INTERNAL_IMPORT_CATEGORY_MAX |
115 | }; |
116 | |
117 | private: |
118 | mutable const HashMap<StringName, Variant> *current_options = nullptr; |
119 | mutable const Dictionary *current_options_dict = nullptr; |
120 | List<ResourceImporter::ImportOption> *current_option_list = nullptr; |
121 | InternalImportCategory current_category = INTERNAL_IMPORT_CATEGORY_MAX; |
122 | |
123 | protected: |
124 | GDVIRTUAL1(_get_internal_import_options, int) |
125 | GDVIRTUAL3RC(Variant, _get_internal_option_visibility, int, bool, String) |
126 | GDVIRTUAL2RC(Variant, _get_internal_option_update_view_required, int, String) |
127 | GDVIRTUAL4(_internal_process, int, Node *, Node *, Ref<Resource>) |
128 | GDVIRTUAL1(_get_import_options, String) |
129 | GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String) |
130 | GDVIRTUAL1(_pre_process, Node *) |
131 | GDVIRTUAL1(_post_process, Node *) |
132 | |
133 | static void _bind_methods(); |
134 | |
135 | public: |
136 | Variant get_option_value(const StringName &p_name) const; |
137 | void add_import_option(const String &p_name, Variant p_default_value); |
138 | void add_import_option_advanced(Variant::Type p_type, const String &p_name, Variant p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT); |
139 | |
140 | virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options); |
141 | virtual Variant get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const; |
142 | virtual Variant get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const; |
143 | |
144 | virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options); |
145 | |
146 | virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options); |
147 | virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const; |
148 | |
149 | virtual void pre_process(Node *p_scene, const HashMap<StringName, Variant> &p_options); |
150 | virtual void post_process(Node *p_scene, const HashMap<StringName, Variant> &p_options); |
151 | |
152 | EditorScenePostImportPlugin() {} |
153 | }; |
154 | |
155 | VARIANT_ENUM_CAST(EditorScenePostImportPlugin::InternalImportCategory) |
156 | |
157 | class ResourceImporterScene : public ResourceImporter { |
158 | GDCLASS(ResourceImporterScene, ResourceImporter); |
159 | |
160 | static Vector<Ref<EditorSceneFormatImporter>> importers; |
161 | static Vector<Ref<EditorScenePostImportPlugin>> post_importer_plugins; |
162 | |
163 | static ResourceImporterScene *scene_singleton; |
164 | static ResourceImporterScene *animation_singleton; |
165 | |
166 | enum LightBakeMode { |
167 | LIGHT_BAKE_DISABLED, |
168 | LIGHT_BAKE_STATIC, |
169 | LIGHT_BAKE_STATIC_LIGHTMAPS, |
170 | LIGHT_BAKE_DYNAMIC, |
171 | }; |
172 | |
173 | enum MeshPhysicsMode { |
174 | MESH_PHYSICS_DISABLED, |
175 | MESH_PHYSICS_MESH_AND_STATIC_COLLIDER, |
176 | MESH_PHYSICS_RIGID_BODY_AND_MESH, |
177 | MESH_PHYSICS_STATIC_COLLIDER_ONLY, |
178 | MESH_PHYSICS_AREA_ONLY, |
179 | }; |
180 | |
181 | enum NavMeshMode { |
182 | NAVMESH_DISABLED, |
183 | NAVMESH_MESH_AND_NAVMESH, |
184 | NAVMESH_NAVMESH_ONLY, |
185 | }; |
186 | |
187 | enum OccluderMode { |
188 | OCCLUDER_DISABLED, |
189 | OCCLUDER_MESH_AND_OCCLUDER, |
190 | OCCLUDER_OCCLUDER_ONLY, |
191 | }; |
192 | |
193 | enum MeshOverride { |
194 | MESH_OVERRIDE_DEFAULT, |
195 | MESH_OVERRIDE_ENABLE, |
196 | MESH_OVERRIDE_DISABLE, |
197 | }; |
198 | |
199 | enum BodyType { |
200 | BODY_TYPE_STATIC, |
201 | BODY_TYPE_DYNAMIC, |
202 | BODY_TYPE_AREA |
203 | }; |
204 | |
205 | enum ShapeType { |
206 | SHAPE_TYPE_DECOMPOSE_CONVEX, |
207 | SHAPE_TYPE_SIMPLE_CONVEX, |
208 | SHAPE_TYPE_TRIMESH, |
209 | SHAPE_TYPE_BOX, |
210 | SHAPE_TYPE_SPHERE, |
211 | SHAPE_TYPE_CYLINDER, |
212 | SHAPE_TYPE_CAPSULE, |
213 | }; |
214 | |
215 | Array _get_skinned_pose_transforms(ImporterMeshInstance3D *p_src_mesh_node); |
216 | void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner); |
217 | 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); |
218 | void _add_shapes(Node *p_node, const Vector<Ref<Shape3D>> &p_shapes); |
219 | |
220 | enum AnimationImportTracks { |
221 | ANIMATION_IMPORT_TRACKS_IF_PRESENT, |
222 | ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL, |
223 | ANIMATION_IMPORT_TRACKS_NEVER, |
224 | }; |
225 | enum TrackChannel { |
226 | TRACK_CHANNEL_POSITION, |
227 | TRACK_CHANNEL_ROTATION, |
228 | TRACK_CHANNEL_SCALE, |
229 | TRACK_CHANNEL_BLEND_SHAPE, |
230 | TRACK_CHANNEL_MAX |
231 | }; |
232 | |
233 | void _optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions); |
234 | |
235 | bool animation_importer = false; |
236 | |
237 | public: |
238 | static ResourceImporterScene *get_scene_singleton() { return scene_singleton; } |
239 | static ResourceImporterScene *get_animation_singleton() { return animation_singleton; } |
240 | |
241 | static void add_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority = false); |
242 | static void remove_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin); |
243 | |
244 | const Vector<Ref<EditorSceneFormatImporter>> &get_importers() const { return importers; } |
245 | |
246 | static void add_importer(Ref<EditorSceneFormatImporter> p_importer, bool p_first_priority = false); |
247 | static void remove_importer(Ref<EditorSceneFormatImporter> p_importer); |
248 | |
249 | static void clean_up_importer_plugins(); |
250 | |
251 | virtual String get_importer_name() const override; |
252 | virtual String get_visible_name() const override; |
253 | virtual void get_recognized_extensions(List<String> *p_extensions) const override; |
254 | virtual String get_save_extension() const override; |
255 | virtual String get_resource_type() const override; |
256 | virtual int get_format_version() const override; |
257 | |
258 | virtual int get_preset_count() const override; |
259 | virtual String get_preset_name(int p_idx) const override; |
260 | |
261 | enum InternalImportCategory { |
262 | INTERNAL_IMPORT_CATEGORY_NODE = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_NODE, |
263 | INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE, |
264 | INTERNAL_IMPORT_CATEGORY_MESH = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MESH, |
265 | INTERNAL_IMPORT_CATEGORY_MATERIAL = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MATERIAL, |
266 | INTERNAL_IMPORT_CATEGORY_ANIMATION = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION, |
267 | INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, |
268 | INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE, |
269 | INTERNAL_IMPORT_CATEGORY_MAX = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MAX |
270 | }; |
271 | |
272 | void get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const; |
273 | bool get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const; |
274 | bool get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const; |
275 | |
276 | virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override; |
277 | virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; |
278 | // Import scenes *after* everything else (such as textures). |
279 | virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; } |
280 | |
281 | Node *_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames); |
282 | Node *_pre_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps); |
283 | Node *_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale); |
284 | Node *_post_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps); |
285 | |
286 | Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks); |
287 | void _create_slices(AnimationPlayer *ap, Ref<Animation> anim, const Array &p_clips, bool p_bake_all); |
288 | void _optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error); |
289 | void _compress_animations(AnimationPlayer *anim, int p_page_size_kb); |
290 | |
291 | Node *pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options); |
292 | virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; |
293 | |
294 | virtual bool has_advanced_options() const override; |
295 | virtual void show_advanced_options(const String &p_path) override; |
296 | |
297 | virtual bool can_import_threaded() const override { return false; } |
298 | |
299 | ResourceImporterScene(bool p_animation_import = false, bool p_singleton = false); |
300 | ~ResourceImporterScene(); |
301 | |
302 | template <class M> |
303 | static Vector<Ref<Shape3D>> get_collision_shapes(const Ref<ImporterMesh> &p_mesh, const M &p_options, float p_applied_root_scale); |
304 | |
305 | template <class M> |
306 | static Transform3D get_collision_shapes_transform(const M &p_options); |
307 | }; |
308 | |
309 | class EditorSceneFormatImporterESCN : public EditorSceneFormatImporter { |
310 | GDCLASS(EditorSceneFormatImporterESCN, EditorSceneFormatImporter); |
311 | |
312 | public: |
313 | virtual uint32_t get_import_flags() const override; |
314 | virtual void get_extensions(List<String> *r_extensions) const override; |
315 | virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; |
316 | }; |
317 | |
318 | template <class M> |
319 | Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<ImporterMesh> &p_mesh, const M &p_options, float p_applied_root_scale) { |
320 | ERR_FAIL_COND_V(p_mesh.is_null(), Vector<Ref<Shape3D>>()); |
321 | ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX; |
322 | if (p_options.has(SNAME("physics/shape_type" ))) { |
323 | generate_shape_type = (ShapeType)p_options[SNAME("physics/shape_type" )].operator int(); |
324 | } |
325 | |
326 | if (generate_shape_type == SHAPE_TYPE_DECOMPOSE_CONVEX) { |
327 | Ref<MeshConvexDecompositionSettings> decomposition_settings = Ref<MeshConvexDecompositionSettings>(); |
328 | decomposition_settings.instantiate(); |
329 | bool advanced = false; |
330 | if (p_options.has(SNAME("decomposition/advanced" ))) { |
331 | advanced = p_options[SNAME("decomposition/advanced" )]; |
332 | } |
333 | |
334 | if (advanced) { |
335 | if (p_options.has(SNAME("decomposition/max_concavity" ))) { |
336 | decomposition_settings->set_max_concavity(p_options[SNAME("decomposition/max_concavity" )]); |
337 | } |
338 | |
339 | if (p_options.has(SNAME("decomposition/symmetry_planes_clipping_bias" ))) { |
340 | decomposition_settings->set_symmetry_planes_clipping_bias(p_options[SNAME("decomposition/symmetry_planes_clipping_bias" )]); |
341 | } |
342 | |
343 | if (p_options.has(SNAME("decomposition/revolution_axes_clipping_bias" ))) { |
344 | decomposition_settings->set_revolution_axes_clipping_bias(p_options[SNAME("decomposition/revolution_axes_clipping_bias" )]); |
345 | } |
346 | |
347 | if (p_options.has(SNAME("decomposition/min_volume_per_convex_hull" ))) { |
348 | decomposition_settings->set_min_volume_per_convex_hull(p_options[SNAME("decomposition/min_volume_per_convex_hull" )]); |
349 | } |
350 | |
351 | if (p_options.has(SNAME("decomposition/resolution" ))) { |
352 | decomposition_settings->set_resolution(p_options[SNAME("decomposition/resolution" )]); |
353 | } |
354 | |
355 | if (p_options.has(SNAME("decomposition/max_num_vertices_per_convex_hull" ))) { |
356 | decomposition_settings->set_max_num_vertices_per_convex_hull(p_options[SNAME("decomposition/max_num_vertices_per_convex_hull" )]); |
357 | } |
358 | |
359 | if (p_options.has(SNAME("decomposition/plane_downsampling" ))) { |
360 | decomposition_settings->set_plane_downsampling(p_options[SNAME("decomposition/plane_downsampling" )]); |
361 | } |
362 | |
363 | if (p_options.has(SNAME("decomposition/convexhull_downsampling" ))) { |
364 | decomposition_settings->set_convex_hull_downsampling(p_options[SNAME("decomposition/convexhull_downsampling" )]); |
365 | } |
366 | |
367 | if (p_options.has(SNAME("decomposition/normalize_mesh" ))) { |
368 | decomposition_settings->set_normalize_mesh(p_options[SNAME("decomposition/normalize_mesh" )]); |
369 | } |
370 | |
371 | if (p_options.has(SNAME("decomposition/mode" ))) { |
372 | decomposition_settings->set_mode((MeshConvexDecompositionSettings::Mode)p_options[SNAME("decomposition/mode" )].operator int()); |
373 | } |
374 | |
375 | if (p_options.has(SNAME("decomposition/convexhull_approximation" ))) { |
376 | decomposition_settings->set_convex_hull_approximation(p_options[SNAME("decomposition/convexhull_approximation" )]); |
377 | } |
378 | |
379 | if (p_options.has(SNAME("decomposition/max_convex_hulls" ))) { |
380 | decomposition_settings->set_max_convex_hulls(MAX(1, (int)p_options[SNAME("decomposition/max_convex_hulls" )])); |
381 | } |
382 | |
383 | if (p_options.has(SNAME("decomposition/project_hull_vertices" ))) { |
384 | decomposition_settings->set_project_hull_vertices(p_options[SNAME("decomposition/project_hull_vertices" )]); |
385 | } |
386 | } else { |
387 | int precision_level = 5; |
388 | if (p_options.has(SNAME("decomposition/precision" ))) { |
389 | precision_level = p_options[SNAME("decomposition/precision" )]; |
390 | } |
391 | |
392 | const real_t precision = real_t(precision_level - 1) / 9.0; |
393 | |
394 | decomposition_settings->set_max_concavity(Math::lerp(real_t(1.0), real_t(0.001), precision)); |
395 | decomposition_settings->set_min_volume_per_convex_hull(Math::lerp(real_t(0.01), real_t(0.0001), precision)); |
396 | decomposition_settings->set_resolution(Math::lerp(10'000, 100'000, precision)); |
397 | decomposition_settings->set_max_num_vertices_per_convex_hull(Math::lerp(32, 64, precision)); |
398 | decomposition_settings->set_plane_downsampling(Math::lerp(3, 16, precision)); |
399 | decomposition_settings->set_convex_hull_downsampling(Math::lerp(3, 16, precision)); |
400 | decomposition_settings->set_max_convex_hulls(Math::lerp(1, 32, precision)); |
401 | } |
402 | |
403 | return p_mesh->convex_decompose(decomposition_settings); |
404 | } else if (generate_shape_type == SHAPE_TYPE_SIMPLE_CONVEX) { |
405 | Vector<Ref<Shape3D>> shapes; |
406 | shapes.push_back(p_mesh->create_convex_shape(true, /*Passing false, otherwise VHACD will be used to simplify (Decompose) the Mesh.*/ false)); |
407 | return shapes; |
408 | } else if (generate_shape_type == SHAPE_TYPE_TRIMESH) { |
409 | Vector<Ref<Shape3D>> shapes; |
410 | shapes.push_back(p_mesh->create_trimesh_shape()); |
411 | return shapes; |
412 | } else if (generate_shape_type == SHAPE_TYPE_BOX) { |
413 | Ref<BoxShape3D> box; |
414 | box.instantiate(); |
415 | if (p_options.has(SNAME("primitive/size" ))) { |
416 | box->set_size(p_options[SNAME("primitive/size" )].operator Vector3() * p_applied_root_scale); |
417 | } else { |
418 | box->set_size(Vector3(2, 2, 2) * p_applied_root_scale); |
419 | } |
420 | |
421 | Vector<Ref<Shape3D>> shapes; |
422 | shapes.push_back(box); |
423 | return shapes; |
424 | |
425 | } else if (generate_shape_type == SHAPE_TYPE_SPHERE) { |
426 | Ref<SphereShape3D> sphere; |
427 | sphere.instantiate(); |
428 | if (p_options.has(SNAME("primitive/radius" ))) { |
429 | sphere->set_radius(p_options[SNAME("primitive/radius" )].operator float() * p_applied_root_scale); |
430 | } else { |
431 | sphere->set_radius(1.0f * p_applied_root_scale); |
432 | } |
433 | |
434 | Vector<Ref<Shape3D>> shapes; |
435 | shapes.push_back(sphere); |
436 | return shapes; |
437 | } else if (generate_shape_type == SHAPE_TYPE_CYLINDER) { |
438 | Ref<CylinderShape3D> cylinder; |
439 | cylinder.instantiate(); |
440 | if (p_options.has(SNAME("primitive/height" ))) { |
441 | cylinder->set_height(p_options[SNAME("primitive/height" )].operator float() * p_applied_root_scale); |
442 | } else { |
443 | cylinder->set_height(1.0f * p_applied_root_scale); |
444 | } |
445 | if (p_options.has(SNAME("primitive/radius" ))) { |
446 | cylinder->set_radius(p_options[SNAME("primitive/radius" )].operator float() * p_applied_root_scale); |
447 | } else { |
448 | cylinder->set_radius(1.0f * p_applied_root_scale); |
449 | } |
450 | |
451 | Vector<Ref<Shape3D>> shapes; |
452 | shapes.push_back(cylinder); |
453 | return shapes; |
454 | } else if (generate_shape_type == SHAPE_TYPE_CAPSULE) { |
455 | Ref<CapsuleShape3D> capsule; |
456 | capsule.instantiate(); |
457 | if (p_options.has(SNAME("primitive/height" ))) { |
458 | capsule->set_height(p_options[SNAME("primitive/height" )].operator float() * p_applied_root_scale); |
459 | } else { |
460 | capsule->set_height(1.0f * p_applied_root_scale); |
461 | } |
462 | if (p_options.has(SNAME("primitive/radius" ))) { |
463 | capsule->set_radius(p_options[SNAME("primitive/radius" )].operator float() * p_applied_root_scale); |
464 | } else { |
465 | capsule->set_radius(1.0f * p_applied_root_scale); |
466 | } |
467 | |
468 | Vector<Ref<Shape3D>> shapes; |
469 | shapes.push_back(capsule); |
470 | return shapes; |
471 | } |
472 | return Vector<Ref<Shape3D>>(); |
473 | } |
474 | |
475 | template <class M> |
476 | Transform3D ResourceImporterScene::get_collision_shapes_transform(const M &p_options) { |
477 | Transform3D transform; |
478 | |
479 | ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX; |
480 | if (p_options.has(SNAME("physics/shape_type" ))) { |
481 | generate_shape_type = (ShapeType)p_options[SNAME("physics/shape_type" )].operator int(); |
482 | } |
483 | |
484 | if (generate_shape_type == SHAPE_TYPE_BOX || |
485 | generate_shape_type == SHAPE_TYPE_SPHERE || |
486 | generate_shape_type == SHAPE_TYPE_CYLINDER || |
487 | generate_shape_type == SHAPE_TYPE_CAPSULE) { |
488 | if (p_options.has(SNAME("primitive/position" ))) { |
489 | transform.origin = p_options[SNAME("primitive/position" )]; |
490 | } |
491 | |
492 | if (p_options.has(SNAME("primitive/rotation" ))) { |
493 | transform.basis = Basis::from_euler(p_options[SNAME("primitive/rotation" )].operator Vector3() * (Math_PI / 180.0)); |
494 | } |
495 | } |
496 | return transform; |
497 | } |
498 | |
499 | #endif // RESOURCE_IMPORTER_SCENE_H |
500 | |