| 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 |  | 
|---|