summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLyuma <xn.lyuma@gmail.com>2024-03-17 20:29:29 -0700
committerLyuma <xn.lyuma@gmail.com>2024-03-19 02:27:34 -0700
commit34f284bcc2929318735f97066763ea679ba30270 (patch)
treec53afeaaff4bfec3bd80fe2e77dcd422316e3acb
parentfe01776f05b1787b28b4a270d53037a3c25f4ca2 (diff)
downloadredot-engine-34f284bcc2929318735f97066763ea679ba30270.tar.gz
Add option to import skeleton rest as RESET animation
Also creates an AnimationPlayer if one does not exist. Designed to be used in conjunction with loading rest pose in another importer.
-rw-r--r--doc/classes/ResourceImporterScene.xml3
-rw-r--r--editor/import/3d/resource_importer_scene.cpp70
-rw-r--r--editor/import/3d/resource_importer_scene.h1
-rw-r--r--editor/import/3d/scene_import_settings.cpp20
-rw-r--r--editor/import/3d/scene_import_settings.h1
5 files changed, 90 insertions, 5 deletions
diff --git a/doc/classes/ResourceImporterScene.xml b/doc/classes/ResourceImporterScene.xml
index 4e20fe150e..900e028b25 100644
--- a/doc/classes/ResourceImporterScene.xml
+++ b/doc/classes/ResourceImporterScene.xml
@@ -21,6 +21,9 @@
<member name="animation/import" type="bool" setter="" getter="" default="true">
If [code]true[/code], import animations from the 3D scene.
</member>
+ <member name="animation/import_rest_as_RESET" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], adds an [Animation] named [code]RESET[/code], containing the [method Skeleton3D.get_bone_rest] from [Skeleton3D] nodes. This can be useful to extract an animation in the reference pose.
+ </member>
<member name="animation/remove_immutable_tracks" type="bool" setter="" getter="" default="true">
If [code]true[/code], remove animation tracks that only contain default values. This can reduce output file size and memory usage with certain 3D scenes, depending on the contents of their animation tracks.
</member>
diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp
index ca128968de..c9a2ca7588 100644
--- a/editor/import/3d/resource_importer_scene.cpp
+++ b/editor/import/3d/resource_importer_scene.cpp
@@ -312,6 +312,71 @@ String ResourceImporterScene::get_preset_name(int p_idx) const {
return String();
}
+void ResourceImporterScene::_pre_fix_global(Node *p_scene, const HashMap<StringName, Variant> &p_options) const {
+ if (p_options.has("animation/import_rest_as_RESET") && (bool)p_options["animation/import_rest_as_RESET"]) {
+ TypedArray<Node> anim_players = p_scene->find_children("*", "AnimationPlayer");
+ if (anim_players.is_empty()) {
+ AnimationPlayer *anim_player = memnew(AnimationPlayer);
+ anim_player->set_name("AnimationPlayer");
+ p_scene->add_child(anim_player);
+ anim_player->set_owner(p_scene);
+ anim_players.append(anim_player);
+ }
+ Ref<Animation> reset_anim;
+ for (int i = 0; i < anim_players.size(); i++) {
+ AnimationPlayer *player = cast_to<AnimationPlayer>(anim_players[i]);
+ if (player->has_animation(SNAME("RESET"))) {
+ reset_anim = player->get_animation(SNAME("RESET"));
+ break;
+ }
+ }
+ if (reset_anim.is_null()) {
+ AnimationPlayer *anim_player = cast_to<AnimationPlayer>(anim_players[0]);
+ reset_anim.instantiate();
+ Ref<AnimationLibrary> anim_library;
+ if (anim_player->has_animation_library(StringName())) {
+ anim_library = anim_player->get_animation_library(StringName());
+ } else {
+ anim_library.instantiate();
+ anim_player->add_animation_library(StringName(), anim_library);
+ }
+ anim_library->add_animation(SNAME("RESET"), reset_anim);
+ }
+ TypedArray<Node> skeletons = p_scene->find_children("*", "Skeleton3D");
+ for (int i = 0; i < skeletons.size(); i++) {
+ Skeleton3D *skeleton = cast_to<Skeleton3D>(skeletons[i]);
+ NodePath skeleton_path = p_scene->get_path_to(skeleton);
+
+ HashSet<NodePath> existing_pos_tracks;
+ HashSet<NodePath> existing_rot_tracks;
+ for (int trk_i = 0; trk_i < reset_anim->get_track_count(); trk_i++) {
+ NodePath np = reset_anim->track_get_path(trk_i);
+ if (reset_anim->track_get_type(trk_i) == Animation::TYPE_POSITION_3D) {
+ existing_pos_tracks.insert(np);
+ }
+ if (reset_anim->track_get_type(trk_i) == Animation::TYPE_ROTATION_3D) {
+ existing_rot_tracks.insert(np);
+ }
+ }
+ for (int bone_i = 0; bone_i < skeleton->get_bone_count(); bone_i++) {
+ NodePath bone_path(skeleton_path.get_names(), Vector<StringName>{ skeleton->get_bone_name(bone_i) }, false);
+ if (!existing_pos_tracks.has(bone_path)) {
+ int pos_t = reset_anim->add_track(Animation::TYPE_POSITION_3D);
+ reset_anim->track_set_path(pos_t, bone_path);
+ reset_anim->position_track_insert_key(pos_t, 0.0, skeleton->get_bone_rest(bone_i).origin);
+ reset_anim->track_set_imported(pos_t, true);
+ }
+ if (!existing_rot_tracks.has(bone_path)) {
+ int rot_t = reset_anim->add_track(Animation::TYPE_ROTATION_3D);
+ reset_anim->track_set_path(rot_t, bone_path);
+ reset_anim->rotation_track_insert_key(rot_t, 0.0, skeleton->get_bone_rest(bone_i).basis.get_rotation_quaternion());
+ reset_anim->track_set_imported(rot_t, true);
+ }
+ }
+ }
+ }
+}
+
static bool _teststr(const String &p_what, const String &p_str) {
String what = p_what;
@@ -1945,6 +2010,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/remove_immutable_tracks"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import_rest_as_RESET"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Dictionary()));
@@ -2387,6 +2453,8 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM
return nullptr;
}
+ _pre_fix_global(scene, p_options);
+
HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
List<Pair<NodePath, Node *>> node_renames;
_pre_fix_node(scene, scene, collision_map, nullptr, node_renames);
@@ -2521,6 +2589,8 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
}
+ _pre_fix_global(scene, p_options);
+
HashSet<Ref<ImporterMesh>> scanned_meshes;
HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
Pair<PackedVector3Array, PackedInt32Array> occluder_arrays;
diff --git a/editor/import/3d/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h
index 17fa9ef0e2..4e15471d17 100644
--- a/editor/import/3d/resource_importer_scene.h
+++ b/editor/import/3d/resource_importer_scene.h
@@ -282,6 +282,7 @@ public:
// Import scenes *after* everything else (such as textures).
virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; }
+ void _pre_fix_global(Node *p_scene, const HashMap<StringName, Variant> &p_options) const;
Node *_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames);
Node *_pre_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps);
Node *_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale);
diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp
index 721eccdfdd..260684ae3d 100644
--- a/editor/import/3d/scene_import_settings.cpp
+++ b/editor/import/3d/scene_import_settings.cpp
@@ -433,13 +433,20 @@ void SceneImportSettingsDialog::_update_view_gizmos() {
return;
}
const HashMap<StringName, Variant> &main_settings = scene_import_settings_data->current;
+ bool reshow_settings = false;
if (main_settings.has("nodes/import_as_skeleton_bones")) {
bool new_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"];
- if (new_import_as_skeleton != previous_import_as_skeleton) {
- previous_import_as_skeleton = new_import_as_skeleton;
- _re_import();
- open_settings(base_path);
- }
+ reshow_settings = reshow_settings || (new_import_as_skeleton != previous_import_as_skeleton);
+ previous_import_as_skeleton = new_import_as_skeleton;
+ }
+ if (main_settings.has("animation/import_rest_as_RESET")) {
+ bool new_rest_as_reset = main_settings["animation/import_rest_as_RESET"];
+ reshow_settings = reshow_settings || (new_rest_as_reset != previous_rest_as_reset);
+ previous_rest_as_reset = new_rest_as_reset;
+ }
+ if (reshow_settings) {
+ _re_import();
+ open_settings(base_path);
return;
}
for (const KeyValue<String, NodeData> &e : node_map) {
@@ -688,6 +695,9 @@ void SceneImportSettingsDialog::open_settings(const String &p_path, bool p_for_a
if (main_settings.has("nodes/import_as_skeleton_bones")) {
previous_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"];
}
+ if (main_settings.has("animation/import_rest_as_RESET")) {
+ previous_rest_as_reset = main_settings["animation/import_rest_as_RESET"];
+ }
popup_centered_ratio();
_update_view_gizmos();
_update_camera();
diff --git a/editor/import/3d/scene_import_settings.h b/editor/import/3d/scene_import_settings.h
index e1183dc5b0..f4954c41db 100644
--- a/editor/import/3d/scene_import_settings.h
+++ b/editor/import/3d/scene_import_settings.h
@@ -97,6 +97,7 @@ class SceneImportSettingsDialog : public ConfirmationDialog {
Animation::LoopMode animation_loop_mode = Animation::LOOP_NONE;
bool animation_pingpong = false;
bool previous_import_as_skeleton = false;
+ bool previous_rest_as_reset = false;
Ref<StandardMaterial3D> collider_mat;