Skip to content

Commit

Permalink
Add option to import skeleton rest as RESET animation
Browse files Browse the repository at this point in the history
Also creates an AnimationPlayer if one does not exist.
Designed to be used in conjunction with loading rest pose in another importer.
  • Loading branch information
lyuma committed Mar 19, 2024
1 parent fe01776 commit 34f284b
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 5 deletions.
3 changes: 3 additions & 0 deletions doc/classes/ResourceImporterScene.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
70 changes: 70 additions & 0 deletions editor/import/3d/resource_importer_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions editor/import/3d/resource_importer_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ class ResourceImporterScene : public ResourceImporter {
// 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);
Expand Down
20 changes: 15 additions & 5 deletions editor/import/3d/scene_import_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions editor/import/3d/scene_import_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 34f284b

Please sign in to comment.