Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/import/3d/resource_importer_scene.cpp
9903 views
1
/**************************************************************************/
2
/* resource_importer_scene.cpp */
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
#include "resource_importer_scene.h"
32
33
#include "core/error/error_macros.h"
34
#include "core/io/dir_access.h"
35
#include "core/io/resource_saver.h"
36
#include "core/object/script_language.h"
37
#include "editor/editor_interface.h"
38
#include "editor/editor_node.h"
39
#include "editor/import/3d/scene_import_settings.h"
40
#include "editor/settings/editor_settings.h"
41
#include "scene/3d/importer_mesh_instance_3d.h"
42
#include "scene/3d/mesh_instance_3d.h"
43
#include "scene/3d/navigation/navigation_region_3d.h"
44
#include "scene/3d/occluder_instance_3d.h"
45
#include "scene/3d/physics/area_3d.h"
46
#include "scene/3d/physics/collision_shape_3d.h"
47
#include "scene/3d/physics/static_body_3d.h"
48
#include "scene/3d/physics/vehicle_body_3d.h"
49
#include "scene/animation/animation_player.h"
50
#include "scene/resources/3d/box_shape_3d.h"
51
#include "scene/resources/3d/importer_mesh.h"
52
#include "scene/resources/3d/separation_ray_shape_3d.h"
53
#include "scene/resources/3d/sphere_shape_3d.h"
54
#include "scene/resources/3d/world_boundary_shape_3d.h"
55
#include "scene/resources/animation.h"
56
#include "scene/resources/bone_map.h"
57
#include "scene/resources/packed_scene.h"
58
#include "scene/resources/resource_format_text.h"
59
60
void EditorSceneFormatImporter::get_extensions(List<String> *r_extensions) const {
61
Vector<String> arr;
62
if (GDVIRTUAL_CALL(_get_extensions, arr)) {
63
for (int i = 0; i < arr.size(); i++) {
64
r_extensions->push_back(arr[i]);
65
}
66
return;
67
}
68
69
ERR_FAIL();
70
}
71
72
Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
73
Dictionary options_dict;
74
for (const KeyValue<StringName, Variant> &elem : p_options) {
75
options_dict[elem.key] = elem.value;
76
}
77
Object *ret = nullptr;
78
if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, options_dict, ret)) {
79
return Object::cast_to<Node>(ret);
80
}
81
82
ERR_FAIL_V(nullptr);
83
}
84
85
void EditorSceneFormatImporter::add_import_option(const String &p_name, const Variant &p_default_value) {
86
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option() can only be called from get_import_options().");
87
add_import_option_advanced(p_default_value.get_type(), p_name, p_default_value);
88
}
89
90
void EditorSceneFormatImporter::add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint, const String &p_hint_string, int p_usage_flags) {
91
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option_advanced() can only be called from get_import_options().");
92
current_option_list->push_back(ResourceImporter::ImportOption(PropertyInfo(p_type, p_name, p_hint, p_hint_string, p_usage_flags), p_default_value));
93
}
94
95
void EditorSceneFormatImporter::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
96
current_option_list = r_options;
97
GDVIRTUAL_CALL(_get_import_options, p_path);
98
current_option_list = nullptr;
99
}
100
101
Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) {
102
Variant ret;
103
// For compatibility with the old API, pass the import type as a boolean.
104
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_scene_import_type == "AnimationLibrary", p_option, ret);
105
return ret;
106
}
107
108
void EditorSceneFormatImporter::_bind_methods() {
109
ClassDB::bind_method(D_METHOD("add_import_option", "name", "value"), &EditorSceneFormatImporter::add_import_option);
110
ClassDB::bind_method(D_METHOD("add_import_option_advanced", "type", "name", "default_value", "hint", "hint_string", "usage_flags"), &EditorSceneFormatImporter::add_import_option_advanced, DEFVAL(PROPERTY_HINT_NONE), DEFVAL(""), DEFVAL(PROPERTY_USAGE_DEFAULT));
111
112
GDVIRTUAL_BIND(_get_extensions);
113
GDVIRTUAL_BIND(_import_scene, "path", "flags", "options");
114
GDVIRTUAL_BIND(_get_import_options, "path");
115
GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option");
116
117
BIND_CONSTANT(IMPORT_SCENE);
118
BIND_CONSTANT(IMPORT_ANIMATION);
119
BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES);
120
BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
121
BIND_CONSTANT(IMPORT_USE_NAMED_SKIN_BINDS);
122
BIND_CONSTANT(IMPORT_DISCARD_MESHES_AND_MATERIALS);
123
BIND_CONSTANT(IMPORT_FORCE_DISABLE_MESH_COMPRESSION);
124
}
125
126
/////////////////////////////////
127
void EditorScenePostImport::_bind_methods() {
128
GDVIRTUAL_BIND(_post_import, "scene")
129
ClassDB::bind_method(D_METHOD("get_source_file"), &EditorScenePostImport::get_source_file);
130
}
131
132
Node *EditorScenePostImport::post_import(Node *p_scene) {
133
Object *ret;
134
if (GDVIRTUAL_CALL(_post_import, p_scene, ret)) {
135
return Object::cast_to<Node>(ret);
136
}
137
138
return p_scene;
139
}
140
141
String EditorScenePostImport::get_source_file() const {
142
return source_file;
143
}
144
145
void EditorScenePostImport::init(const String &p_source_file) {
146
source_file = p_source_file;
147
}
148
149
///////////////////////////////////////////////////////
150
151
Variant EditorScenePostImportPlugin::get_option_value(const StringName &p_name) const {
152
ERR_FAIL_COND_V_MSG(current_options == nullptr && current_options_dict == nullptr, Variant(), "get_option_value called from a function where option values are not available.");
153
ERR_FAIL_COND_V_MSG(current_options && !current_options->has(p_name), Variant(), "get_option_value called with unexisting option argument: " + String(p_name));
154
ERR_FAIL_COND_V_MSG(current_options_dict && !current_options_dict->has(p_name), Variant(), "get_option_value called with unexisting option argument: " + String(p_name));
155
if (current_options && current_options->has(p_name)) {
156
return (*current_options)[p_name];
157
}
158
if (current_options_dict && current_options_dict->has(p_name)) {
159
return (*current_options_dict)[p_name];
160
}
161
return Variant();
162
}
163
void EditorScenePostImportPlugin::add_import_option(const String &p_name, const Variant &p_default_value) {
164
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option() can only be called from get_import_options().");
165
add_import_option_advanced(p_default_value.get_type(), p_name, p_default_value);
166
}
167
void EditorScenePostImportPlugin::add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint, const String &p_hint_string, int p_usage_flags) {
168
ERR_FAIL_NULL_MSG(current_option_list, "add_import_option_advanced() can only be called from get_import_options().");
169
current_option_list->push_back(ResourceImporter::ImportOption(PropertyInfo(p_type, p_name, p_hint, p_hint_string, p_usage_flags), p_default_value));
170
}
171
172
void EditorScenePostImportPlugin::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) {
173
current_option_list = r_options;
174
GDVIRTUAL_CALL(_get_internal_import_options, p_category);
175
current_option_list = nullptr;
176
}
177
178
Variant EditorScenePostImportPlugin::get_internal_option_visibility(InternalImportCategory p_category, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
179
current_options = &p_options;
180
Variant ret;
181
// For compatibility with the old API, pass the import type as a boolean.
182
GDVIRTUAL_CALL(_get_internal_option_visibility, p_category, p_scene_import_type == "AnimationLibrary", p_option, ret);
183
current_options = nullptr;
184
return ret;
185
}
186
187
Variant EditorScenePostImportPlugin::get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
188
current_options = &p_options;
189
Variant ret;
190
GDVIRTUAL_CALL(_get_internal_option_update_view_required, p_category, p_option, ret);
191
current_options = nullptr;
192
return ret;
193
}
194
195
void EditorScenePostImportPlugin::internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) {
196
current_options_dict = &p_options;
197
GDVIRTUAL_CALL(_internal_process, p_category, p_base_scene, p_node, p_resource);
198
current_options_dict = nullptr;
199
}
200
201
void EditorScenePostImportPlugin::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
202
current_option_list = r_options;
203
GDVIRTUAL_CALL(_get_import_options, p_path);
204
current_option_list = nullptr;
205
}
206
Variant EditorScenePostImportPlugin::get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
207
current_options = &p_options;
208
Variant ret;
209
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_scene_import_type == "AnimationLibrary", p_option, ret);
210
current_options = nullptr;
211
return ret;
212
}
213
214
void EditorScenePostImportPlugin::pre_process(Node *p_scene, const HashMap<StringName, Variant> &p_options) {
215
current_options = &p_options;
216
GDVIRTUAL_CALL(_pre_process, p_scene);
217
current_options = nullptr;
218
}
219
void EditorScenePostImportPlugin::post_process(Node *p_scene, const HashMap<StringName, Variant> &p_options) {
220
current_options = &p_options;
221
GDVIRTUAL_CALL(_post_process, p_scene);
222
current_options = nullptr;
223
}
224
225
void EditorScenePostImportPlugin::_bind_methods() {
226
ClassDB::bind_method(D_METHOD("get_option_value", "name"), &EditorScenePostImportPlugin::get_option_value);
227
228
ClassDB::bind_method(D_METHOD("add_import_option", "name", "value"), &EditorScenePostImportPlugin::add_import_option);
229
ClassDB::bind_method(D_METHOD("add_import_option_advanced", "type", "name", "default_value", "hint", "hint_string", "usage_flags"), &EditorScenePostImportPlugin::add_import_option_advanced, DEFVAL(PROPERTY_HINT_NONE), DEFVAL(""), DEFVAL(PROPERTY_USAGE_DEFAULT));
230
231
GDVIRTUAL_BIND(_get_internal_import_options, "category");
232
GDVIRTUAL_BIND(_get_internal_option_visibility, "category", "for_animation", "option");
233
GDVIRTUAL_BIND(_get_internal_option_update_view_required, "category", "option");
234
GDVIRTUAL_BIND(_internal_process, "category", "base_node", "node", "resource");
235
GDVIRTUAL_BIND(_get_import_options, "path");
236
GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option");
237
GDVIRTUAL_BIND(_pre_process, "scene");
238
GDVIRTUAL_BIND(_post_process, "scene");
239
240
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_NODE);
241
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE);
242
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_MESH);
243
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_MATERIAL);
244
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_ANIMATION);
245
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE);
246
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE);
247
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_MAX);
248
}
249
250
/////////////////////////////////////////////////////////
251
252
const String ResourceImporterScene::material_extension[3] = { ".tres", ".res", ".material" };
253
254
String ResourceImporterScene::get_importer_name() const {
255
// For compatibility with 4.2 and earlier we need to keep the "scene" and "animation_library" names.
256
// However this is arbitrary so for new import types we can use any string.
257
if (_scene_import_type == "PackedScene") {
258
return "scene";
259
} else if (_scene_import_type == "AnimationLibrary") {
260
return "animation_library";
261
}
262
return _scene_import_type;
263
}
264
265
String ResourceImporterScene::get_visible_name() const {
266
// This is displayed on the UI. Friendly names here are nice but not vital, so fall back to the type.
267
if (_scene_import_type == "PackedScene") {
268
return "Scene";
269
}
270
return _scene_import_type.capitalize();
271
}
272
273
void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions) const {
274
get_scene_importer_extensions(p_extensions);
275
}
276
277
String ResourceImporterScene::get_save_extension() const {
278
if (_scene_import_type == "PackedScene") {
279
return "scn";
280
}
281
return "res";
282
}
283
284
String ResourceImporterScene::get_resource_type() const {
285
return _scene_import_type;
286
}
287
288
int ResourceImporterScene::get_format_version() const {
289
return 1;
290
}
291
292
bool ResourceImporterScene::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
293
if (_scene_import_type == "PackedScene") {
294
if (p_option.begins_with("animation/")) {
295
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
296
return false;
297
}
298
}
299
} else if (_scene_import_type == "AnimationLibrary") {
300
if (p_option == "animation/import") { // Option ignored, animation always imported.
301
return false;
302
}
303
if (p_option == "nodes/root_type" || p_option == "nodes/root_name" || p_option.begins_with("meshes/") || p_option.begins_with("skins/")) {
304
return false; // Nothing to do here for animations.
305
}
306
}
307
308
if (p_option == "nodes/use_node_type_suffixes" && p_options.has("nodes/use_name_suffixes")) {
309
return p_options["nodes/use_name_suffixes"];
310
}
311
if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) != 2) {
312
// Only display the lightmap texel size import option when using the Static Lightmaps light baking mode.
313
return false;
314
}
315
316
for (int i = 0; i < post_importer_plugins.size(); i++) {
317
Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, _scene_import_type, p_option, p_options);
318
if (ret.get_type() == Variant::BOOL) {
319
if (!ret) {
320
return false;
321
}
322
}
323
}
324
325
for (Ref<EditorSceneFormatImporter> importer : scene_importers) {
326
Variant ret = importer->get_option_visibility(p_path, _scene_import_type, p_option, p_options);
327
if (ret.get_type() == Variant::BOOL) {
328
if (!ret) {
329
return false;
330
}
331
}
332
}
333
334
return true;
335
}
336
337
int ResourceImporterScene::get_preset_count() const {
338
return 0;
339
}
340
341
String ResourceImporterScene::get_preset_name(int p_idx) const {
342
return String();
343
}
344
345
void ResourceImporterScene::_pre_fix_global(Node *p_scene, const HashMap<StringName, Variant> &p_options) const {
346
if (p_options.has("animation/import_rest_as_RESET") && (bool)p_options["animation/import_rest_as_RESET"]) {
347
TypedArray<Node> anim_players = p_scene->find_children("*", "AnimationPlayer");
348
if (anim_players.is_empty()) {
349
AnimationPlayer *anim_player = memnew(AnimationPlayer);
350
anim_player->set_name("AnimationPlayer");
351
p_scene->add_child(anim_player);
352
anim_player->set_owner(p_scene);
353
anim_players.append(anim_player);
354
}
355
Ref<Animation> reset_anim;
356
for (int i = 0; i < anim_players.size(); i++) {
357
AnimationPlayer *player = cast_to<AnimationPlayer>(anim_players[i]);
358
if (player->has_animation(SceneStringName(RESET))) {
359
reset_anim = player->get_animation(SceneStringName(RESET));
360
break;
361
}
362
}
363
if (reset_anim.is_null()) {
364
AnimationPlayer *anim_player = cast_to<AnimationPlayer>(anim_players[0]);
365
reset_anim.instantiate();
366
Ref<AnimationLibrary> anim_library;
367
if (anim_player->has_animation_library(StringName())) {
368
anim_library = anim_player->get_animation_library(StringName());
369
} else {
370
anim_library.instantiate();
371
anim_player->add_animation_library(StringName(), anim_library);
372
}
373
anim_library->add_animation(SceneStringName(RESET), reset_anim);
374
}
375
TypedArray<Node> skeletons = p_scene->find_children("*", "Skeleton3D");
376
for (int i = 0; i < skeletons.size(); i++) {
377
Skeleton3D *skeleton = cast_to<Skeleton3D>(skeletons[i]);
378
NodePath skeleton_path = p_scene->get_path_to(skeleton);
379
380
HashSet<NodePath> existing_pos_tracks;
381
HashSet<NodePath> existing_rot_tracks;
382
for (int trk_i = 0; trk_i < reset_anim->get_track_count(); trk_i++) {
383
NodePath np = reset_anim->track_get_path(trk_i);
384
if (reset_anim->track_get_type(trk_i) == Animation::TYPE_POSITION_3D) {
385
existing_pos_tracks.insert(np);
386
}
387
if (reset_anim->track_get_type(trk_i) == Animation::TYPE_ROTATION_3D) {
388
existing_rot_tracks.insert(np);
389
}
390
}
391
for (int bone_i = 0; bone_i < skeleton->get_bone_count(); bone_i++) {
392
NodePath bone_path(skeleton_path.get_names(), Vector<StringName>{ skeleton->get_bone_name(bone_i) }, false);
393
if (!existing_pos_tracks.has(bone_path)) {
394
int pos_t = reset_anim->add_track(Animation::TYPE_POSITION_3D);
395
reset_anim->track_set_path(pos_t, bone_path);
396
reset_anim->position_track_insert_key(pos_t, 0.0, skeleton->get_bone_rest(bone_i).origin);
397
reset_anim->track_set_imported(pos_t, true);
398
}
399
if (!existing_rot_tracks.has(bone_path)) {
400
int rot_t = reset_anim->add_track(Animation::TYPE_ROTATION_3D);
401
reset_anim->track_set_path(rot_t, bone_path);
402
reset_anim->rotation_track_insert_key(rot_t, 0.0, skeleton->get_bone_rest(bone_i).basis.get_rotation_quaternion());
403
reset_anim->track_set_imported(rot_t, true);
404
}
405
}
406
}
407
}
408
}
409
410
static bool _teststr(const String &p_what, const String &p_str) {
411
String what = p_what;
412
413
// Remove trailing spaces and numbers, some apps like blender add ".number" to duplicates
414
// (dot is replaced with _ as invalid character) so also compensate for this.
415
while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '_')) {
416
what = what.substr(0, what.length() - 1);
417
}
418
419
if (what.containsn("$" + p_str)) { // Blender and other stuff.
420
return true;
421
}
422
if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
423
return true;
424
}
425
if (what.to_lower().ends_with("_" + p_str)) { //collada only supports "_" and "-" besides letters
426
return true;
427
}
428
return false;
429
}
430
431
static String _fixstr(const String &p_what, const String &p_str) {
432
String what = p_what;
433
434
// Remove trailing spaces and numbers, some apps like blender add ".number" to duplicates
435
// (dot is replaced with _ as invalid character) so also compensate for this.
436
while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '_')) {
437
what = what.substr(0, what.length() - 1);
438
}
439
440
String end = p_what.substr(what.length());
441
442
if (what.containsn("$" + p_str)) { // Blender and other stuff.
443
return what.replace("$" + p_str, "") + end;
444
}
445
if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
446
return what.substr(0, what.length() - (p_str.length() + 1)) + end;
447
}
448
if (what.to_lower().ends_with("_" + p_str)) { //collada only supports "_" and "-" besides letters
449
return what.substr(0, what.length() - (p_str.length() + 1)) + end;
450
}
451
return what;
452
}
453
454
static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
455
ERR_FAIL_COND_MSG(mesh.is_null(), "Cannot generate shape list with null mesh value.");
456
if (!p_convex) {
457
Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape();
458
r_shape_list.push_back(shape);
459
} else {
460
Vector<Ref<Shape3D>> cd;
461
cd.push_back(mesh->create_convex_shape(true, /*Passing false, otherwise VHACD will be used to simplify (Decompose) the Mesh.*/ false));
462
if (cd.size()) {
463
for (int i = 0; i < cd.size(); i++) {
464
r_shape_list.push_back(cd[i]);
465
}
466
}
467
}
468
}
469
470
struct ScalableNodeCollection {
471
HashSet<Node3D *> node_3ds;
472
HashSet<Ref<ImporterMesh>> importer_meshes;
473
HashSet<Ref<Skin>> skins;
474
HashSet<Ref<Animation>> animations;
475
};
476
477
void _rescale_importer_mesh(Vector3 p_scale, Ref<ImporterMesh> p_mesh, bool is_shadow = false) {
478
// MESH and SKIN data divide, to compensate for object position multiplying.
479
480
const int surf_count = p_mesh->get_surface_count();
481
const int blendshape_count = p_mesh->get_blend_shape_count();
482
struct LocalSurfData {
483
Mesh::PrimitiveType prim = {};
484
Array arr;
485
Array bsarr;
486
Dictionary lods;
487
String name;
488
Ref<Material> mat;
489
uint64_t fmt_compress_flags = 0;
490
};
491
492
Vector<LocalSurfData> surf_data_by_mesh;
493
494
Vector<String> blendshape_names;
495
for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
496
blendshape_names.append(p_mesh->get_blend_shape_name(bsidx));
497
}
498
499
for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) {
500
Mesh::PrimitiveType prim = p_mesh->get_surface_primitive_type(surf_idx);
501
const uint64_t fmt_compress_flags = p_mesh->get_surface_format(surf_idx);
502
Array arr = p_mesh->get_surface_arrays(surf_idx);
503
String name = p_mesh->get_surface_name(surf_idx);
504
Dictionary lods;
505
Ref<Material> mat = p_mesh->get_surface_material(surf_idx);
506
{
507
Vector<Vector3> vertex_array = arr[ArrayMesh::ARRAY_VERTEX];
508
for (int vert_arr_i = 0; vert_arr_i < vertex_array.size(); vert_arr_i++) {
509
vertex_array.write[vert_arr_i] = vertex_array[vert_arr_i] * p_scale;
510
}
511
arr[ArrayMesh::ARRAY_VERTEX] = vertex_array;
512
}
513
Array blendshapes;
514
for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
515
Array current_bsarr = p_mesh->get_surface_blend_shape_arrays(surf_idx, bsidx);
516
Vector<Vector3> current_bs_vertex_array = current_bsarr[ArrayMesh::ARRAY_VERTEX];
517
int current_bs_vert_arr_len = current_bs_vertex_array.size();
518
for (int32_t bs_vert_arr_i = 0; bs_vert_arr_i < current_bs_vert_arr_len; bs_vert_arr_i++) {
519
current_bs_vertex_array.write[bs_vert_arr_i] = current_bs_vertex_array[bs_vert_arr_i] * p_scale;
520
}
521
current_bsarr[ArrayMesh::ARRAY_VERTEX] = current_bs_vertex_array;
522
blendshapes.push_back(current_bsarr);
523
}
524
525
LocalSurfData surf_data_dictionary = LocalSurfData();
526
surf_data_dictionary.prim = prim;
527
surf_data_dictionary.arr = arr;
528
surf_data_dictionary.bsarr = blendshapes;
529
surf_data_dictionary.lods = lods;
530
surf_data_dictionary.fmt_compress_flags = fmt_compress_flags;
531
surf_data_dictionary.name = name;
532
surf_data_dictionary.mat = mat;
533
534
surf_data_by_mesh.push_back(surf_data_dictionary);
535
}
536
537
p_mesh->clear();
538
539
for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
540
p_mesh->add_blend_shape(blendshape_names[bsidx]);
541
}
542
543
for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) {
544
const Mesh::PrimitiveType prim = surf_data_by_mesh[surf_idx].prim;
545
const Array arr = surf_data_by_mesh[surf_idx].arr;
546
const Array bsarr = surf_data_by_mesh[surf_idx].bsarr;
547
const Dictionary lods = surf_data_by_mesh[surf_idx].lods;
548
const uint64_t fmt_compress_flags = surf_data_by_mesh[surf_idx].fmt_compress_flags;
549
const String name = surf_data_by_mesh[surf_idx].name;
550
const Ref<Material> mat = surf_data_by_mesh[surf_idx].mat;
551
552
p_mesh->add_surface(prim, arr, bsarr, lods, mat, name, fmt_compress_flags);
553
}
554
555
if (!is_shadow && p_mesh->get_shadow_mesh() != p_mesh && p_mesh->get_shadow_mesh().is_valid()) {
556
_rescale_importer_mesh(p_scale, p_mesh->get_shadow_mesh(), true);
557
}
558
}
559
560
void _rescale_skin(Vector3 p_scale, Ref<Skin> p_skin) {
561
// MESH and SKIN data divide, to compensate for object position multiplying.
562
for (int i = 0; i < p_skin->get_bind_count(); i++) {
563
Transform3D transform = p_skin->get_bind_pose(i);
564
p_skin->set_bind_pose(i, Transform3D(transform.basis, p_scale * transform.origin));
565
}
566
}
567
568
void _rescale_animation(Vector3 p_scale, Ref<Animation> p_animation) {
569
for (int track_idx = 0; track_idx < p_animation->get_track_count(); track_idx++) {
570
if (p_animation->track_get_type(track_idx) == Animation::TYPE_POSITION_3D) {
571
for (int key_idx = 0; key_idx < p_animation->track_get_key_count(track_idx); key_idx++) {
572
Vector3 value = p_animation->track_get_key_value(track_idx, key_idx);
573
value = p_scale * value;
574
p_animation->track_set_key_value(track_idx, key_idx, value);
575
}
576
}
577
}
578
}
579
580
void _apply_scale_to_scalable_node_collection(ScalableNodeCollection &p_collection, Vector3 p_scale) {
581
for (Node3D *node_3d : p_collection.node_3ds) {
582
node_3d->set_position(p_scale * node_3d->get_position());
583
Skeleton3D *skeleton_3d = Object::cast_to<Skeleton3D>(node_3d);
584
if (skeleton_3d) {
585
for (int i = 0; i < skeleton_3d->get_bone_count(); i++) {
586
Transform3D rest = skeleton_3d->get_bone_rest(i);
587
Vector3 position = skeleton_3d->get_bone_pose_position(i);
588
skeleton_3d->set_bone_rest(i, Transform3D(rest.basis, p_scale * rest.origin));
589
skeleton_3d->set_bone_pose_position(i, p_scale * position);
590
}
591
}
592
}
593
for (Ref<ImporterMesh> mesh : p_collection.importer_meshes) {
594
_rescale_importer_mesh(p_scale, mesh, false);
595
}
596
for (Ref<Skin> skin : p_collection.skins) {
597
_rescale_skin(p_scale, skin);
598
}
599
for (Ref<Animation> animation : p_collection.animations) {
600
_rescale_animation(p_scale, animation);
601
}
602
}
603
604
void _populate_scalable_nodes_collection(Node *p_node, ScalableNodeCollection &p_collection) {
605
if (!p_node) {
606
return;
607
}
608
Node3D *node_3d = Object::cast_to<Node3D>(p_node);
609
if (node_3d) {
610
p_collection.node_3ds.insert(node_3d);
611
ImporterMeshInstance3D *mesh_instance_3d = Object::cast_to<ImporterMeshInstance3D>(p_node);
612
if (mesh_instance_3d) {
613
Ref<ImporterMesh> mesh = mesh_instance_3d->get_mesh();
614
if (mesh.is_valid()) {
615
p_collection.importer_meshes.insert(mesh);
616
}
617
Ref<Skin> skin = mesh_instance_3d->get_skin();
618
if (skin.is_valid()) {
619
p_collection.skins.insert(skin);
620
}
621
}
622
}
623
AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_node);
624
if (animation_player) {
625
List<StringName> animation_list;
626
animation_player->get_animation_list(&animation_list);
627
628
for (const StringName &E : animation_list) {
629
Ref<Animation> animation = animation_player->get_animation(E);
630
p_collection.animations.insert(animation);
631
}
632
}
633
634
for (int i = 0; i < p_node->get_child_count(); i++) {
635
Node *child = p_node->get_child(i);
636
_populate_scalable_nodes_collection(child, p_collection);
637
}
638
}
639
640
void _apply_permanent_scale_to_descendants(Node *p_root_node, Vector3 p_scale) {
641
ScalableNodeCollection scalable_node_collection;
642
_populate_scalable_nodes_collection(p_root_node, scalable_node_collection);
643
_apply_scale_to_scalable_node_collection(scalable_node_collection, p_scale);
644
}
645
646
Node *ResourceImporterScene::_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, const HashMap<StringName, Variant> &p_options) {
647
bool use_name_suffixes = true;
648
if (p_options.has("nodes/use_name_suffixes")) {
649
use_name_suffixes = p_options["nodes/use_name_suffixes"];
650
}
651
if (!use_name_suffixes) {
652
return p_node;
653
}
654
655
// Children first.
656
for (int i = 0; i < p_node->get_child_count(); i++) {
657
Node *r = _pre_fix_node(p_node->get_child(i), p_root, r_collision_map, r_occluder_arrays, r_node_renames, p_options);
658
if (!r) {
659
i--; // Was erased.
660
}
661
}
662
663
String name = p_node->get_name();
664
NodePath original_path = p_root->get_path_to(p_node); // Used to detect renames due to import hints.
665
666
Ref<Resource> original_meta = memnew(Resource); // Create temp resource to hold original meta
667
original_meta->merge_meta_from(p_node);
668
669
bool isroot = p_node == p_root;
670
671
if (!isroot && _teststr(name, "noimp")) {
672
p_node->set_owner(nullptr);
673
memdelete(p_node);
674
return nullptr;
675
}
676
677
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
678
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
679
680
Ref<ImporterMesh> m = mi->get_mesh();
681
682
if (m.is_valid()) {
683
for (int i = 0; i < m->get_surface_count(); i++) {
684
Ref<BaseMaterial3D> mat = m->get_surface_material(i);
685
if (mat.is_null()) {
686
continue;
687
}
688
689
if (_teststr(mat->get_name(), "alpha")) {
690
mat->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
691
mat->set_name(_fixstr(mat->get_name(), "alpha"));
692
}
693
if (_teststr(mat->get_name(), "vcol")) {
694
mat->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
695
mat->set_flag(BaseMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
696
mat->set_name(_fixstr(mat->get_name(), "vcol"));
697
}
698
}
699
}
700
}
701
702
if (Object::cast_to<AnimationPlayer>(p_node)) {
703
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
704
705
// Node paths in animation tracks are relative to the following path (this is used to fix node paths below).
706
Node *ap_root = ap->get_node(ap->get_root_node());
707
NodePath path_prefix = p_root->get_path_to(ap_root);
708
709
bool nodes_were_renamed = r_node_renames.size() != 0;
710
711
List<StringName> anims;
712
ap->get_animation_list(&anims);
713
for (const StringName &E : anims) {
714
Ref<Animation> anim = ap->get_animation(E);
715
ERR_CONTINUE(anim.is_null());
716
717
// Remove animation tracks referencing non-importable nodes.
718
for (int i = 0; i < anim->get_track_count(); i++) {
719
NodePath path = anim->track_get_path(i);
720
721
for (int j = 0; j < path.get_name_count(); j++) {
722
String node = path.get_name(j);
723
if (_teststr(node, "noimp")) {
724
anim->remove_track(i);
725
i--;
726
break;
727
}
728
}
729
}
730
731
// Fix node paths in animations, in case nodes were renamed earlier due to import hints.
732
if (nodes_were_renamed) {
733
for (int i = 0; i < anim->get_track_count(); i++) {
734
NodePath path = anim->track_get_path(i);
735
// Convert track path to absolute node path without subnames (some manual work because we are not in the scene tree).
736
Vector<StringName> absolute_path_names = path_prefix.get_names();
737
absolute_path_names.append_array(path.get_names());
738
NodePath absolute_path(absolute_path_names, false);
739
absolute_path.simplify();
740
// Fix paths to renamed nodes.
741
for (const Pair<NodePath, Node *> &F : r_node_renames) {
742
if (F.first == absolute_path) {
743
NodePath new_path(ap_root->get_path_to(F.second).get_names(), path.get_subnames(), false);
744
print_verbose(vformat("Fix: Correcting node path in animation track: %s should be %s", path, new_path));
745
anim->track_set_path(i, new_path);
746
break; // Only one match is possible.
747
}
748
}
749
}
750
}
751
752
String animname = E;
753
const int loop_string_count = 3;
754
static const char *loop_strings[loop_string_count] = { "loop_mode", "loop", "cycle" };
755
for (int i = 0; i < loop_string_count; i++) {
756
if (_teststr(animname, loop_strings[i])) {
757
anim->set_loop_mode(Animation::LOOP_LINEAR);
758
animname = _fixstr(animname, loop_strings[i]);
759
760
Ref<AnimationLibrary> library = ap->get_animation_library(ap->find_animation_library(anim));
761
library->rename_animation(E, animname);
762
}
763
}
764
}
765
}
766
767
bool use_node_type_suffixes = true;
768
if (p_options.has("nodes/use_node_type_suffixes")) {
769
use_node_type_suffixes = p_options["nodes/use_node_type_suffixes"];
770
}
771
if (!use_node_type_suffixes) {
772
return p_node;
773
}
774
775
if (_teststr(name, "colonly") || _teststr(name, "convcolonly")) {
776
if (isroot) {
777
return p_node;
778
}
779
780
String fixed_name;
781
if (_teststr(name, "colonly")) {
782
fixed_name = _fixstr(name, "colonly");
783
} else if (_teststr(name, "convcolonly")) {
784
fixed_name = _fixstr(name, "convcolonly");
785
}
786
787
if (fixed_name.is_empty()) {
788
p_node->set_owner(nullptr);
789
memdelete(p_node);
790
ERR_FAIL_V_MSG(nullptr, vformat("Skipped node `%s` because its name is empty after removing the suffix.", name));
791
}
792
793
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
794
if (mi) {
795
Ref<ImporterMesh> mesh = mi->get_mesh();
796
797
if (mesh.is_valid()) {
798
Vector<Ref<Shape3D>> shapes;
799
if (r_collision_map.has(mesh)) {
800
shapes = r_collision_map[mesh];
801
} else if (_teststr(name, "colonly")) {
802
_pre_gen_shape_list(mesh, shapes, false);
803
r_collision_map[mesh] = shapes;
804
} else if (_teststr(name, "convcolonly")) {
805
_pre_gen_shape_list(mesh, shapes, true);
806
r_collision_map[mesh] = shapes;
807
}
808
809
if (shapes.size()) {
810
StaticBody3D *col = memnew(StaticBody3D);
811
col->set_transform(mi->get_transform());
812
col->set_name(fixed_name);
813
_copy_meta(p_node, col);
814
p_node->replace_by(col);
815
p_node->set_owner(nullptr);
816
memdelete(p_node);
817
p_node = col;
818
819
_add_shapes(col, shapes);
820
}
821
}
822
823
} else if (p_node->has_meta("empty_draw_type")) {
824
String empty_draw_type = String(p_node->get_meta("empty_draw_type"));
825
StaticBody3D *sb = memnew(StaticBody3D);
826
sb->set_name(fixed_name);
827
Object::cast_to<Node3D>(sb)->set_transform(Object::cast_to<Node3D>(p_node)->get_transform());
828
_copy_meta(p_node, sb);
829
p_node->replace_by(sb);
830
p_node->set_owner(nullptr);
831
memdelete(p_node);
832
p_node = sb;
833
CollisionShape3D *colshape = memnew(CollisionShape3D);
834
if (empty_draw_type == "CUBE") {
835
BoxShape3D *boxShape = memnew(BoxShape3D);
836
boxShape->set_size(Vector3(2, 2, 2));
837
colshape->set_shape(boxShape);
838
} else if (empty_draw_type == "SINGLE_ARROW") {
839
SeparationRayShape3D *rayShape = memnew(SeparationRayShape3D);
840
rayShape->set_length(1);
841
colshape->set_shape(rayShape);
842
Object::cast_to<Node3D>(sb)->rotate_x(Math::PI / 2);
843
} else if (empty_draw_type == "IMAGE") {
844
WorldBoundaryShape3D *world_boundary_shape = memnew(WorldBoundaryShape3D);
845
colshape->set_shape(world_boundary_shape);
846
} else {
847
SphereShape3D *sphereShape = memnew(SphereShape3D);
848
sphereShape->set_radius(1);
849
colshape->set_shape(sphereShape);
850
}
851
sb->add_child(colshape, true);
852
colshape->set_owner(sb->get_owner());
853
}
854
855
} else if (_teststr(name, "rigid") && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
856
if (isroot) {
857
return p_node;
858
}
859
860
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
861
Ref<ImporterMesh> mesh = mi->get_mesh();
862
863
if (mesh.is_valid()) {
864
Vector<Ref<Shape3D>> shapes;
865
if (r_collision_map.has(mesh)) {
866
shapes = r_collision_map[mesh];
867
} else {
868
_pre_gen_shape_list(mesh, shapes, true);
869
}
870
871
RigidBody3D *rigid_body = memnew(RigidBody3D);
872
rigid_body->set_name(_fixstr(name, "rigid_body"));
873
_copy_meta(p_node, rigid_body);
874
p_node->replace_by(rigid_body);
875
rigid_body->set_transform(mi->get_transform());
876
p_node = rigid_body;
877
mi->set_transform(Transform3D());
878
rigid_body->add_child(mi, true);
879
mi->set_owner(rigid_body->get_owner());
880
881
_add_shapes(rigid_body, shapes);
882
}
883
884
} else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
885
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
886
887
Ref<ImporterMesh> mesh = mi->get_mesh();
888
889
if (mesh.is_valid()) {
890
Vector<Ref<Shape3D>> shapes;
891
String fixed_name;
892
if (r_collision_map.has(mesh)) {
893
shapes = r_collision_map[mesh];
894
} else if (_teststr(name, "col")) {
895
_pre_gen_shape_list(mesh, shapes, false);
896
r_collision_map[mesh] = shapes;
897
} else if (_teststr(name, "convcol")) {
898
_pre_gen_shape_list(mesh, shapes, true);
899
r_collision_map[mesh] = shapes;
900
}
901
902
if (_teststr(name, "col")) {
903
fixed_name = _fixstr(name, "col");
904
} else if (_teststr(name, "convcol")) {
905
fixed_name = _fixstr(name, "convcol");
906
}
907
908
if (!fixed_name.is_empty()) {
909
if (mi->get_parent() && !mi->get_parent()->has_node(fixed_name)) {
910
mi->set_name(fixed_name);
911
}
912
}
913
914
if (shapes.size()) {
915
StaticBody3D *col = memnew(StaticBody3D);
916
mi->add_child(col, true);
917
col->set_owner(mi->get_owner());
918
919
_add_shapes(col, shapes);
920
}
921
}
922
923
} else if (_teststr(name, "navmesh") && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
924
if (isroot) {
925
return p_node;
926
}
927
928
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
929
930
Ref<ImporterMesh> mesh = mi->get_mesh();
931
ERR_FAIL_COND_V(mesh.is_null(), nullptr);
932
NavigationRegion3D *nmi = memnew(NavigationRegion3D);
933
934
nmi->set_name(_fixstr(name, "navmesh"));
935
Ref<NavigationMesh> nmesh = mesh->create_navigation_mesh();
936
nmi->set_navigation_mesh(nmesh);
937
Object::cast_to<Node3D>(nmi)->set_transform(mi->get_transform());
938
_copy_meta(p_node, nmi);
939
p_node->replace_by(nmi);
940
p_node->set_owner(nullptr);
941
memdelete(p_node);
942
p_node = nmi;
943
} else if (_teststr(name, "occ") || _teststr(name, "occonly")) {
944
if (isroot) {
945
return p_node;
946
}
947
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
948
if (mi) {
949
Ref<ImporterMesh> mesh = mi->get_mesh();
950
951
if (mesh.is_valid()) {
952
if (r_occluder_arrays) {
953
OccluderInstance3D::bake_single_node(mi, 0.0f, r_occluder_arrays->first, r_occluder_arrays->second);
954
}
955
if (_teststr(name, "occ")) {
956
String fixed_name = _fixstr(name, "occ");
957
if (!fixed_name.is_empty()) {
958
if (mi->get_parent() && !mi->get_parent()->has_node(fixed_name)) {
959
mi->set_name(fixed_name);
960
}
961
}
962
} else {
963
p_node->set_owner(nullptr);
964
memdelete(p_node);
965
p_node = nullptr;
966
}
967
}
968
}
969
} else if (_teststr(name, "vehicle")) {
970
if (isroot) {
971
return p_node;
972
}
973
974
Node *owner = p_node->get_owner();
975
Node3D *s = Object::cast_to<Node3D>(p_node);
976
VehicleBody3D *bv = memnew(VehicleBody3D);
977
String n = _fixstr(p_node->get_name(), "vehicle");
978
bv->set_name(n);
979
_copy_meta(p_node, bv);
980
p_node->replace_by(bv);
981
p_node->set_name(n);
982
bv->add_child(p_node);
983
bv->set_owner(owner);
984
p_node->set_owner(owner);
985
bv->set_transform(s->get_transform());
986
s->set_transform(Transform3D());
987
988
p_node = bv;
989
} else if (_teststr(name, "wheel")) {
990
if (isroot) {
991
return p_node;
992
}
993
994
Node *owner = p_node->get_owner();
995
Node3D *s = Object::cast_to<Node3D>(p_node);
996
VehicleWheel3D *bv = memnew(VehicleWheel3D);
997
String n = _fixstr(p_node->get_name(), "wheel");
998
bv->set_name(n);
999
_copy_meta(p_node, bv);
1000
p_node->replace_by(bv);
1001
p_node->set_name(n);
1002
bv->add_child(p_node);
1003
bv->set_owner(owner);
1004
p_node->set_owner(owner);
1005
bv->set_transform(s->get_transform());
1006
s->set_transform(Transform3D());
1007
1008
p_node = bv;
1009
} else if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
1010
//last attempt, maybe collision inside the mesh data
1011
1012
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
1013
1014
Ref<ImporterMesh> mesh = mi->get_mesh();
1015
if (mesh.is_valid()) {
1016
Vector<Ref<Shape3D>> shapes;
1017
if (r_collision_map.has(mesh)) {
1018
shapes = r_collision_map[mesh];
1019
} else if (_teststr(mesh->get_name(), "col")) {
1020
_pre_gen_shape_list(mesh, shapes, false);
1021
r_collision_map[mesh] = shapes;
1022
mesh->set_name(_fixstr(mesh->get_name(), "col"));
1023
} else if (_teststr(mesh->get_name(), "convcol")) {
1024
_pre_gen_shape_list(mesh, shapes, true);
1025
r_collision_map[mesh] = shapes;
1026
mesh->set_name(_fixstr(mesh->get_name(), "convcol"));
1027
} else if (_teststr(mesh->get_name(), "occ")) {
1028
if (r_occluder_arrays) {
1029
OccluderInstance3D::bake_single_node(mi, 0.0f, r_occluder_arrays->first, r_occluder_arrays->second);
1030
}
1031
mesh->set_name(_fixstr(mesh->get_name(), "occ"));
1032
}
1033
1034
if (shapes.size()) {
1035
StaticBody3D *col = memnew(StaticBody3D);
1036
p_node->add_child(col, true);
1037
col->set_owner(p_node->get_owner());
1038
1039
_add_shapes(col, shapes);
1040
}
1041
}
1042
}
1043
1044
if (p_node) {
1045
NodePath new_path = p_root->get_path_to(p_node);
1046
if (new_path != original_path) {
1047
print_verbose(vformat("Fix: Renamed %s to %s", original_path, new_path));
1048
r_node_renames.push_back({ original_path, p_node });
1049
}
1050
// If we created new node instead, merge meta values from the original node.
1051
p_node->merge_meta_from(*original_meta);
1052
}
1053
1054
return p_node;
1055
}
1056
1057
Node *ResourceImporterScene::_pre_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps) {
1058
// children first
1059
for (int i = 0; i < p_node->get_child_count(); i++) {
1060
Node *r = _pre_fix_animations(p_node->get_child(i), p_root, p_node_data, p_animation_data, p_animation_fps);
1061
if (!r) {
1062
i--; //was erased
1063
}
1064
}
1065
1066
String import_id = p_node->get_meta("import_id", "PATH:" + String(p_root->get_path_to(p_node)));
1067
1068
Dictionary node_settings;
1069
if (p_node_data.has(import_id)) {
1070
node_settings = p_node_data[import_id];
1071
}
1072
1073
{
1074
//make sure this is unique
1075
node_settings = node_settings.duplicate(true);
1076
//fill node settings for this node with default values
1077
List<ImportOption> iopts;
1078
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, &iopts);
1079
for (const ImportOption &E : iopts) {
1080
if (!node_settings.has(E.option.name)) {
1081
node_settings[E.option.name] = E.default_value;
1082
}
1083
}
1084
}
1085
1086
if (Object::cast_to<AnimationPlayer>(p_node)) {
1087
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
1088
List<StringName> anims;
1089
ap->get_animation_list(&anims);
1090
1091
AnimationImportTracks import_tracks_mode[TRACK_CHANNEL_MAX] = {
1092
AnimationImportTracks(int(node_settings["import_tracks/position"])),
1093
AnimationImportTracks(int(node_settings["import_tracks/rotation"])),
1094
AnimationImportTracks(int(node_settings["import_tracks/scale"]))
1095
};
1096
1097
if (!anims.is_empty() && (import_tracks_mode[0] != ANIMATION_IMPORT_TRACKS_IF_PRESENT || import_tracks_mode[1] != ANIMATION_IMPORT_TRACKS_IF_PRESENT || import_tracks_mode[2] != ANIMATION_IMPORT_TRACKS_IF_PRESENT)) {
1098
_optimize_track_usage(ap, import_tracks_mode);
1099
}
1100
}
1101
1102
return p_node;
1103
}
1104
1105
Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps, bool p_remove_immutable_tracks) {
1106
// children first
1107
for (int i = 0; i < p_node->get_child_count(); i++) {
1108
Node *r = _post_fix_animations(p_node->get_child(i), p_root, p_node_data, p_animation_data, p_animation_fps, p_remove_immutable_tracks);
1109
if (!r) {
1110
i--; //was erased
1111
}
1112
}
1113
1114
String import_id = p_node->get_meta("import_id", "PATH:" + String(p_root->get_path_to(p_node)));
1115
1116
Dictionary node_settings;
1117
if (p_node_data.has(import_id)) {
1118
node_settings = p_node_data[import_id];
1119
}
1120
1121
{
1122
//make sure this is unique
1123
node_settings = node_settings.duplicate(true);
1124
//fill node settings for this node with default values
1125
List<ImportOption> iopts;
1126
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, &iopts);
1127
for (const ImportOption &E : iopts) {
1128
if (!node_settings.has(E.option.name)) {
1129
node_settings[E.option.name] = E.default_value;
1130
}
1131
}
1132
}
1133
1134
if (Object::cast_to<AnimationPlayer>(p_node)) {
1135
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
1136
List<StringName> anims;
1137
ap->get_animation_list(&anims);
1138
1139
if (p_remove_immutable_tracks) {
1140
AnimationImportTracks import_tracks_mode[TRACK_CHANNEL_MAX] = {
1141
AnimationImportTracks(int(node_settings["import_tracks/position"])),
1142
AnimationImportTracks(int(node_settings["import_tracks/rotation"])),
1143
AnimationImportTracks(int(node_settings["import_tracks/scale"]))
1144
};
1145
HashMap<NodePath, bool> used_tracks[TRACK_CHANNEL_MAX];
1146
1147
for (const StringName &name : anims) {
1148
Ref<Animation> anim = ap->get_animation(name);
1149
int track_count = anim->get_track_count();
1150
LocalVector<int> tracks_to_keep;
1151
for (int track_i = 0; track_i < track_count; track_i++) {
1152
tracks_to_keep.push_back(track_i);
1153
int track_channel_type = 0;
1154
switch (anim->track_get_type(track_i)) {
1155
case Animation::TYPE_POSITION_3D:
1156
track_channel_type = TRACK_CHANNEL_POSITION;
1157
break;
1158
case Animation::TYPE_ROTATION_3D:
1159
track_channel_type = TRACK_CHANNEL_ROTATION;
1160
break;
1161
case Animation::TYPE_SCALE_3D:
1162
track_channel_type = TRACK_CHANNEL_SCALE;
1163
break;
1164
default:
1165
continue;
1166
}
1167
AnimationImportTracks track_mode = import_tracks_mode[track_channel_type];
1168
NodePath path = anim->track_get_path(track_i);
1169
Node *n = p_root->get_node(path);
1170
Node3D *n3d = Object::cast_to<Node3D>(n);
1171
Skeleton3D *skel = Object::cast_to<Skeleton3D>(n);
1172
bool keep_track = false;
1173
Vector3 loc;
1174
Quaternion rot;
1175
Vector3 scale;
1176
if (skel && path.get_subname_count() > 0) {
1177
StringName bone = path.get_subname(0);
1178
int bone_idx = skel->find_bone(bone);
1179
if (bone_idx == -1) {
1180
continue;
1181
}
1182
// Note that this is using get_bone_pose to update the bone pose cache.
1183
Transform3D bone_rest = skel->get_bone_rest(bone_idx);
1184
loc = bone_rest.origin / skel->get_motion_scale();
1185
rot = bone_rest.basis.get_rotation_quaternion();
1186
scale = bone_rest.basis.get_scale();
1187
} else if (n3d) {
1188
loc = n3d->get_position();
1189
rot = n3d->get_transform().basis.get_rotation_quaternion();
1190
scale = n3d->get_scale();
1191
} else {
1192
continue;
1193
}
1194
1195
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
1196
if (used_tracks[track_channel_type].has(path)) {
1197
if (used_tracks[track_channel_type][path]) {
1198
continue;
1199
}
1200
} else {
1201
used_tracks[track_channel_type].insert(path, false);
1202
}
1203
}
1204
1205
for (int key_i = 0; key_i < anim->track_get_key_count(track_i) && !keep_track; key_i++) {
1206
switch (track_channel_type) {
1207
case TRACK_CHANNEL_POSITION: {
1208
Vector3 key_pos;
1209
anim->position_track_get_key(track_i, key_i, &key_pos);
1210
if (!key_pos.is_equal_approx(loc)) {
1211
keep_track = true;
1212
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
1213
used_tracks[track_channel_type][path] = true;
1214
}
1215
}
1216
} break;
1217
case TRACK_CHANNEL_ROTATION: {
1218
Quaternion key_rot;
1219
anim->rotation_track_get_key(track_i, key_i, &key_rot);
1220
if (!key_rot.is_equal_approx(rot)) {
1221
keep_track = true;
1222
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
1223
used_tracks[track_channel_type][path] = true;
1224
}
1225
}
1226
} break;
1227
case TRACK_CHANNEL_SCALE: {
1228
Vector3 key_scl;
1229
anim->scale_track_get_key(track_i, key_i, &key_scl);
1230
if (!key_scl.is_equal_approx(scale)) {
1231
keep_track = true;
1232
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
1233
used_tracks[track_channel_type][path] = true;
1234
}
1235
}
1236
} break;
1237
default:
1238
break;
1239
}
1240
}
1241
if (track_mode != ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL && !keep_track) {
1242
tracks_to_keep.remove_at(tracks_to_keep.size() - 1);
1243
}
1244
}
1245
for (int dst_track_i = 0; dst_track_i < (int)tracks_to_keep.size(); dst_track_i++) {
1246
int src_track_i = tracks_to_keep[dst_track_i];
1247
if (src_track_i != dst_track_i) {
1248
anim->track_swap(src_track_i, dst_track_i);
1249
}
1250
}
1251
for (int track_i = track_count - 1; track_i >= (int)tracks_to_keep.size(); track_i--) {
1252
anim->remove_track(track_i);
1253
}
1254
}
1255
for (const StringName &name : anims) {
1256
Ref<Animation> anim = ap->get_animation(name);
1257
int track_count = anim->get_track_count();
1258
LocalVector<int> tracks_to_keep;
1259
for (int track_i = 0; track_i < track_count; track_i++) {
1260
tracks_to_keep.push_back(track_i);
1261
int track_channel_type = 0;
1262
switch (anim->track_get_type(track_i)) {
1263
case Animation::TYPE_POSITION_3D:
1264
track_channel_type = TRACK_CHANNEL_POSITION;
1265
break;
1266
case Animation::TYPE_ROTATION_3D:
1267
track_channel_type = TRACK_CHANNEL_ROTATION;
1268
break;
1269
case Animation::TYPE_SCALE_3D:
1270
track_channel_type = TRACK_CHANNEL_SCALE;
1271
break;
1272
default:
1273
continue;
1274
}
1275
AnimationImportTracks track_mode = import_tracks_mode[track_channel_type];
1276
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
1277
NodePath path = anim->track_get_path(track_i);
1278
if (used_tracks[track_channel_type].has(path) && !used_tracks[track_channel_type][path]) {
1279
tracks_to_keep.remove_at(tracks_to_keep.size() - 1);
1280
}
1281
}
1282
}
1283
for (int dst_track_i = 0; dst_track_i < (int)tracks_to_keep.size(); dst_track_i++) {
1284
int src_track_i = tracks_to_keep[dst_track_i];
1285
if (src_track_i != dst_track_i) {
1286
anim->track_swap(src_track_i, dst_track_i);
1287
}
1288
}
1289
for (int track_i = track_count - 1; track_i >= (int)tracks_to_keep.size(); track_i--) {
1290
anim->remove_track(track_i);
1291
}
1292
}
1293
}
1294
1295
bool use_optimizer = node_settings["optimizer/enabled"];
1296
float anim_optimizer_linerr = node_settings["optimizer/max_velocity_error"];
1297
float anim_optimizer_angerr = node_settings["optimizer/max_angular_error"];
1298
int anim_optimizer_preerr = node_settings["optimizer/max_precision_error"];
1299
1300
if (use_optimizer) {
1301
_optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_preerr);
1302
}
1303
1304
bool use_compression = node_settings["compression/enabled"];
1305
int anim_compression_page_size = node_settings["compression/page_size"];
1306
1307
if (use_compression) {
1308
_compress_animations(ap, anim_compression_page_size);
1309
}
1310
1311
for (const StringName &name : anims) {
1312
Ref<Animation> anim = ap->get_animation(name);
1313
Array animation_slices;
1314
1315
if (p_animation_data.has(name)) {
1316
Dictionary anim_settings = p_animation_data[name];
1317
1318
{
1319
int slice_count = anim_settings["slices/amount"];
1320
1321
for (int i = 0; i < slice_count; i++) {
1322
String slice_name = anim_settings["slice_" + itos(i + 1) + "/name"];
1323
int from_frame = anim_settings["slice_" + itos(i + 1) + "/start_frame"];
1324
int end_frame = anim_settings["slice_" + itos(i + 1) + "/end_frame"];
1325
Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)anim_settings["slice_" + itos(i + 1) + "/loop_mode"]);
1326
bool save_to_file = anim_settings["slice_" + itos(i + 1) + "/save_to_file/enabled"];
1327
String save_to_path = anim_settings["slice_" + itos(i + 1) + "/save_to_file/path"];
1328
bool save_to_file_keep_custom = anim_settings["slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
1329
1330
animation_slices.push_back(slice_name);
1331
animation_slices.push_back(from_frame / p_animation_fps);
1332
animation_slices.push_back(end_frame / p_animation_fps);
1333
animation_slices.push_back(loop_mode);
1334
animation_slices.push_back(save_to_file);
1335
animation_slices.push_back(save_to_path);
1336
animation_slices.push_back(save_to_file_keep_custom);
1337
}
1338
1339
if (animation_slices.size() > 0) {
1340
_create_slices(ap, anim, animation_slices, true);
1341
}
1342
}
1343
{
1344
//fill with default values
1345
List<ImportOption> iopts;
1346
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION, &iopts);
1347
for (const ImportOption &F : iopts) {
1348
if (!anim_settings.has(F.option.name)) {
1349
anim_settings[F.option.name] = F.default_value;
1350
}
1351
}
1352
}
1353
1354
anim->set_loop_mode(static_cast<Animation::LoopMode>((int)anim_settings["settings/loop_mode"]));
1355
bool save = anim_settings["save_to_file/enabled"];
1356
String path = anim_settings["save_to_file/path"];
1357
bool keep_custom = anim_settings["save_to_file/keep_custom_tracks"];
1358
1359
Ref<Animation> saved_anim = _save_animation_to_file(anim, save, path, keep_custom);
1360
1361
if (saved_anim != anim) {
1362
Ref<AnimationLibrary> al = ap->get_animation_library(ap->find_animation_library(anim));
1363
al->add_animation(name, saved_anim); //replace
1364
}
1365
}
1366
}
1367
}
1368
1369
return p_node;
1370
}
1371
1372
Node *ResourceImporterScene::_replace_node_with_type_and_script(Node *p_node, String p_node_type, Ref<Script> p_script) {
1373
p_node_type = p_node_type.get_slicec(' ', 0); // Full root_type is "ClassName (filename.gd)" for a script global class.
1374
if (p_script.is_valid()) {
1375
// Ensure the node type supports the script, or pick one that does.
1376
String script_base_type = p_script->get_instance_base_type();
1377
if (ClassDB::is_parent_class(script_base_type, "Node")) {
1378
if (p_node_type.is_empty() || !ClassDB::is_parent_class(p_node_type, script_base_type)) {
1379
p_node_type = script_base_type;
1380
}
1381
}
1382
}
1383
if (!p_node_type.is_empty() && ScriptServer::is_global_class(p_node_type)) {
1384
// If the user specified a script class, we need to get the base node type.
1385
if (p_script.is_null()) {
1386
p_script = ResourceLoader::load(ScriptServer::get_global_class_path(p_node_type));
1387
}
1388
p_node_type = ScriptServer::get_global_class_base(p_node_type);
1389
while (!p_node_type.is_empty()) {
1390
if (ScriptServer::is_global_class(p_node_type)) {
1391
p_node_type = ScriptServer::get_global_class_base(p_node_type);
1392
} else {
1393
break;
1394
}
1395
}
1396
}
1397
if (!p_node_type.is_empty() && p_node->get_class_name() != p_node_type) {
1398
// If the user specified a Godot node type that does not match
1399
// what the scene import gave us, replace the root node.
1400
Node *new_base_node = Object::cast_to<Node>(ClassDB::instantiate(p_node_type));
1401
if (new_base_node) {
1402
List<PropertyInfo> old_properties;
1403
p_node->get_property_list(&old_properties);
1404
for (const PropertyInfo &prop : old_properties) {
1405
if (!(prop.usage & PROPERTY_USAGE_STORAGE)) {
1406
continue;
1407
}
1408
new_base_node->set(prop.name, p_node->get(prop.name));
1409
}
1410
new_base_node->set_name(p_node->get_name());
1411
_copy_meta(p_node, new_base_node);
1412
p_node->replace_by(new_base_node);
1413
p_node->set_owner(nullptr);
1414
memdelete(p_node);
1415
p_node = new_base_node;
1416
}
1417
}
1418
if (p_script.is_valid()) {
1419
p_node->set_script(Variant(p_script));
1420
}
1421
return p_node;
1422
}
1423
1424
Node *ResourceImporterScene::_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, const String &p_source_file, const HashMap<StringName, Variant> &p_options) {
1425
// children first
1426
for (int i = 0; i < p_node->get_child_count(); i++) {
1427
Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_occluder_arrays, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps, p_applied_root_scale, p_source_file, p_options);
1428
if (!r) {
1429
i--; //was erased
1430
}
1431
}
1432
1433
int extract_mat = 0;
1434
if (p_options.has("materials/extract")) {
1435
extract_mat = p_options["materials/extract"];
1436
}
1437
1438
String spath = p_source_file.get_base_dir();
1439
if (p_options.has("materials/extract_path")) {
1440
String extpath = p_options["materials/extract_path"];
1441
if (!extpath.is_empty()) {
1442
spath = extpath;
1443
}
1444
}
1445
1446
bool isroot = p_node == p_root;
1447
1448
String import_id = p_node->get_meta("import_id", "PATH:" + String(p_root->get_path_to(p_node)));
1449
1450
Dictionary node_settings;
1451
if (p_node_data.has(import_id)) {
1452
node_settings = p_node_data[import_id];
1453
}
1454
1455
if (!isroot && (node_settings.has("import/skip_import") && bool(node_settings["import/skip_import"]))) {
1456
p_node->set_owner(nullptr);
1457
memdelete(p_node);
1458
return nullptr;
1459
}
1460
1461
{
1462
//make sure this is unique
1463
node_settings = node_settings.duplicate(true);
1464
//fill node settings for this node with default values
1465
List<ImportOption> iopts;
1466
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
1467
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE, &iopts);
1468
} else if (Object::cast_to<AnimationPlayer>(p_node)) {
1469
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, &iopts);
1470
} else if (Object::cast_to<Skeleton3D>(p_node)) {
1471
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE, &iopts);
1472
} else {
1473
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_NODE, &iopts);
1474
}
1475
for (const ImportOption &E : iopts) {
1476
if (!node_settings.has(E.option.name)) {
1477
node_settings[E.option.name] = E.default_value;
1478
}
1479
}
1480
}
1481
1482
{
1483
ObjectID node_id = p_node->get_instance_id();
1484
for (int i = 0; i < post_importer_plugins.size(); i++) {
1485
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_NODE, p_root, p_node, Ref<Resource>(), node_settings);
1486
if (ObjectDB::get_instance(node_id) == nullptr) { //may have been erased, so do not continue
1487
break;
1488
}
1489
}
1490
}
1491
1492
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
1493
ObjectID node_id = p_node->get_instance_id();
1494
for (int i = 0; i < post_importer_plugins.size(); i++) {
1495
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE, p_root, p_node, Ref<Resource>(), node_settings);
1496
if (ObjectDB::get_instance(node_id) == nullptr) { //may have been erased, so do not continue
1497
break;
1498
}
1499
}
1500
}
1501
1502
if (Object::cast_to<Skeleton3D>(p_node)) {
1503
Ref<Animation> rest_animation;
1504
float rest_animation_timestamp = 0.0;
1505
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
1506
if (skeleton != nullptr && int(node_settings.get("rest_pose/load_pose", 0)) != 0) {
1507
String selected_animation_name = node_settings.get("rest_pose/selected_animation", String());
1508
if (int(node_settings["rest_pose/load_pose"]) == 1) {
1509
TypedArray<Node> children = p_root->find_children("*", "AnimationPlayer", true, false);
1510
for (int node_i = 0; node_i < children.size(); node_i++) {
1511
AnimationPlayer *anim_player = cast_to<AnimationPlayer>(children[node_i]);
1512
ERR_CONTINUE(anim_player == nullptr);
1513
List<StringName> anim_list;
1514
anim_player->get_animation_list(&anim_list);
1515
if (anim_list.size() == 1) {
1516
selected_animation_name = anim_list.front()->get();
1517
}
1518
rest_animation = anim_player->get_animation(selected_animation_name);
1519
if (rest_animation.is_valid()) {
1520
break;
1521
}
1522
}
1523
} else if (int(node_settings["rest_pose/load_pose"]) == 2) {
1524
Object *external_object = node_settings.get("rest_pose/external_animation_library", Variant());
1525
rest_animation = external_object;
1526
if (rest_animation.is_null()) {
1527
Ref<AnimationLibrary> library(external_object);
1528
if (library.is_valid()) {
1529
List<StringName> anim_list;
1530
library->get_animation_list(&anim_list);
1531
if (anim_list.size() == 1) {
1532
selected_animation_name = String(anim_list.front()->get());
1533
}
1534
rest_animation = library->get_animation(selected_animation_name);
1535
}
1536
}
1537
}
1538
rest_animation_timestamp = double(node_settings.get("rest_pose/selected_timestamp", 0.0));
1539
if (rest_animation.is_valid()) {
1540
for (int track_i = 0; track_i < rest_animation->get_track_count(); track_i++) {
1541
NodePath path = rest_animation->track_get_path(track_i);
1542
StringName node_path = path.get_concatenated_names();
1543
if (String(node_path).begins_with("%")) {
1544
continue; // Unique node names are commonly used with retargeted animations, which we do not want to use.
1545
}
1546
StringName skeleton_bone = path.get_concatenated_subnames();
1547
if (skeleton_bone == StringName()) {
1548
continue;
1549
}
1550
int bone_idx = skeleton->find_bone(skeleton_bone);
1551
if (bone_idx == -1) {
1552
continue;
1553
}
1554
switch (rest_animation->track_get_type(track_i)) {
1555
case Animation::TYPE_POSITION_3D: {
1556
Vector3 bone_position = rest_animation->position_track_interpolate(track_i, rest_animation_timestamp);
1557
skeleton->set_bone_rest(bone_idx, Transform3D(skeleton->get_bone_rest(bone_idx).basis, bone_position));
1558
} break;
1559
case Animation::TYPE_ROTATION_3D: {
1560
Quaternion bone_rotation = rest_animation->rotation_track_interpolate(track_i, rest_animation_timestamp);
1561
Transform3D current_rest = skeleton->get_bone_rest(bone_idx);
1562
skeleton->set_bone_rest(bone_idx, Transform3D(Basis(bone_rotation).scaled(current_rest.basis.get_scale()), current_rest.origin));
1563
} break;
1564
default:
1565
break;
1566
}
1567
}
1568
}
1569
}
1570
1571
ObjectID node_id = p_node->get_instance_id();
1572
for (int i = 0; i < post_importer_plugins.size(); i++) {
1573
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE, p_root, p_node, Ref<Resource>(), node_settings);
1574
if (ObjectDB::get_instance(node_id) == nullptr) { //may have been erased, so do not continue
1575
break;
1576
}
1577
}
1578
}
1579
1580
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
1581
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
1582
1583
Ref<ImporterMesh> m = mi->get_mesh();
1584
1585
if (m.is_valid()) {
1586
if (!r_scanned_meshes.has(m)) {
1587
for (int i = 0; i < m->get_surface_count(); i++) {
1588
Ref<Material> mat = m->get_surface_material(i);
1589
if (mat.is_valid()) {
1590
String mat_id = mat->get_meta("import_id", mat->get_name());
1591
if (!mat_id.is_empty() && p_material_data.has(mat_id)) {
1592
Dictionary matdata = p_material_data[mat_id];
1593
{
1594
//fill node settings for this node with default values
1595
List<ImportOption> iopts;
1596
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_MATERIAL, &iopts);
1597
for (const ImportOption &E : iopts) {
1598
if (!matdata.has(E.option.name)) {
1599
matdata[E.option.name] = E.default_value;
1600
}
1601
}
1602
}
1603
1604
for (int j = 0; j < post_importer_plugins.size(); j++) {
1605
post_importer_plugins.write[j]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MATERIAL, p_root, p_node, mat, matdata);
1606
}
1607
}
1608
if (!mat_id.is_empty() && extract_mat != 0) {
1609
String ext = material_extension[p_options.has("materials/extract_format") ? (int)p_options["materials/extract_format"] : 0];
1610
String path = spath.path_join(mat_id.validate_filename() + ext);
1611
String uid_path = ResourceUID::path_to_uid(path);
1612
1613
Dictionary matdata = p_material_data[mat_id];
1614
matdata["use_external/enabled"] = true;
1615
matdata["use_external/path"] = uid_path;
1616
matdata["use_external/fallback_path"] = path;
1617
if (!FileAccess::exists(path) || extract_mat == 2 /*overwrite*/) {
1618
ResourceSaver::save(mat, path);
1619
}
1620
1621
Ref<Material> external_mat = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE);
1622
if (external_mat.is_valid()) {
1623
m->set_surface_material(i, external_mat);
1624
}
1625
}
1626
if (!mat_id.is_empty() && p_material_data.has(mat_id)) {
1627
Dictionary matdata = p_material_data[mat_id];
1628
if (matdata.has("use_external/enabled") && bool(matdata["use_external/enabled"]) && matdata.has("use_external/path")) {
1629
String path = matdata["use_external/path"];
1630
Ref<Material> external_mat = ResourceLoader::load(path);
1631
if (external_mat.is_null()) {
1632
if (matdata.has("use_external/fallback_path")) {
1633
String fallback_save_path = matdata["use_external/fallback_path"];
1634
if (!fallback_save_path.is_empty()) {
1635
external_mat = ResourceLoader::load(fallback_save_path);
1636
if (external_mat.is_valid()) {
1637
path = fallback_save_path;
1638
}
1639
}
1640
}
1641
}
1642
if (external_mat.is_valid()) {
1643
m->set_surface_material(i, external_mat);
1644
if (!path.begins_with("uid://")) {
1645
const ResourceUID::ID id = ResourceLoader::get_resource_uid(path);
1646
if (id != ResourceUID::INVALID_ID) {
1647
matdata["use_external/path"] = ResourceUID::get_singleton()->id_to_text(id);
1648
}
1649
}
1650
matdata["use_external/fallback_path"] = external_mat->get_path();
1651
}
1652
}
1653
}
1654
}
1655
}
1656
1657
r_scanned_meshes.insert(m);
1658
}
1659
1660
if (node_settings.has("generate/physics")) {
1661
int mesh_physics_mode = MeshPhysicsMode::MESH_PHYSICS_DISABLED;
1662
1663
const bool generate_collider = node_settings["generate/physics"];
1664
if (generate_collider) {
1665
mesh_physics_mode = MeshPhysicsMode::MESH_PHYSICS_MESH_AND_STATIC_COLLIDER;
1666
if (node_settings.has("physics/body_type")) {
1667
const BodyType body_type = (BodyType)node_settings["physics/body_type"].operator int();
1668
switch (body_type) {
1669
case BODY_TYPE_STATIC:
1670
mesh_physics_mode = MeshPhysicsMode::MESH_PHYSICS_MESH_AND_STATIC_COLLIDER;
1671
break;
1672
case BODY_TYPE_DYNAMIC:
1673
mesh_physics_mode = MeshPhysicsMode::MESH_PHYSICS_RIGID_BODY_AND_MESH;
1674
break;
1675
case BODY_TYPE_AREA:
1676
mesh_physics_mode = MeshPhysicsMode::MESH_PHYSICS_AREA_ONLY;
1677
break;
1678
}
1679
}
1680
}
1681
1682
if (mesh_physics_mode != MeshPhysicsMode::MESH_PHYSICS_DISABLED) {
1683
Vector<Ref<Shape3D>> shapes;
1684
if (collision_map.has(m)) {
1685
shapes = collision_map[m];
1686
} else {
1687
shapes = get_collision_shapes(
1688
m,
1689
node_settings,
1690
p_applied_root_scale);
1691
}
1692
1693
if (shapes.size()) {
1694
CollisionObject3D *base = nullptr;
1695
switch (mesh_physics_mode) {
1696
case MESH_PHYSICS_MESH_AND_STATIC_COLLIDER: {
1697
StaticBody3D *col = memnew(StaticBody3D);
1698
p_node->add_child(col, true);
1699
col->set_owner(p_node->get_owner());
1700
col->set_transform(get_collision_shapes_transform(node_settings));
1701
col->set_position(p_applied_root_scale * col->get_position());
1702
const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
1703
if (pmo.is_valid()) {
1704
col->set_physics_material_override(pmo);
1705
}
1706
base = col;
1707
} break;
1708
case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
1709
RigidBody3D *rigid_body = memnew(RigidBody3D);
1710
rigid_body->set_name(p_node->get_name());
1711
_copy_meta(p_node, rigid_body);
1712
p_node->replace_by(rigid_body);
1713
rigid_body->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings));
1714
rigid_body->set_position(p_applied_root_scale * rigid_body->get_position());
1715
p_node = rigid_body;
1716
mi->set_transform(Transform3D());
1717
rigid_body->add_child(mi, true);
1718
mi->set_owner(rigid_body->get_owner());
1719
const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
1720
if (pmo.is_valid()) {
1721
rigid_body->set_physics_material_override(pmo);
1722
}
1723
base = rigid_body;
1724
} break;
1725
case MESH_PHYSICS_STATIC_COLLIDER_ONLY: {
1726
StaticBody3D *col = memnew(StaticBody3D);
1727
col->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings));
1728
col->set_position(p_applied_root_scale * col->get_position());
1729
col->set_name(p_node->get_name());
1730
_copy_meta(p_node, col);
1731
p_node->replace_by(col);
1732
p_node->set_owner(nullptr);
1733
memdelete(p_node);
1734
p_node = col;
1735
const Ref<PhysicsMaterial> &pmo = node_settings["physics/physics_material_override"];
1736
if (pmo.is_valid()) {
1737
col->set_physics_material_override(pmo);
1738
}
1739
base = col;
1740
} break;
1741
case MESH_PHYSICS_AREA_ONLY: {
1742
Area3D *area = memnew(Area3D);
1743
area->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings));
1744
area->set_position(p_applied_root_scale * area->get_position());
1745
area->set_name(p_node->get_name());
1746
_copy_meta(p_node, area);
1747
p_node->replace_by(area);
1748
p_node->set_owner(nullptr);
1749
memdelete(p_node);
1750
p_node = area;
1751
base = area;
1752
1753
} break;
1754
}
1755
1756
base->set_collision_layer(node_settings["physics/layer"]);
1757
base->set_collision_mask(node_settings["physics/mask"]);
1758
1759
for (const Ref<Shape3D> &E : shapes) {
1760
CollisionShape3D *cshape = memnew(CollisionShape3D);
1761
cshape->set_shape(E);
1762
base->add_child(cshape, true);
1763
1764
cshape->set_owner(base->get_owner());
1765
}
1766
}
1767
}
1768
}
1769
}
1770
}
1771
1772
//navmesh (node may have changed type above)
1773
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
1774
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
1775
1776
Ref<ImporterMesh> m = mi->get_mesh();
1777
1778
if (m.is_valid()) {
1779
if (node_settings.has("generate/navmesh")) {
1780
int navmesh_mode = node_settings["generate/navmesh"];
1781
1782
if (navmesh_mode != NAVMESH_DISABLED) {
1783
NavigationRegion3D *nmi = memnew(NavigationRegion3D);
1784
1785
Ref<NavigationMesh> nmesh = m->create_navigation_mesh();
1786
nmi->set_navigation_mesh(nmesh);
1787
1788
if (navmesh_mode == NAVMESH_NAVMESH_ONLY) {
1789
nmi->set_transform(mi->get_transform());
1790
_copy_meta(p_node, nmi);
1791
p_node->replace_by(nmi);
1792
p_node->set_owner(nullptr);
1793
memdelete(p_node);
1794
p_node = nmi;
1795
} else {
1796
mi->add_child(nmi, true);
1797
nmi->set_owner(mi->get_owner());
1798
}
1799
}
1800
}
1801
}
1802
}
1803
1804
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
1805
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
1806
1807
Ref<ImporterMesh> m = mi->get_mesh();
1808
1809
if (m.is_valid()) {
1810
if (node_settings.has("generate/occluder")) {
1811
int occluder_mode = node_settings["generate/occluder"];
1812
1813
if (occluder_mode != OCCLUDER_DISABLED) {
1814
float simplification_dist = 0.0f;
1815
if (node_settings.has("occluder/simplification_distance")) {
1816
simplification_dist = node_settings["occluder/simplification_distance"];
1817
}
1818
1819
OccluderInstance3D::bake_single_node(mi, simplification_dist, r_occluder_arrays.first, r_occluder_arrays.second);
1820
1821
if (occluder_mode == OCCLUDER_OCCLUDER_ONLY) {
1822
p_node->set_owner(nullptr);
1823
memdelete(p_node);
1824
p_node = nullptr;
1825
}
1826
}
1827
}
1828
}
1829
}
1830
1831
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
1832
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
1833
1834
if (node_settings.has("mesh_instance/layers")) {
1835
mi->set_layer_mask(node_settings["mesh_instance/layers"]);
1836
}
1837
1838
if (node_settings.has("mesh_instance/visibility_range_begin")) {
1839
mi->set_visibility_range_begin(node_settings["mesh_instance/visibility_range_begin"]);
1840
}
1841
1842
if (node_settings.has("mesh_instance/visibility_range_begin_margin")) {
1843
mi->set_visibility_range_begin_margin(node_settings["mesh_instance/visibility_range_begin_margin"]);
1844
}
1845
1846
if (node_settings.has("mesh_instance/visibility_range_end")) {
1847
mi->set_visibility_range_end(node_settings["mesh_instance/visibility_range_end"]);
1848
}
1849
1850
if (node_settings.has("mesh_instance/visibility_range_end_margin")) {
1851
mi->set_visibility_range_end_margin(node_settings["mesh_instance/visibility_range_end_margin"]);
1852
}
1853
1854
if (node_settings.has("mesh_instance/visibility_range_fade_mode")) {
1855
const GeometryInstance3D::VisibilityRangeFadeMode range_fade_mode = (GeometryInstance3D::VisibilityRangeFadeMode)node_settings["mesh_instance/visibility_range_fade_mode"].operator int();
1856
mi->set_visibility_range_fade_mode(range_fade_mode);
1857
}
1858
1859
if (node_settings.has("mesh_instance/cast_shadow")) {
1860
const GeometryInstance3D::ShadowCastingSetting cast_shadows = (GeometryInstance3D::ShadowCastingSetting)node_settings["mesh_instance/cast_shadow"].operator int();
1861
mi->set_cast_shadows_setting(cast_shadows);
1862
}
1863
}
1864
1865
if (Object::cast_to<AnimationPlayer>(p_node)) {
1866
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
1867
1868
for (int i = 0; i < post_importer_plugins.size(); i++) {
1869
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, p_root, p_node, Ref<Resource>(), node_settings);
1870
}
1871
1872
if (post_importer_plugins.size()) {
1873
List<StringName> anims;
1874
ap->get_animation_list(&anims);
1875
for (const StringName &name : anims) {
1876
if (p_animation_data.has(name)) {
1877
Ref<Animation> anim = ap->get_animation(name);
1878
Dictionary anim_settings = p_animation_data[name];
1879
{
1880
//fill with default values
1881
List<ImportOption> iopts;
1882
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION, &iopts);
1883
for (const ImportOption &F : iopts) {
1884
if (!anim_settings.has(F.option.name)) {
1885
anim_settings[F.option.name] = F.default_value;
1886
}
1887
}
1888
}
1889
1890
for (int i = 0; i < post_importer_plugins.size(); i++) {
1891
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION, p_root, p_node, anim, anim_settings);
1892
}
1893
}
1894
}
1895
}
1896
}
1897
1898
String node_type = node_settings.get("node/node_type", "");
1899
Ref<Script> node_script = node_settings.get("node/script", Ref<Script>());
1900
p_node = _replace_node_with_type_and_script(p_node, node_type, node_script);
1901
1902
return p_node;
1903
}
1904
1905
Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, const String &p_save_to_path, bool p_keep_custom_tracks) {
1906
String res_path = ResourceUID::ensure_path(p_save_to_path);
1907
if (!p_save_to_file || !res_path.is_resource_file()) {
1908
return anim;
1909
}
1910
1911
if (FileAccess::exists(res_path) && p_keep_custom_tracks) {
1912
// Copy custom animation tracks from previously imported files.
1913
Ref<Animation> old_anim = ResourceLoader::load(res_path, "Animation", ResourceFormatLoader::CACHE_MODE_IGNORE);
1914
if (old_anim.is_valid()) {
1915
for (int i = 0; i < old_anim->get_track_count(); i++) {
1916
if (!old_anim->track_is_imported(i)) {
1917
old_anim->copy_track(i, anim);
1918
}
1919
}
1920
anim->set_loop_mode(old_anim->get_loop_mode());
1921
}
1922
}
1923
1924
if (ResourceCache::has(res_path)) {
1925
Ref<Animation> old_anim = ResourceCache::get_ref(res_path);
1926
if (old_anim.is_valid()) {
1927
old_anim->copy_from(anim);
1928
anim = old_anim;
1929
}
1930
}
1931
anim->set_path(res_path, true); // Set path to save externally.
1932
Error err = ResourceSaver::save(anim, res_path, ResourceSaver::FLAG_CHANGE_PATH);
1933
1934
ERR_FAIL_COND_V_MSG(err != OK, anim, "Saving of animation failed: " + res_path);
1935
if (p_save_to_path.begins_with("uid://")) {
1936
// slow
1937
ResourceSaver::set_uid(res_path, ResourceUID::get_singleton()->text_to_id(p_save_to_path));
1938
}
1939
return anim;
1940
}
1941
1942
void ResourceImporterScene::_create_slices(AnimationPlayer *ap, Ref<Animation> anim, const Array &p_slices, bool p_bake_all) {
1943
Ref<AnimationLibrary> al = ap->get_animation_library(ap->find_animation_library(anim));
1944
1945
for (int i = 0; i < p_slices.size(); i += 7) {
1946
String name = p_slices[i];
1947
float from = p_slices[i + 1];
1948
float to = p_slices[i + 2];
1949
Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)p_slices[i + 3]);
1950
bool save_to_file = p_slices[i + 4];
1951
String save_to_path = p_slices[i + 5];
1952
bool keep_current = p_slices[i + 6];
1953
if (from >= to) {
1954
continue;
1955
}
1956
1957
Ref<Animation> new_anim = memnew(Animation);
1958
1959
for (int j = 0; j < anim->get_track_count(); j++) {
1960
List<float> keys;
1961
int kc = anim->track_get_key_count(j);
1962
int dtrack = -1;
1963
for (int k = 0; k < kc; k++) {
1964
float kt = anim->track_get_key_time(j, k);
1965
if (kt >= from && kt < to) {
1966
//found a key within range, so create track
1967
if (dtrack == -1) {
1968
new_anim->add_track(anim->track_get_type(j));
1969
dtrack = new_anim->get_track_count() - 1;
1970
new_anim->track_set_path(dtrack, anim->track_get_path(j));
1971
new_anim->track_set_imported(dtrack, true);
1972
1973
if (kt > (from + 0.01) && k > 0) {
1974
if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
1975
Vector3 p;
1976
anim->try_position_track_interpolate(j, from, &p);
1977
new_anim->position_track_insert_key(dtrack, 0, p);
1978
} else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
1979
Quaternion r;
1980
anim->try_rotation_track_interpolate(j, from, &r);
1981
new_anim->rotation_track_insert_key(dtrack, 0, r);
1982
} else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
1983
Vector3 s;
1984
anim->try_scale_track_interpolate(j, from, &s);
1985
new_anim->scale_track_insert_key(dtrack, 0, s);
1986
} else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
1987
Variant var = anim->value_track_interpolate(j, from);
1988
new_anim->track_insert_key(dtrack, 0, var);
1989
} else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
1990
float interp;
1991
anim->try_blend_shape_track_interpolate(j, from, &interp);
1992
new_anim->blend_shape_track_insert_key(dtrack, 0, interp);
1993
}
1994
}
1995
}
1996
1997
if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
1998
Vector3 p;
1999
anim->position_track_get_key(j, k, &p);
2000
new_anim->position_track_insert_key(dtrack, kt - from, p);
2001
} else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
2002
Quaternion r;
2003
anim->rotation_track_get_key(j, k, &r);
2004
new_anim->rotation_track_insert_key(dtrack, kt - from, r);
2005
} else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
2006
Vector3 s;
2007
anim->scale_track_get_key(j, k, &s);
2008
new_anim->scale_track_insert_key(dtrack, kt - from, s);
2009
} else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
2010
Variant var = anim->track_get_key_value(j, k);
2011
new_anim->track_insert_key(dtrack, kt - from, var);
2012
} else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
2013
float interp;
2014
anim->blend_shape_track_get_key(j, k, &interp);
2015
new_anim->blend_shape_track_insert_key(dtrack, kt - from, interp);
2016
}
2017
}
2018
2019
if (dtrack != -1 && kt >= to) {
2020
if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
2021
Vector3 p;
2022
anim->try_position_track_interpolate(j, to, &p);
2023
new_anim->position_track_insert_key(dtrack, to - from, p);
2024
} else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
2025
Quaternion r;
2026
anim->try_rotation_track_interpolate(j, to, &r);
2027
new_anim->rotation_track_insert_key(dtrack, to - from, r);
2028
} else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
2029
Vector3 s;
2030
anim->try_scale_track_interpolate(j, to, &s);
2031
new_anim->scale_track_insert_key(dtrack, to - from, s);
2032
} else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
2033
Variant var = anim->value_track_interpolate(j, to);
2034
new_anim->track_insert_key(dtrack, to - from, var);
2035
} else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
2036
float interp;
2037
anim->try_blend_shape_track_interpolate(j, to, &interp);
2038
new_anim->blend_shape_track_insert_key(dtrack, to - from, interp);
2039
}
2040
}
2041
}
2042
2043
if (dtrack == -1 && p_bake_all) {
2044
new_anim->add_track(anim->track_get_type(j));
2045
dtrack = new_anim->get_track_count() - 1;
2046
new_anim->track_set_path(dtrack, anim->track_get_path(j));
2047
new_anim->track_set_imported(dtrack, true);
2048
if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
2049
Vector3 p;
2050
anim->try_position_track_interpolate(j, from, &p);
2051
new_anim->position_track_insert_key(dtrack, 0, p);
2052
anim->try_position_track_interpolate(j, to, &p);
2053
new_anim->position_track_insert_key(dtrack, to - from, p);
2054
} else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
2055
Quaternion r;
2056
anim->try_rotation_track_interpolate(j, from, &r);
2057
new_anim->rotation_track_insert_key(dtrack, 0, r);
2058
anim->try_rotation_track_interpolate(j, to, &r);
2059
new_anim->rotation_track_insert_key(dtrack, to - from, r);
2060
} else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
2061
Vector3 s;
2062
anim->try_scale_track_interpolate(j, from, &s);
2063
new_anim->scale_track_insert_key(dtrack, 0, s);
2064
anim->try_scale_track_interpolate(j, to, &s);
2065
new_anim->scale_track_insert_key(dtrack, to - from, s);
2066
} else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
2067
Variant var = anim->value_track_interpolate(j, from);
2068
new_anim->track_insert_key(dtrack, 0, var);
2069
Variant to_var = anim->value_track_interpolate(j, to);
2070
new_anim->track_insert_key(dtrack, to - from, to_var);
2071
} else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
2072
float interp;
2073
anim->try_blend_shape_track_interpolate(j, from, &interp);
2074
new_anim->blend_shape_track_insert_key(dtrack, 0, interp);
2075
anim->try_blend_shape_track_interpolate(j, to, &interp);
2076
new_anim->blend_shape_track_insert_key(dtrack, to - from, interp);
2077
}
2078
}
2079
}
2080
2081
new_anim->set_name(name);
2082
new_anim->set_loop_mode(loop_mode);
2083
new_anim->set_length(to - from);
2084
new_anim->set_step(anim->get_step());
2085
2086
al->add_animation(name, new_anim);
2087
2088
Ref<Animation> saved_anim = _save_animation_to_file(new_anim, save_to_file, save_to_path, keep_current);
2089
if (saved_anim != new_anim) {
2090
al->add_animation(name, saved_anim);
2091
}
2092
}
2093
2094
al->remove_animation(ap->find_animation(anim)); // Remove original animation (no longer needed).
2095
}
2096
2097
void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error) {
2098
List<StringName> anim_names;
2099
anim->get_animation_list(&anim_names);
2100
for (const StringName &E : anim_names) {
2101
Ref<Animation> a = anim->get_animation(E);
2102
a->optimize(p_max_vel_error, p_max_ang_error, p_prc_error);
2103
}
2104
}
2105
2106
void ResourceImporterScene::_compress_animations(AnimationPlayer *anim, int p_page_size_kb) {
2107
List<StringName> anim_names;
2108
anim->get_animation_list(&anim_names);
2109
for (const StringName &E : anim_names) {
2110
Ref<Animation> a = anim->get_animation(E);
2111
a->compress(p_page_size_kb * 1024);
2112
}
2113
}
2114
2115
void ResourceImporterScene::get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const {
2116
switch (p_category) {
2117
case INTERNAL_IMPORT_CATEGORY_NODE: {
2118
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "node/node_type", PROPERTY_HINT_TYPE_STRING, "Node"), ""));
2119
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "node/script", PROPERTY_HINT_RESOURCE_TYPE, "Script"), Variant()));
2120
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2121
} break;
2122
case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
2123
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "node/script", PROPERTY_HINT_RESOURCE_TYPE, "Script"), Variant()));
2124
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2125
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate/physics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2126
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/navmesh", PROPERTY_HINT_ENUM, "Disabled,Mesh + NavMesh,NavMesh Only"), 0));
2127
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/body_type", PROPERTY_HINT_ENUM, "Static,Dynamic,Area"), 0));
2128
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/shape_type", PROPERTY_HINT_ENUM, "Decompose Convex,Simple Convex,Trimesh,Box,Sphere,Cylinder,Capsule,Automatic", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 7));
2129
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "physics/physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), Variant()));
2130
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), 1));
2131
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "physics/mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), 1));
2132
2133
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mesh_instance/layers", PROPERTY_HINT_LAYERS_3D_RENDER), 1));
2134
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "mesh_instance/visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), 0.0f));
2135
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "mesh_instance/visibility_range_begin_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), 0.0f));
2136
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "mesh_instance/visibility_range_end", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), 0.0f));
2137
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "mesh_instance/visibility_range_end_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), 0.0f));
2138
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mesh_instance/visibility_range_fade_mode", PROPERTY_HINT_ENUM, "Disabled,Self,Dependencies"), GeometryInstance3D::VISIBILITY_RANGE_FADE_DISABLED));
2139
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mesh_instance/cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), GeometryInstance3D::SHADOW_CASTING_SETTING_ON));
2140
2141
// Decomposition
2142
Ref<MeshConvexDecompositionSettings> decomposition_default = Ref<MeshConvexDecompositionSettings>();
2143
decomposition_default.instantiate();
2144
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/advanced", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2145
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/precision", PROPERTY_HINT_RANGE, "1,10,1"), 5));
2146
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/max_concavity", PROPERTY_HINT_RANGE, "0.0,1.0,0.001", PROPERTY_USAGE_DEFAULT), decomposition_default->get_max_concavity()));
2147
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), decomposition_default->get_symmetry_planes_clipping_bias()));
2148
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), decomposition_default->get_revolution_axes_clipping_bias()));
2149
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "decomposition/min_volume_per_convex_hull", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_min_volume_per_convex_hull()));
2150
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/resolution", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_resolution()));
2151
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_num_vertices_per_convex_hull", PROPERTY_HINT_RANGE, "5,512,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_max_num_vertices_per_convex_hull()));
2152
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/plane_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_plane_downsampling()));
2153
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/convexhull_downsampling", PROPERTY_HINT_RANGE, "1,16,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_convex_hull_downsampling()));
2154
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/normalize_mesh", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_normalize_mesh()));
2155
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/mode", PROPERTY_HINT_ENUM, "Voxel,Tetrahedron", PROPERTY_USAGE_DEFAULT), static_cast<int>(decomposition_default->get_mode())));
2156
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/convexhull_approximation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_convex_hull_approximation()));
2157
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "decomposition/max_convex_hulls", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT), decomposition_default->get_max_convex_hulls()));
2158
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "decomposition/project_hull_vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), decomposition_default->get_project_hull_vertices()));
2159
2160
// Primitives: Box, Sphere, Cylinder, Capsule.
2161
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), Vector3(2.0, 2.0, 2.0)));
2162
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "primitive/height", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), 1.0));
2163
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "primitive/radius", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), 1.0));
2164
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), Vector3()));
2165
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT), Vector3()));
2166
2167
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/occluder", PROPERTY_HINT_ENUM, "Disabled,Mesh + Occluder,Occluder Only", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
2168
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "occluder/simplification_distance", PROPERTY_HINT_RANGE, "0.0,2.0,0.01", PROPERTY_USAGE_DEFAULT), 0.1f));
2169
} break;
2170
case INTERNAL_IMPORT_CATEGORY_MESH: {
2171
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2172
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
2173
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
2174
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/shadow_meshes", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
2175
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lightmap_uv", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
2176
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lods", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
2177
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lods/normal_merge_angle", PROPERTY_HINT_RANGE, "0,180,1,degrees"), 20.0f));
2178
} break;
2179
case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
2180
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "use_external/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2181
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/path", PROPERTY_HINT_FILE, "*.material,*.res,*.tres"), ""));
2182
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
2183
} break;
2184
case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
2185
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "settings/loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Pingpong"), 0));
2186
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2187
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.anim,*.tres"), ""));
2188
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
2189
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/keep_custom_tracks"), ""));
2190
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
2191
2192
for (int i = 0; i < 256; i++) {
2193
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/name"), ""));
2194
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/start_frame"), 0));
2195
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
2196
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Pingpong"), 0));
2197
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2198
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.anim,*.tres"), ""));
2199
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
2200
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
2201
}
2202
} break;
2203
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
2204
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "node/script", PROPERTY_HINT_RESOURCE_TYPE, "Script"), Variant()));
2205
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2206
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
2207
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_velocity_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01));
2208
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01));
2209
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "optimizer/max_precision_error", PROPERTY_HINT_NONE, "1,6,1"), 3));
2210
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compression/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2211
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compression/page_size", PROPERTY_HINT_RANGE, "4,512,1,suffix:kb"), 8));
2212
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
2213
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/rotation", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
2214
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/scale", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
2215
} break;
2216
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
2217
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "node/script", PROPERTY_HINT_RESOURCE_TYPE, "Script"), Variant()));
2218
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
2219
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "rest_pose/load_pose", PROPERTY_HINT_ENUM, "Default Pose,Use AnimationPlayer,Load External Animation", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
2220
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "rest_pose/external_animation_library", PROPERTY_HINT_RESOURCE_TYPE, "Animation,AnimationLibrary", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant()));
2221
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "rest_pose/selected_animation", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), ""));
2222
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "rest_pose/selected_timestamp", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT), 0.0f));
2223
String mismatched_or_empty_profile_warning = String(
2224
"The external rest animation is missing some bones. "
2225
"Consider disabling Remove Immutable Tracks on the other file."); // TODO: translate.
2226
r_options->push_back(ImportOption(
2227
PropertyInfo(
2228
Variant::STRING, U"rest_pose/\u26A0_validation_warning/mismatched_or_empty_profile",
2229
PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY),
2230
Variant(mismatched_or_empty_profile_warning)));
2231
String profile_must_not_be_retargeted_warning = String(
2232
"This external rest animation appears to have been imported with a BoneMap. "
2233
"Disable the bone map when exporting a rest animation from the reference model."); // TODO: translate.
2234
r_options->push_back(ImportOption(
2235
PropertyInfo(
2236
Variant::STRING, U"rest_pose/\u26A0_validation_warning/profile_must_not_be_retargeted",
2237
PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY),
2238
Variant(profile_must_not_be_retargeted_warning)));
2239
String no_animation_warning = String(
2240
"Select an animation: Find a FBX or glTF in a compatible rest pose "
2241
"and export a compatible animation from its import settings."); // TODO: translate.
2242
r_options->push_back(ImportOption(
2243
PropertyInfo(
2244
Variant::STRING, U"rest_pose//no_animation_chosen",
2245
PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY),
2246
Variant(no_animation_warning)));
2247
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "retarget/bone_map", PROPERTY_HINT_RESOURCE_TYPE, "BoneMap", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant()));
2248
} break;
2249
default: {
2250
}
2251
}
2252
2253
for (int i = 0; i < post_importer_plugins.size(); i++) {
2254
post_importer_plugins.write[i]->get_internal_import_options(EditorScenePostImportPlugin::InternalImportCategory(p_category), r_options);
2255
}
2256
}
2257
2258
bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
2259
if (p_options.has("import/skip_import") && p_option != "import/skip_import" && bool(p_options["import/skip_import"])) {
2260
return false; //if skip import
2261
}
2262
switch (p_category) {
2263
case INTERNAL_IMPORT_CATEGORY_NODE: {
2264
} break;
2265
case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
2266
const bool generate_physics =
2267
p_options.has("generate/physics") &&
2268
p_options["generate/physics"].operator bool();
2269
2270
if (p_option.contains("physics/")) {
2271
// Show if need to generate collisions.
2272
return generate_physics;
2273
}
2274
2275
if (p_option.contains("decomposition/")) {
2276
// Show if need to generate collisions.
2277
if (generate_physics &&
2278
// Show if convex is enabled.
2279
p_options["physics/shape_type"] == Variant(SHAPE_TYPE_DECOMPOSE_CONVEX)) {
2280
if (p_option == "decomposition/advanced") {
2281
return true;
2282
}
2283
2284
const bool decomposition_advanced =
2285
p_options.has("decomposition/advanced") &&
2286
p_options["decomposition/advanced"].operator bool();
2287
2288
if (p_option == "decomposition/precision") {
2289
return !decomposition_advanced;
2290
} else {
2291
return decomposition_advanced;
2292
}
2293
}
2294
2295
return false;
2296
}
2297
2298
if (p_option == "primitive/position" || p_option == "primitive/rotation") {
2299
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
2300
return generate_physics &&
2301
physics_shape >= SHAPE_TYPE_BOX;
2302
}
2303
2304
if (p_option == "primitive/size") {
2305
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
2306
return generate_physics &&
2307
physics_shape == SHAPE_TYPE_BOX;
2308
}
2309
2310
if (p_option == "primitive/radius") {
2311
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
2312
return generate_physics &&
2313
(physics_shape == SHAPE_TYPE_SPHERE ||
2314
physics_shape == SHAPE_TYPE_CYLINDER ||
2315
physics_shape == SHAPE_TYPE_CAPSULE);
2316
}
2317
2318
if (p_option == "primitive/height") {
2319
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
2320
return generate_physics &&
2321
(physics_shape == SHAPE_TYPE_CYLINDER ||
2322
physics_shape == SHAPE_TYPE_CAPSULE);
2323
}
2324
2325
if (p_option == "occluder/simplification_distance") {
2326
// Show only if occluder generation is enabled
2327
return p_options.has("generate/occluder") && p_options["generate/occluder"].operator signed int() != OCCLUDER_DISABLED;
2328
}
2329
} break;
2330
case INTERNAL_IMPORT_CATEGORY_MESH: {
2331
if (p_option == "save_to_file/path") {
2332
return p_options["save_to_file/enabled"];
2333
}
2334
} break;
2335
case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
2336
if (p_option == "use_external/path") {
2337
return p_options["use_external/enabled"];
2338
}
2339
} break;
2340
case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
2341
if (p_option == "save_to_file/path" || p_option == "save_to_file/keep_custom_tracks") {
2342
return p_options["save_to_file/enabled"];
2343
}
2344
if (p_option.begins_with("slice_")) {
2345
int max_slice = p_options["slices/amount"];
2346
int slice = p_option.get_slicec('_', 1).to_int() - 1;
2347
if (slice >= max_slice) {
2348
return false;
2349
}
2350
}
2351
} break;
2352
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
2353
if (p_option.begins_with("optimizer/") && p_option != "optimizer/enabled" && !bool(p_options["optimizer/enabled"])) {
2354
return false;
2355
}
2356
if (p_option.begins_with("compression/") && p_option != "compression/enabled" && !bool(p_options["compression/enabled"])) {
2357
return false;
2358
}
2359
} break;
2360
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
2361
const bool use_retarget = Object::cast_to<BoneMap>(p_options["retarget/bone_map"].get_validated_object()) != nullptr;
2362
if (!use_retarget && p_option != "retarget/bone_map" && p_option.begins_with("retarget/")) {
2363
return false;
2364
}
2365
int rest_warning = 0;
2366
if (p_option.begins_with("rest_pose/")) {
2367
if (!p_options.has("rest_pose/load_pose") || int(p_options["rest_pose/load_pose"]) == 0) {
2368
if (p_option != "rest_pose/load_pose") {
2369
return false;
2370
}
2371
} else if (int(p_options["rest_pose/load_pose"]) == 1) {
2372
if (p_option == "rest_pose/external_animation_library") {
2373
return false;
2374
}
2375
} else if (int(p_options["rest_pose/load_pose"]) == 2) {
2376
Object *res = p_options["rest_pose/external_animation_library"];
2377
Ref<Animation> anim(res);
2378
if (anim.is_valid() && p_option == "rest_pose/selected_animation") {
2379
return false;
2380
}
2381
Ref<AnimationLibrary> library(res);
2382
String selected_animation_name = p_options["rest_pose/selected_animation"];
2383
if (library.is_valid()) {
2384
List<StringName> anim_list;
2385
library->get_animation_list(&anim_list);
2386
if (anim_list.size() == 1) {
2387
selected_animation_name = String(anim_list.front()->get());
2388
}
2389
if (library->has_animation(selected_animation_name)) {
2390
anim = library->get_animation(selected_animation_name);
2391
}
2392
}
2393
int found_bone_count = 0;
2394
Ref<BoneMap> bone_map;
2395
Ref<SkeletonProfile> prof;
2396
if (p_options.has("retarget/bone_map")) {
2397
bone_map = p_options["retarget/bone_map"];
2398
}
2399
if (bone_map.is_valid()) {
2400
prof = bone_map->get_profile();
2401
}
2402
if (anim.is_valid()) {
2403
HashSet<StringName> target_bones;
2404
if (bone_map.is_valid() && prof.is_valid()) {
2405
for (int target_i = 0; target_i < prof->get_bone_size(); target_i++) {
2406
StringName skeleton_bone_name = bone_map->get_skeleton_bone_name(prof->get_bone_name(target_i));
2407
if (skeleton_bone_name) {
2408
target_bones.insert(skeleton_bone_name);
2409
}
2410
}
2411
}
2412
for (int track_i = 0; track_i < anim->get_track_count(); track_i++) {
2413
if (anim->track_get_type(track_i) != Animation::TYPE_POSITION_3D && anim->track_get_type(track_i) != Animation::TYPE_ROTATION_3D) {
2414
continue;
2415
}
2416
NodePath path = anim->track_get_path(track_i);
2417
StringName node_path = path.get_concatenated_names();
2418
StringName skeleton_bone = path.get_concatenated_subnames();
2419
if (skeleton_bone) {
2420
if (String(node_path).begins_with("%")) {
2421
rest_warning = 1;
2422
}
2423
if (target_bones.has(skeleton_bone)) {
2424
target_bones.erase(skeleton_bone);
2425
}
2426
found_bone_count++;
2427
}
2428
}
2429
if ((found_bone_count < 15 || !target_bones.is_empty()) && rest_warning != 1) {
2430
rest_warning = 2; // heuristic: animation targeted too few bones.
2431
}
2432
} else {
2433
rest_warning = 3;
2434
}
2435
}
2436
if (p_option.begins_with("rest_pose/") && p_option.ends_with("profile_must_not_be_retargeted")) {
2437
return rest_warning == 1;
2438
}
2439
if (p_option.begins_with("rest_pose/") && p_option.ends_with("mismatched_or_empty_profile")) {
2440
return rest_warning == 2;
2441
}
2442
if (p_option.begins_with("rest_pose/") && p_option.ends_with("no_animation_chosen")) {
2443
return rest_warning == 3;
2444
}
2445
}
2446
} break;
2447
default: {
2448
}
2449
}
2450
2451
// TODO: If there are more than 2 or equal get_internal_option_visibility method, visibility state is broken.
2452
for (int i = 0; i < post_importer_plugins.size(); i++) {
2453
Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), _scene_import_type, p_option, p_options);
2454
if (ret.get_type() == Variant::BOOL) {
2455
return ret;
2456
}
2457
}
2458
2459
return true;
2460
}
2461
2462
bool ResourceImporterScene::get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
2463
switch (p_category) {
2464
case INTERNAL_IMPORT_CATEGORY_NODE: {
2465
} break;
2466
case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
2467
if (
2468
p_option == "generate/physics" ||
2469
p_option == "physics/shape_type" ||
2470
p_option.contains("decomposition/") ||
2471
p_option.contains("primitive/")) {
2472
return true;
2473
}
2474
} break;
2475
case INTERNAL_IMPORT_CATEGORY_MESH: {
2476
} break;
2477
case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
2478
} break;
2479
case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
2480
} break;
2481
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
2482
} break;
2483
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
2484
} break;
2485
default: {
2486
}
2487
}
2488
2489
for (int i = 0; i < post_importer_plugins.size(); i++) {
2490
Variant ret = post_importer_plugins.write[i]->get_internal_option_update_view_required(EditorScenePostImportPlugin::InternalImportCategory(p_category), p_option, p_options);
2491
if (ret.get_type() == Variant::BOOL) {
2492
return ret;
2493
}
2494
}
2495
2496
return false;
2497
}
2498
2499
void ResourceImporterScene::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
2500
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), ""));
2501
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_name"), ""));
2502
r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "nodes/root_script", PROPERTY_HINT_RESOURCE_TYPE, "Script"), Variant()));
2503
2504
List<String> script_extensions;
2505
ResourceLoader::get_recognized_extensions_for_type("Script", &script_extensions);
2506
2507
String script_ext_hint;
2508
2509
for (const String &E : script_extensions) {
2510
if (!script_ext_hint.is_empty()) {
2511
script_ext_hint += ",";
2512
}
2513
script_ext_hint += "*." + E;
2514
}
2515
bool trimming_defaults_on = p_path.get_extension().to_lower() == "fbx";
2516
2517
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/apply_root_scale"), true));
2518
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
2519
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/import_as_skeleton_bones"), false));
2520
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/use_name_suffixes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
2521
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/use_node_type_suffixes"), true));
2522
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
2523
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
2524
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true));
2525
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Static,Static Lightmaps,Dynamic", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1));
2526
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2));
2527
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/force_disable_compression"), false));
2528
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
2529
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
2530
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30));
2531
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), trimming_defaults_on));
2532
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/remove_immutable_tracks"), true));
2533
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import_rest_as_RESET"), false));
2534
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
2535
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/extract", PROPERTY_HINT_ENUM, "Keep Internal,Extract Once,Extract and Overwrite"), 0));
2536
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/extract_format", PROPERTY_HINT_ENUM, "Text (*.tres),Binary (*.res),Material (*.material)"), 0));
2537
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "materials/extract_path", PROPERTY_HINT_DIR, ""), ""));
2538
2539
r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Dictionary()));
2540
2541
for (int i = 0; i < post_importer_plugins.size(); i++) {
2542
post_importer_plugins.write[i]->get_import_options(p_path, r_options);
2543
}
2544
2545
for (Ref<EditorSceneFormatImporter> importer_elem : scene_importers) {
2546
importer_elem->get_import_options(p_path, r_options);
2547
}
2548
}
2549
2550
void ResourceImporterScene::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {
2551
for (Ref<EditorSceneFormatImporter> importer_elem : scene_importers) {
2552
importer_elem->handle_compatibility_options(p_import_params);
2553
}
2554
}
2555
2556
void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner) {
2557
if (p_node != p_new_owner && p_node->get_owner() == p_scene) {
2558
p_node->set_owner(p_new_owner);
2559
}
2560
2561
for (int i = 0; i < p_node->get_child_count(); i++) {
2562
Node *n = p_node->get_child(i);
2563
_replace_owner(n, p_scene, p_new_owner);
2564
}
2565
}
2566
2567
Array ResourceImporterScene::_get_skinned_pose_transforms(ImporterMeshInstance3D *p_src_mesh_node) {
2568
Array skin_pose_transform_array;
2569
2570
const Ref<Skin> skin = p_src_mesh_node->get_skin();
2571
if (skin.is_valid()) {
2572
NodePath skeleton_path = p_src_mesh_node->get_skeleton_path();
2573
const Node *node = p_src_mesh_node->get_node_or_null(skeleton_path);
2574
const Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
2575
if (skeleton) {
2576
int bind_count = skin->get_bind_count();
2577
2578
for (int i = 0; i < bind_count; i++) {
2579
Transform3D bind_pose = skin->get_bind_pose(i);
2580
String bind_name = skin->get_bind_name(i);
2581
2582
int bone_idx = bind_name.is_empty() ? skin->get_bind_bone(i) : skeleton->find_bone(bind_name);
2583
ERR_FAIL_COND_V(bone_idx >= skeleton->get_bone_count(), Array());
2584
2585
Transform3D bp_global_rest;
2586
if (bone_idx >= 0) {
2587
bp_global_rest = skeleton->get_bone_global_pose(bone_idx);
2588
} else {
2589
bp_global_rest = skeleton->get_bone_global_pose(i);
2590
}
2591
2592
skin_pose_transform_array.push_back(bp_global_rest * bind_pose);
2593
}
2594
}
2595
}
2596
2597
return skin_pose_transform_array;
2598
}
2599
2600
Node *ResourceImporterScene::_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) {
2601
ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
2602
if (src_mesh_node) {
2603
//is mesh
2604
MeshInstance3D *mesh_node = memnew(MeshInstance3D);
2605
mesh_node->set_name(src_mesh_node->get_name());
2606
mesh_node->set_transform(src_mesh_node->get_transform());
2607
mesh_node->set_skin(src_mesh_node->get_skin());
2608
mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
2609
mesh_node->merge_meta_from(src_mesh_node);
2610
2611
Ref<ImporterMesh> importer_mesh = src_mesh_node->get_mesh();
2612
if (importer_mesh.is_valid()) {
2613
Ref<ArrayMesh> mesh;
2614
if (!importer_mesh->has_mesh()) {
2615
//do mesh processing
2616
2617
bool generate_lods = p_generate_lods;
2618
float merge_angle = 20.0f;
2619
bool create_shadow_meshes = p_create_shadow_meshes;
2620
bool bake_lightmaps = p_light_bake_mode == LIGHT_BAKE_STATIC_LIGHTMAPS;
2621
String save_to_file;
2622
2623
String mesh_id = importer_mesh->get_meta("import_id", importer_mesh->get_name());
2624
2625
if (!mesh_id.is_empty() && p_mesh_data.has(mesh_id)) {
2626
Dictionary mesh_settings = p_mesh_data[mesh_id];
2627
{
2628
//fill node settings for this node with default values
2629
List<ImportOption> iopts;
2630
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_MESH, &iopts);
2631
for (const ImportOption &E : iopts) {
2632
if (!mesh_settings.has(E.option.name)) {
2633
mesh_settings[E.option.name] = E.default_value;
2634
}
2635
}
2636
}
2637
2638
if (mesh_settings.has("generate/shadow_meshes")) {
2639
int shadow_meshes = mesh_settings["generate/shadow_meshes"];
2640
if (shadow_meshes == MESH_OVERRIDE_ENABLE) {
2641
create_shadow_meshes = true;
2642
} else if (shadow_meshes == MESH_OVERRIDE_DISABLE) {
2643
create_shadow_meshes = false;
2644
}
2645
}
2646
2647
if (mesh_settings.has("generate/lightmap_uv")) {
2648
int lightmap_uv = mesh_settings["generate/lightmap_uv"];
2649
if (lightmap_uv == MESH_OVERRIDE_ENABLE) {
2650
bake_lightmaps = true;
2651
} else if (lightmap_uv == MESH_OVERRIDE_DISABLE) {
2652
bake_lightmaps = false;
2653
}
2654
}
2655
2656
if (mesh_settings.has("generate/lods")) {
2657
int lods = mesh_settings["generate/lods"];
2658
if (lods == MESH_OVERRIDE_ENABLE) {
2659
generate_lods = true;
2660
} else if (lods == MESH_OVERRIDE_DISABLE) {
2661
generate_lods = false;
2662
}
2663
}
2664
2665
if (mesh_settings.has("lods/normal_merge_angle")) {
2666
merge_angle = mesh_settings["lods/normal_merge_angle"];
2667
}
2668
2669
if (bool(mesh_settings.get("save_to_file/enabled", false))) {
2670
save_to_file = mesh_settings.get("save_to_file/path", String());
2671
if (!ResourceUID::ensure_path(save_to_file).is_resource_file()) {
2672
save_to_file = "";
2673
}
2674
}
2675
2676
for (int i = 0; i < post_importer_plugins.size(); i++) {
2677
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MESH, nullptr, src_mesh_node, importer_mesh, mesh_settings);
2678
}
2679
}
2680
2681
if (bake_lightmaps) {
2682
Transform3D xf;
2683
Node3D *n = src_mesh_node;
2684
while (n) {
2685
xf = n->get_transform() * xf;
2686
n = n->get_parent_node_3d();
2687
}
2688
2689
Vector<uint8_t> lightmap_cache;
2690
importer_mesh->lightmap_unwrap_cached(xf, p_lightmap_texel_size, p_src_lightmap_cache, lightmap_cache);
2691
2692
if (!lightmap_cache.is_empty()) {
2693
if (r_lightmap_caches.is_empty()) {
2694
r_lightmap_caches.push_back(lightmap_cache);
2695
} else {
2696
String new_md5 = String::md5(lightmap_cache.ptr()); // MD5 is stored at the beginning of the cache data
2697
2698
for (int i = 0; i < r_lightmap_caches.size(); i++) {
2699
String md5 = String::md5(r_lightmap_caches[i].ptr());
2700
if (new_md5 < md5) {
2701
r_lightmap_caches.insert(i, lightmap_cache);
2702
break;
2703
}
2704
2705
if (new_md5 == md5) {
2706
break;
2707
}
2708
}
2709
}
2710
}
2711
}
2712
2713
if (generate_lods) {
2714
Array skin_pose_transform_array = _get_skinned_pose_transforms(src_mesh_node);
2715
importer_mesh->generate_lods(merge_angle, skin_pose_transform_array);
2716
}
2717
2718
if (create_shadow_meshes) {
2719
importer_mesh->create_shadow_mesh();
2720
}
2721
2722
importer_mesh->optimize_indices();
2723
2724
if (!save_to_file.is_empty()) {
2725
String save_res_path = ResourceUID::ensure_path(save_to_file);
2726
Ref<Mesh> existing = ResourceCache::get_ref(save_res_path);
2727
if (existing.is_valid()) {
2728
//if somehow an existing one is useful, create
2729
existing->reset_state();
2730
}
2731
mesh = importer_mesh->get_mesh(existing);
2732
2733
Error err = ResourceSaver::save(mesh, save_res_path); //override
2734
if (err != OK) {
2735
WARN_PRINT(vformat("Failed to save mesh %s to '%s'.", mesh->get_name(), save_res_path));
2736
}
2737
if (err == OK && save_to_file.begins_with("uid://")) {
2738
// slow
2739
ResourceSaver::set_uid(save_res_path, ResourceUID::get_singleton()->text_to_id(save_to_file));
2740
}
2741
2742
mesh->set_path(save_res_path, true); //takeover existing, if needed
2743
2744
} else {
2745
mesh = importer_mesh->get_mesh();
2746
}
2747
} else {
2748
mesh = importer_mesh->get_mesh();
2749
}
2750
2751
if (mesh.is_valid()) {
2752
_copy_meta(importer_mesh.ptr(), mesh.ptr());
2753
mesh_node->set_mesh(mesh);
2754
for (int i = 0; i < mesh->get_surface_count(); i++) {
2755
mesh_node->set_surface_override_material(i, src_mesh_node->get_surface_material(i));
2756
}
2757
mesh->merge_meta_from(*importer_mesh);
2758
}
2759
}
2760
2761
switch (p_light_bake_mode) {
2762
case LIGHT_BAKE_DISABLED: {
2763
mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_DISABLED);
2764
} break;
2765
case LIGHT_BAKE_DYNAMIC: {
2766
mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_DYNAMIC);
2767
} break;
2768
case LIGHT_BAKE_STATIC:
2769
case LIGHT_BAKE_STATIC_LIGHTMAPS: {
2770
mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_STATIC);
2771
} break;
2772
}
2773
2774
mesh_node->set_layer_mask(src_mesh_node->get_layer_mask());
2775
mesh_node->set_cast_shadows_setting(src_mesh_node->get_cast_shadows_setting());
2776
mesh_node->set_visible(src_mesh_node->is_visible());
2777
mesh_node->set_visibility_range_begin(src_mesh_node->get_visibility_range_begin());
2778
mesh_node->set_visibility_range_begin_margin(src_mesh_node->get_visibility_range_begin_margin());
2779
mesh_node->set_visibility_range_end(src_mesh_node->get_visibility_range_end());
2780
mesh_node->set_visibility_range_end_margin(src_mesh_node->get_visibility_range_end_margin());
2781
mesh_node->set_visibility_range_fade_mode(src_mesh_node->get_visibility_range_fade_mode());
2782
2783
_copy_meta(p_node, mesh_node);
2784
2785
p_node->replace_by(mesh_node);
2786
p_node->set_owner(nullptr);
2787
memdelete(p_node);
2788
p_node = mesh_node;
2789
}
2790
2791
for (int i = 0; i < p_node->get_child_count(); i++) {
2792
_generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_lightmap_caches);
2793
}
2794
2795
return p_node;
2796
}
2797
2798
void ResourceImporterScene::_add_shapes(Node *p_node, const Vector<Ref<Shape3D>> &p_shapes) {
2799
for (const Ref<Shape3D> &E : p_shapes) {
2800
CollisionShape3D *cshape = memnew(CollisionShape3D);
2801
cshape->set_shape(E);
2802
p_node->add_child(cshape, true);
2803
2804
cshape->set_owner(p_node->get_owner());
2805
}
2806
}
2807
2808
void ResourceImporterScene::_copy_meta(Object *p_src_object, Object *p_dst_object) {
2809
List<StringName> meta_list;
2810
p_src_object->get_meta_list(&meta_list);
2811
for (const StringName &meta_key : meta_list) {
2812
Variant meta_value = p_src_object->get_meta(meta_key);
2813
p_dst_object->set_meta(meta_key, meta_value);
2814
}
2815
}
2816
2817
void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions) {
2818
List<StringName> anims;
2819
p_player->get_animation_list(&anims);
2820
Node *parent = p_player->get_parent();
2821
ERR_FAIL_NULL(parent);
2822
HashMap<NodePath, uint32_t> used_tracks[TRACK_CHANNEL_MAX];
2823
bool tracks_to_add = false;
2824
static const Animation::TrackType track_types[TRACK_CHANNEL_MAX] = { Animation::TYPE_POSITION_3D, Animation::TYPE_ROTATION_3D, Animation::TYPE_SCALE_3D, Animation::TYPE_BLEND_SHAPE };
2825
for (const StringName &I : anims) {
2826
Ref<Animation> anim = p_player->get_animation(I);
2827
for (int i = 0; i < anim->get_track_count(); i++) {
2828
for (int j = 0; j < TRACK_CHANNEL_MAX; j++) {
2829
if (anim->track_get_type(i) != track_types[j]) {
2830
continue;
2831
}
2832
switch (p_track_actions[j]) {
2833
case ANIMATION_IMPORT_TRACKS_IF_PRESENT: {
2834
// Do Nothing.
2835
} break;
2836
case ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL: {
2837
used_tracks[j].insert(anim->track_get_path(i), 0);
2838
tracks_to_add = true;
2839
} break;
2840
case ANIMATION_IMPORT_TRACKS_NEVER: {
2841
anim->remove_track(i);
2842
i--;
2843
} break;
2844
}
2845
}
2846
}
2847
}
2848
2849
if (!tracks_to_add) {
2850
return;
2851
}
2852
2853
uint32_t pass = 0;
2854
for (const StringName &I : anims) {
2855
Ref<Animation> anim = p_player->get_animation(I);
2856
for (int j = 0; j < TRACK_CHANNEL_MAX; j++) {
2857
if (p_track_actions[j] != ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
2858
continue;
2859
}
2860
2861
pass++;
2862
2863
for (int i = 0; i < anim->get_track_count(); i++) {
2864
if (anim->track_get_type(i) != track_types[j]) {
2865
continue;
2866
}
2867
2868
NodePath path = anim->track_get_path(i);
2869
2870
ERR_CONTINUE(!used_tracks[j].has(path)); // Should never happen.
2871
2872
used_tracks[j][path] = pass;
2873
}
2874
2875
for (const KeyValue<NodePath, uint32_t> &J : used_tracks[j]) {
2876
if (J.value == pass) {
2877
continue;
2878
}
2879
2880
NodePath path = J.key;
2881
Node *n = parent->get_node(path);
2882
2883
if (j == TRACK_CHANNEL_BLEND_SHAPE) {
2884
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(n);
2885
if (mi && path.get_subname_count() > 0) {
2886
StringName bs = path.get_subname(0);
2887
bool valid;
2888
float value = mi->get(bs, &valid);
2889
if (valid) {
2890
int track_idx = anim->add_track(track_types[j]);
2891
anim->track_set_path(track_idx, path);
2892
anim->track_set_imported(track_idx, true);
2893
anim->blend_shape_track_insert_key(track_idx, 0, value);
2894
}
2895
}
2896
2897
} else {
2898
Skeleton3D *skel = Object::cast_to<Skeleton3D>(n);
2899
Node3D *n3d = Object::cast_to<Node3D>(n);
2900
Vector3 loc;
2901
Quaternion rot;
2902
Vector3 scale;
2903
if (skel && path.get_subname_count() > 0) {
2904
StringName bone = path.get_subname(0);
2905
int bone_idx = skel->find_bone(bone);
2906
if (bone_idx == -1) {
2907
continue;
2908
}
2909
// Note that this is using get_bone_pose to update the bone pose cache.
2910
_ALLOW_DISCARD_ skel->get_bone_pose(bone_idx);
2911
loc = skel->get_bone_pose_position(bone_idx);
2912
rot = skel->get_bone_pose_rotation(bone_idx);
2913
scale = skel->get_bone_pose_scale(bone_idx);
2914
} else if (n3d) {
2915
loc = n3d->get_position();
2916
rot = n3d->get_transform().basis.get_rotation_quaternion();
2917
scale = n3d->get_scale();
2918
} else {
2919
continue;
2920
}
2921
2922
// Ensure insertion keeps tracks together and ordered by type (loc/rot/scale)
2923
int insert_at_pos = -1;
2924
for (int k = 0; k < anim->get_track_count(); k++) {
2925
NodePath tpath = anim->track_get_path(k);
2926
2927
if (path == tpath) {
2928
Animation::TrackType ttype = anim->track_get_type(k);
2929
if (insert_at_pos == -1) {
2930
// First insert, determine whether replacing or kicking back
2931
if (track_types[j] < ttype) {
2932
insert_at_pos = k;
2933
break; // No point in continuing.
2934
} else {
2935
insert_at_pos = k + 1;
2936
}
2937
} else if (ttype < track_types[j]) {
2938
// Kick back.
2939
insert_at_pos = k + 1;
2940
}
2941
} else if (insert_at_pos >= 0) {
2942
break;
2943
}
2944
}
2945
int track_idx = anim->add_track(track_types[j], insert_at_pos);
2946
2947
anim->track_set_path(track_idx, path);
2948
anim->track_set_imported(track_idx, true);
2949
switch (j) {
2950
case TRACK_CHANNEL_POSITION: {
2951
anim->position_track_insert_key(track_idx, 0, loc);
2952
} break;
2953
case TRACK_CHANNEL_ROTATION: {
2954
anim->rotation_track_insert_key(track_idx, 0, rot);
2955
} break;
2956
case TRACK_CHANNEL_SCALE: {
2957
anim->scale_track_insert_key(track_idx, 0, scale);
2958
} break;
2959
default: {
2960
}
2961
}
2962
}
2963
}
2964
}
2965
}
2966
}
2967
2968
Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options) {
2969
Ref<EditorSceneFormatImporter> importer;
2970
String ext = p_source_file.get_extension().to_lower();
2971
2972
// TRANSLATORS: This is an editor progress label.
2973
EditorProgress progress("pre-import", TTR("Pre-Import Scene"), 0);
2974
progress.step(TTR("Importing Scene..."), 0);
2975
2976
for (Ref<EditorSceneFormatImporter> importer_elem : scene_importers) {
2977
List<String> extensions;
2978
importer_elem->get_extensions(&extensions);
2979
2980
for (const String &F : extensions) {
2981
if (F.to_lower() == ext) {
2982
importer = importer_elem;
2983
break;
2984
}
2985
}
2986
2987
if (importer.is_valid()) {
2988
break;
2989
}
2990
}
2991
2992
ERR_FAIL_COND_V(importer.is_null(), nullptr);
2993
ERR_FAIL_COND_V(p_options.is_empty(), nullptr);
2994
2995
Error err = OK;
2996
2997
Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS | EditorSceneFormatImporter::IMPORT_FORCE_DISABLE_MESH_COMPRESSION, p_options, nullptr, &err);
2998
if (!scene || err != OK) {
2999
return nullptr;
3000
}
3001
3002
_pre_fix_global(scene, p_options);
3003
3004
HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
3005
List<Pair<NodePath, Node *>> node_renames;
3006
_pre_fix_node(scene, scene, collision_map, nullptr, node_renames, p_options);
3007
3008
return scene;
3009
}
3010
3011
static Error convert_path_to_uid(ResourceUID::ID p_source_id, const String &p_hash_str, Dictionary &p_settings, const String &p_path_key, const String &p_fallback_path_key) {
3012
const String &raw_save_path = p_settings[p_path_key];
3013
String save_path = ResourceUID::ensure_path(raw_save_path);
3014
if (raw_save_path.begins_with("uid://")) {
3015
if (save_path.is_empty() || !DirAccess::exists(save_path.get_base_dir())) {
3016
if (p_settings.has(p_fallback_path_key)) {
3017
String fallback_save_path = p_settings[p_fallback_path_key];
3018
if (!fallback_save_path.is_empty() && DirAccess::exists(fallback_save_path.get_base_dir())) {
3019
save_path = fallback_save_path;
3020
ResourceUID::get_singleton()->add_id(ResourceUID::get_singleton()->text_to_id(raw_save_path), save_path);
3021
}
3022
}
3023
} else {
3024
p_settings[p_fallback_path_key] = save_path;
3025
}
3026
}
3027
ERR_FAIL_COND_V(!save_path.is_empty() && !DirAccess::exists(save_path.get_base_dir()), ERR_FILE_BAD_PATH);
3028
if (!save_path.is_empty() && !raw_save_path.begins_with("uid://")) {
3029
const ResourceUID::ID id = ResourceLoader::get_resource_uid(save_path);
3030
if (id != ResourceUID::INVALID_ID) {
3031
p_settings[p_path_key] = ResourceUID::get_singleton()->id_to_text(id);
3032
} else {
3033
ResourceUID::ID save_id = hash64_murmur3_64(p_hash_str.hash64(), p_source_id) & 0x7FFFFFFFFFFFFFFF;
3034
if (ResourceUID::get_singleton()->has_id(save_id)) {
3035
if (save_path != ResourceUID::get_singleton()->get_id_path(save_id)) {
3036
// The user has specified a path which does not match the default UID.
3037
save_id = ResourceUID::get_singleton()->create_id_for_path(save_path);
3038
}
3039
}
3040
p_settings[p_path_key] = ResourceUID::get_singleton()->id_to_text(save_id);
3041
ResourceUID::get_singleton()->add_id(save_id, save_path);
3042
}
3043
p_settings[p_fallback_path_key] = save_path;
3044
}
3045
return OK;
3046
}
3047
3048
Error ResourceImporterScene::_check_resource_save_paths(ResourceUID::ID p_source_id, const String &p_hash_suffix, const Dictionary &p_data) {
3049
for (const KeyValue<Variant, Variant> &kv : p_data) {
3050
Dictionary settings = kv.value;
3051
3052
if (bool(settings.get("save_to_file/enabled", false)) && settings.has("save_to_file/path")) {
3053
String to_hash = kv.key.operator String() + p_hash_suffix;
3054
Error ret = convert_path_to_uid(p_source_id, to_hash, settings, "save_to_file/path", "save_to_file/fallback_path");
3055
ERR_FAIL_COND_V_MSG(ret != OK, ret, vformat("Resource save path %s not valid. Ensure parent directory has been created.", settings.has("save_to_file/path")));
3056
}
3057
3058
if (settings.has("slices/amount")) {
3059
int slice_count = settings["slices/amount"];
3060
for (int si = 0; si < slice_count; si++) {
3061
if (bool(settings.get("slice_" + itos(si + 1) + "/save_to_file/enabled", false)) &&
3062
settings.has("slice_" + itos(si + 1) + "/save_to_file/path")) {
3063
String to_hash = kv.key.operator String() + p_hash_suffix + itos(si + 1);
3064
Error ret = convert_path_to_uid(p_source_id, to_hash, settings,
3065
"slice_" + itos(si + 1) + "/save_to_file/path",
3066
"slice_" + itos(si + 1) + "/save_to_file/fallback_path");
3067
ERR_FAIL_COND_V_MSG(ret != OK, ret, vformat("Slice save path %s not valid. Ensure parent directory has been created.", settings.has("save_to_file/path")));
3068
}
3069
}
3070
}
3071
}
3072
3073
return OK;
3074
}
3075
3076
Error ResourceImporterScene::import(ResourceUID::ID p_source_id, 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, Variant *r_metadata) {
3077
const String &src_path = p_source_file;
3078
3079
Ref<EditorSceneFormatImporter> importer;
3080
String ext = src_path.get_extension().to_lower();
3081
3082
EditorProgress progress("import", TTR("Import Scene"), 104);
3083
progress.step(TTR("Importing Scene..."), 0);
3084
3085
for (Ref<EditorSceneFormatImporter> importer_elem : scene_importers) {
3086
List<String> extensions;
3087
importer_elem->get_extensions(&extensions);
3088
3089
for (const String &F : extensions) {
3090
if (F.to_lower() == ext) {
3091
importer = importer_elem;
3092
break;
3093
}
3094
}
3095
3096
if (importer.is_valid()) {
3097
break;
3098
}
3099
}
3100
3101
ERR_FAIL_COND_V(importer.is_null(), ERR_FILE_UNRECOGNIZED);
3102
ERR_FAIL_COND_V(p_options.is_empty(), ERR_BUG);
3103
3104
int import_flags = 0;
3105
3106
if (_scene_import_type == "AnimationLibrary") {
3107
import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION;
3108
import_flags |= EditorSceneFormatImporter::IMPORT_DISCARD_MESHES_AND_MATERIALS;
3109
} else if (bool(p_options["animation/import"])) {
3110
import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION;
3111
}
3112
3113
if (bool(p_options["skins/use_named_skins"])) {
3114
import_flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
3115
}
3116
3117
bool ensure_tangents = p_options["meshes/ensure_tangents"];
3118
if (ensure_tangents) {
3119
import_flags |= EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
3120
}
3121
3122
bool force_disable_compression = p_options["meshes/force_disable_compression"];
3123
if (force_disable_compression) {
3124
import_flags |= EditorSceneFormatImporter::IMPORT_FORCE_DISABLE_MESH_COMPRESSION;
3125
}
3126
3127
Dictionary subresources = p_options["_subresources"];
3128
3129
Error err = OK;
3130
3131
// Check whether any of the meshes or animations have nonexistent save paths
3132
// and if they do, fail the import immediately.
3133
if (subresources.has("meshes")) {
3134
err = _check_resource_save_paths(p_source_id, "m", subresources["meshes"]);
3135
if (err != OK) {
3136
return err;
3137
}
3138
}
3139
3140
if (subresources.has("animations")) {
3141
err = _check_resource_save_paths(p_source_id, "a", subresources["animations"]);
3142
if (err != OK) {
3143
return err;
3144
}
3145
}
3146
3147
List<String> missing_deps; // for now, not much will be done with this
3148
Node *scene = importer->import_scene(src_path, import_flags, p_options, &missing_deps, &err);
3149
if (!scene || err != OK) {
3150
return err;
3151
}
3152
3153
bool apply_root = true;
3154
if (p_options.has("nodes/apply_root_scale")) {
3155
apply_root = p_options["nodes/apply_root_scale"];
3156
}
3157
real_t root_scale = 1;
3158
if (p_options.has("nodes/root_scale")) {
3159
root_scale = p_options["nodes/root_scale"];
3160
}
3161
if (Object::cast_to<Node3D>(scene)) {
3162
Node3D *scene_3d = Object::cast_to<Node3D>(scene);
3163
Vector3 scale = Vector3(root_scale, root_scale, root_scale);
3164
if (apply_root) {
3165
_apply_permanent_scale_to_descendants(scene, scale);
3166
} else {
3167
scene_3d->scale(scale);
3168
}
3169
}
3170
3171
_pre_fix_global(scene, p_options);
3172
3173
HashSet<Ref<ImporterMesh>> scanned_meshes;
3174
HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
3175
Pair<PackedVector3Array, PackedInt32Array> occluder_arrays;
3176
List<Pair<NodePath, Node *>> node_renames;
3177
3178
_pre_fix_node(scene, scene, collision_map, &occluder_arrays, node_renames, p_options);
3179
3180
for (int i = 0; i < post_importer_plugins.size(); i++) {
3181
post_importer_plugins.write[i]->pre_process(scene, p_options);
3182
}
3183
3184
// data in _subresources may be modified by pre_process(), so wait until now to check.
3185
Dictionary node_data;
3186
if (subresources.has("nodes")) {
3187
node_data = subresources["nodes"];
3188
}
3189
3190
Dictionary material_data;
3191
if (subresources.has("materials")) {
3192
material_data = subresources["materials"];
3193
}
3194
3195
Dictionary animation_data;
3196
if (subresources.has("animations")) {
3197
animation_data = subresources["animations"];
3198
}
3199
3200
Dictionary mesh_data;
3201
if (subresources.has("meshes")) {
3202
mesh_data = subresources["meshes"];
3203
}
3204
3205
float fps = 30;
3206
if (p_options.has(SNAME("animation/fps"))) {
3207
fps = (float)p_options[SNAME("animation/fps")];
3208
}
3209
bool remove_immutable_tracks = p_options.has("animation/remove_immutable_tracks") ? (bool)p_options["animation/remove_immutable_tracks"] : true;
3210
_pre_fix_animations(scene, scene, node_data, animation_data, fps);
3211
_post_fix_node(scene, scene, collision_map, occluder_arrays, scanned_meshes, node_data, material_data, animation_data, fps, apply_root ? root_scale : 1.0, p_source_file, p_options);
3212
_post_fix_animations(scene, scene, node_data, animation_data, fps, remove_immutable_tracks);
3213
3214
String root_type = p_options["nodes/root_type"];
3215
Ref<Script> root_script = p_options["nodes/root_script"];
3216
scene = _replace_node_with_type_and_script(scene, root_type, root_script);
3217
3218
String root_name = p_options["nodes/root_name"];
3219
if (!root_name.is_empty() && root_name != "Scene Root") {
3220
// TODO: Remove `&& root_name != "Scene Root"` for Godot 5.0.
3221
// For backwards compatibility with existing .import files,
3222
// treat "Scene Root" as having no root name override.
3223
scene->set_name(root_name);
3224
} else if (String(scene->get_name()).is_empty()) {
3225
scene->set_name(p_save_path.get_file().get_basename());
3226
}
3227
3228
if (!occluder_arrays.first.is_empty() && !occluder_arrays.second.is_empty()) {
3229
Ref<ArrayOccluder3D> occ = memnew(ArrayOccluder3D);
3230
occ->set_arrays(occluder_arrays.first, occluder_arrays.second);
3231
OccluderInstance3D *occluder_instance = memnew(OccluderInstance3D);
3232
occluder_instance->set_occluder(occ);
3233
scene->add_child(occluder_instance, true);
3234
occluder_instance->set_owner(scene);
3235
}
3236
3237
bool gen_lods = bool(p_options["meshes/generate_lods"]);
3238
bool create_shadow_meshes = bool(p_options["meshes/create_shadow_meshes"]);
3239
int light_bake_mode = p_options["meshes/light_baking"];
3240
float texel_size = p_options["meshes/lightmap_texel_size"];
3241
float lightmap_texel_size = MAX(0.001, texel_size);
3242
3243
Vector<uint8_t> src_lightmap_cache;
3244
Vector<Vector<uint8_t>> mesh_lightmap_caches;
3245
3246
{
3247
src_lightmap_cache = FileAccess::get_file_as_bytes(p_source_file + ".unwrap_cache", &err);
3248
if (err != OK) {
3249
src_lightmap_cache.clear();
3250
}
3251
}
3252
3253
scene = _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, mesh_lightmap_caches);
3254
3255
if (mesh_lightmap_caches.size()) {
3256
Ref<FileAccess> f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
3257
if (f.is_valid()) {
3258
f->store_32(mesh_lightmap_caches.size());
3259
for (int i = 0; i < mesh_lightmap_caches.size(); i++) {
3260
String md5 = String::md5(mesh_lightmap_caches[i].ptr());
3261
f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size());
3262
}
3263
}
3264
}
3265
err = OK;
3266
3267
progress.step(TTR("Running Custom Script..."), 2);
3268
3269
String post_import_script_path = p_options["import_script/path"];
3270
3271
Ref<EditorScenePostImport> post_import_script;
3272
3273
if (!post_import_script_path.is_empty()) {
3274
if (post_import_script_path.is_relative_path()) {
3275
post_import_script_path = p_source_file.get_base_dir().path_join(post_import_script_path);
3276
}
3277
Ref<Script> scr = ResourceLoader::load(post_import_script_path);
3278
if (scr.is_null()) {
3279
EditorNode::add_io_error(TTR("Couldn't load post-import script:") + " " + post_import_script_path);
3280
} else if (scr->get_instance_base_type() != "EditorScenePostImport") {
3281
EditorNode::add_io_error(TTR("Script is not a subtype of EditorScenePostImport:") + " " + post_import_script_path);
3282
} else {
3283
post_import_script.instantiate();
3284
post_import_script->set_script(scr);
3285
if (!post_import_script->get_script_instance()) {
3286
EditorNode::add_io_error(TTR("Invalid/broken script for post-import (check console):") + " " + post_import_script_path);
3287
post_import_script.unref();
3288
return ERR_CANT_CREATE;
3289
}
3290
}
3291
}
3292
3293
// Apply RESET animation before serializing.
3294
if (_scene_import_type == "PackedScene") {
3295
int scene_child_count = scene->get_child_count();
3296
for (int i = 0; i < scene_child_count; i++) {
3297
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(scene->get_child(i));
3298
if (ap) {
3299
if (ap->can_apply_reset()) {
3300
ap->apply_reset();
3301
}
3302
}
3303
}
3304
}
3305
3306
if (post_import_script.is_valid()) {
3307
post_import_script->init(p_source_file);
3308
scene = post_import_script->post_import(scene);
3309
if (!scene) {
3310
EditorNode::add_io_error(
3311
TTR("Error running post-import script:") + " " + post_import_script_path + "\n" +
3312
TTR("Did you return a Node-derived object in the `_post_import()` method?"));
3313
return err;
3314
}
3315
}
3316
3317
for (int i = 0; i < post_importer_plugins.size(); i++) {
3318
post_importer_plugins.write[i]->post_process(scene, p_options);
3319
}
3320
3321
progress.step(TTR("Saving..."), 104);
3322
3323
int flags = 0;
3324
if (EditorSettings::get_singleton() && EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
3325
flags |= ResourceSaver::FLAG_COMPRESS;
3326
}
3327
3328
if (_scene_import_type == "AnimationLibrary") {
3329
Ref<AnimationLibrary> library;
3330
for (int i = 0; i < scene->get_child_count(); i++) {
3331
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(scene->get_child(i));
3332
if (ap) {
3333
List<StringName> libs;
3334
ap->get_animation_library_list(&libs);
3335
if (libs.size()) {
3336
library = ap->get_animation_library(libs.front()->get());
3337
break;
3338
}
3339
}
3340
}
3341
3342
if (library.is_null()) {
3343
library.instantiate(); // Will be empty
3344
}
3345
3346
print_verbose("Saving animation to: " + p_save_path + ".res");
3347
err = ResourceSaver::save(library, p_save_path + ".res", flags); //do not take over, let the changed files reload themselves
3348
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save animation to file '" + p_save_path + ".res'.");
3349
} else if (_scene_import_type == "PackedScene") {
3350
Ref<PackedScene> packer = memnew(PackedScene);
3351
packer->pack(scene);
3352
print_verbose("Saving scene to: " + p_save_path + ".scn");
3353
err = ResourceSaver::save(packer, p_save_path + ".scn", flags); //do not take over, let the changed files reload themselves
3354
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'.");
3355
EditorInterface::get_singleton()->make_scene_preview(p_source_file, scene, 1024);
3356
} else {
3357
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown scene import type: " + _scene_import_type);
3358
}
3359
3360
memdelete(scene);
3361
3362
//this is not the time to reimport, wait until import process is done, import file is saved, etc.
3363
//EditorNode::get_singleton()->reload_scene(p_source_file);
3364
3365
return OK;
3366
}
3367
3368
ResourceImporterScene *ResourceImporterScene::scene_singleton = nullptr;
3369
ResourceImporterScene *ResourceImporterScene::animation_singleton = nullptr;
3370
3371
Vector<Ref<EditorSceneFormatImporter>> ResourceImporterScene::scene_importers;
3372
Vector<Ref<EditorScenePostImportPlugin>> ResourceImporterScene::post_importer_plugins;
3373
3374
bool ResourceImporterScene::has_advanced_options() const {
3375
return true;
3376
}
3377
3378
void ResourceImporterScene::show_advanced_options(const String &p_path) {
3379
SceneImportSettingsDialog::get_singleton()->open_settings(p_path, _scene_import_type);
3380
}
3381
3382
ResourceImporterScene::ResourceImporterScene(const String &p_scene_import_type, bool p_singleton) {
3383
// This should only be set through the EditorNode.
3384
if (p_singleton) {
3385
if (p_scene_import_type == "AnimationLibrary") {
3386
animation_singleton = this;
3387
} else if (p_scene_import_type == "PackedScene") {
3388
scene_singleton = this;
3389
}
3390
}
3391
3392
_scene_import_type = p_scene_import_type;
3393
}
3394
3395
ResourceImporterScene::~ResourceImporterScene() {
3396
if (animation_singleton == this) {
3397
animation_singleton = nullptr;
3398
}
3399
if (scene_singleton == this) {
3400
scene_singleton = nullptr;
3401
}
3402
}
3403
3404
void ResourceImporterScene::add_scene_importer(Ref<EditorSceneFormatImporter> p_importer, bool p_first_priority) {
3405
ERR_FAIL_COND(p_importer.is_null());
3406
if (p_first_priority) {
3407
scene_importers.insert(0, p_importer);
3408
} else {
3409
scene_importers.push_back(p_importer);
3410
}
3411
}
3412
3413
void ResourceImporterScene::remove_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin) {
3414
post_importer_plugins.erase(p_plugin);
3415
}
3416
3417
void ResourceImporterScene::add_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority) {
3418
ERR_FAIL_COND(p_plugin.is_null());
3419
if (p_first_priority) {
3420
post_importer_plugins.insert(0, p_plugin);
3421
} else {
3422
post_importer_plugins.push_back(p_plugin);
3423
}
3424
}
3425
3426
void ResourceImporterScene::remove_scene_importer(Ref<EditorSceneFormatImporter> p_importer) {
3427
scene_importers.erase(p_importer);
3428
}
3429
3430
void ResourceImporterScene::clean_up_importer_plugins() {
3431
scene_importers.clear();
3432
post_importer_plugins.clear();
3433
}
3434
3435
void ResourceImporterScene::get_scene_importer_extensions(List<String> *p_extensions) {
3436
for (Ref<EditorSceneFormatImporter> importer_elem : scene_importers) {
3437
importer_elem->get_extensions(p_extensions);
3438
}
3439
}
3440
3441
///////////////////////////////////////
3442
3443
void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) const {
3444
r_extensions->push_back("escn");
3445
}
3446
3447
Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
3448
Error error;
3449
Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error);
3450
ERR_FAIL_COND_V_MSG(ps.is_null(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
3451
Node *scene = ps->instantiate();
3452
TypedArray<Node> nodes = scene->find_children("*", "MeshInstance3D");
3453
for (int32_t node_i = 0; node_i < nodes.size(); node_i++) {
3454
MeshInstance3D *mesh_3d = cast_to<MeshInstance3D>(nodes[node_i]);
3455
Ref<ImporterMesh> mesh;
3456
mesh.instantiate();
3457
// Ignore the aabb, it will be recomputed.
3458
ImporterMeshInstance3D *importer_mesh_3d = memnew(ImporterMeshInstance3D);
3459
importer_mesh_3d->set_name(mesh_3d->get_name());
3460
importer_mesh_3d->set_transform(mesh_3d->get_relative_transform(mesh_3d->get_parent()));
3461
importer_mesh_3d->set_skin(mesh_3d->get_skin());
3462
importer_mesh_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
3463
Ref<ArrayMesh> array_mesh_3d_mesh = mesh_3d->get_mesh();
3464
if (array_mesh_3d_mesh.is_valid()) {
3465
// For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially.
3466
mesh->set_name(array_mesh_3d_mesh->get_name());
3467
for (int32_t blend_i = 0; blend_i < array_mesh_3d_mesh->get_blend_shape_count(); blend_i++) {
3468
mesh->add_blend_shape(array_mesh_3d_mesh->get_blend_shape_name(blend_i));
3469
}
3470
for (int32_t surface_i = 0; surface_i < array_mesh_3d_mesh->get_surface_count(); surface_i++) {
3471
mesh->add_surface(array_mesh_3d_mesh->surface_get_primitive_type(surface_i),
3472
array_mesh_3d_mesh->surface_get_arrays(surface_i),
3473
array_mesh_3d_mesh->surface_get_blend_shape_arrays(surface_i),
3474
array_mesh_3d_mesh->surface_get_lods(surface_i),
3475
array_mesh_3d_mesh->surface_get_material(surface_i),
3476
array_mesh_3d_mesh->surface_get_name(surface_i),
3477
array_mesh_3d_mesh->surface_get_format(surface_i));
3478
}
3479
mesh->set_blend_shape_mode(array_mesh_3d_mesh->get_blend_shape_mode());
3480
importer_mesh_3d->set_mesh(mesh);
3481
mesh_3d->replace_by(importer_mesh_3d);
3482
continue;
3483
}
3484
Ref<Mesh> mesh_3d_mesh = mesh_3d->get_mesh();
3485
if (mesh_3d_mesh.is_valid()) {
3486
// For the MeshInstance3D nodes, we need to convert the Mesh to an ImporterMesh specially.
3487
mesh->set_name(mesh_3d_mesh->get_name());
3488
for (int32_t surface_i = 0; surface_i < mesh_3d_mesh->get_surface_count(); surface_i++) {
3489
mesh->add_surface(mesh_3d_mesh->surface_get_primitive_type(surface_i),
3490
mesh_3d_mesh->surface_get_arrays(surface_i),
3491
Array(),
3492
mesh_3d_mesh->surface_get_lods(surface_i),
3493
mesh_3d_mesh->surface_get_material(surface_i),
3494
mesh_3d_mesh->surface_get_material(surface_i).is_valid() ? mesh_3d_mesh->surface_get_material(surface_i)->get_name() : String(),
3495
mesh_3d_mesh->surface_get_format(surface_i));
3496
}
3497
importer_mesh_3d->set_mesh(mesh);
3498
mesh_3d->replace_by(importer_mesh_3d);
3499
continue;
3500
}
3501
}
3502
3503
ERR_FAIL_NULL_V(scene, nullptr);
3504
3505
return scene;
3506
}
3507
3508