Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply "Remove Immutable Tracks" after post-import. #90064

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 162 additions & 5 deletions editor/import/3d/resource_importer_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1046,10 +1046,10 @@ Node *ResourceImporterScene::_pre_fix_animations(Node *p_node, Node *p_root, con
return p_node;
}

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) {
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) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
Node *r = _post_fix_animations(p_node->get_child(i), p_root, p_node_data, p_animation_data, p_animation_fps);
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);
if (!r) {
i--; //was erased
}
Expand Down Expand Up @@ -1077,6 +1077,164 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co

if (Object::cast_to<AnimationPlayer>(p_node)) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
List<StringName> anims;
ap->get_animation_list(&anims);

if (p_remove_immutable_tracks) {
AnimationImportTracks import_tracks_mode[TRACK_CHANNEL_MAX] = {
AnimationImportTracks(int(node_settings["import_tracks/position"])),
AnimationImportTracks(int(node_settings["import_tracks/rotation"])),
AnimationImportTracks(int(node_settings["import_tracks/scale"]))
};
HashMap<NodePath, bool> used_tracks[TRACK_CHANNEL_MAX];

for (const StringName &name : anims) {
Ref<Animation> anim = ap->get_animation(name);
int track_count = anim->get_track_count();
LocalVector<int> tracks_to_keep;
for (int track_i = 0; track_i < track_count; track_i++) {
tracks_to_keep.push_back(track_i);
int track_channel_type = 0;
switch (anim->track_get_type(track_i)) {
case Animation::TYPE_POSITION_3D:
track_channel_type = TRACK_CHANNEL_POSITION;
break;
case Animation::TYPE_ROTATION_3D:
track_channel_type = TRACK_CHANNEL_ROTATION;
break;
case Animation::TYPE_SCALE_3D:
track_channel_type = TRACK_CHANNEL_SCALE;
break;
default:
continue;
}
AnimationImportTracks track_mode = import_tracks_mode[track_channel_type];
NodePath path = anim->track_get_path(track_i);
Node *n = p_root->get_node(path);
Node3D *n3d = Object::cast_to<Node3D>(n);
Skeleton3D *skel = Object::cast_to<Skeleton3D>(n);
bool keep_track = false;
Vector3 loc;
Quaternion rot;
Vector3 scale;
if (skel && path.get_subname_count() > 0) {
StringName bone = path.get_subname(0);
int bone_idx = skel->find_bone(bone);
if (bone_idx == -1) {
continue;
}
// Note that this is using get_bone_pose to update the bone pose cache.
Transform3D bone_rest = skel->get_bone_rest(bone_idx);
loc = bone_rest.origin / skel->get_motion_scale();
rot = bone_rest.basis.get_rotation_quaternion();
scale = bone_rest.basis.get_scale();
} else if (n3d) {
loc = n3d->get_position();
rot = n3d->get_transform().basis.get_rotation_quaternion();
scale = n3d->get_scale();
} else {
continue;
}

if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
if (used_tracks[track_channel_type].has(path)) {
if (used_tracks[track_channel_type][path]) {
continue;
}
} else {
used_tracks[track_channel_type].insert(path, false);
}
}

for (int key_i = 0; key_i < anim->track_get_key_count(track_i) && !keep_track; key_i++) {
switch (track_channel_type) {
case TRACK_CHANNEL_POSITION: {
Vector3 key_pos;
anim->position_track_get_key(track_i, key_i, &key_pos);
if (!key_pos.is_equal_approx(loc)) {
keep_track = true;
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
used_tracks[track_channel_type][path] = true;
}
}
} break;
case TRACK_CHANNEL_ROTATION: {
Quaternion key_rot;
anim->rotation_track_get_key(track_i, key_i, &key_rot);
if (!key_rot.is_equal_approx(rot)) {
keep_track = true;
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
used_tracks[track_channel_type][path] = true;
}
}
} break;
case TRACK_CHANNEL_SCALE: {
Vector3 key_scl;
anim->scale_track_get_key(track_i, key_i, &key_scl);
if (!key_scl.is_equal_approx(scale)) {
keep_track = true;
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
used_tracks[track_channel_type][path] = true;
}
}
} break;
default:
break;
}
}
if (track_mode != ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL && !keep_track) {
tracks_to_keep.remove_at(tracks_to_keep.size() - 1);
}
}
for (int dst_track_i = 0; dst_track_i < (int)tracks_to_keep.size(); dst_track_i++) {
int src_track_i = tracks_to_keep[dst_track_i];
if (src_track_i != dst_track_i) {
anim->track_swap(src_track_i, dst_track_i);
}
}
for (int track_i = track_count - 1; track_i >= (int)tracks_to_keep.size(); track_i--) {
anim->remove_track(track_i);
}
}
for (const StringName &name : anims) {
Ref<Animation> anim = ap->get_animation(name);
int track_count = anim->get_track_count();
LocalVector<int> tracks_to_keep;
for (int track_i = 0; track_i < track_count; track_i++) {
tracks_to_keep.push_back(track_i);
int track_channel_type = 0;
switch (anim->track_get_type(track_i)) {
case Animation::TYPE_POSITION_3D:
track_channel_type = TRACK_CHANNEL_POSITION;
break;
case Animation::TYPE_ROTATION_3D:
track_channel_type = TRACK_CHANNEL_ROTATION;
break;
case Animation::TYPE_SCALE_3D:
track_channel_type = TRACK_CHANNEL_SCALE;
break;
default:
continue;
}
AnimationImportTracks track_mode = import_tracks_mode[track_channel_type];
if (track_mode == ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
NodePath path = anim->track_get_path(track_i);
if (used_tracks[track_channel_type].has(path) && !used_tracks[track_channel_type][path]) {
tracks_to_keep.remove_at(tracks_to_keep.size() - 1);
}
}
}
for (int dst_track_i = 0; dst_track_i < (int)tracks_to_keep.size(); dst_track_i++) {
int src_track_i = tracks_to_keep[dst_track_i];
if (src_track_i != dst_track_i) {
anim->track_swap(src_track_i, dst_track_i);
}
}
for (int track_i = track_count - 1; track_i >= (int)tracks_to_keep.size(); track_i--) {
anim->remove_track(track_i);
}
}
}

bool use_optimizer = node_settings["optimizer/enabled"];
float anim_optimizer_linerr = node_settings["optimizer/max_velocity_error"];
Expand All @@ -1094,8 +1252,6 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co
_compress_animations(ap, anim_compression_page_size);
}

List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
Ref<Animation> anim = ap->get_animation(name);
Array animation_slices;
Expand Down Expand Up @@ -2784,9 +2940,10 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (p_options.has(SNAME("animation/fps"))) {
fps = (float)p_options[SNAME("animation/fps")];
}
bool remove_immutable_tracks = p_options.has("animation/remove_immutable_tracks") ? (bool)p_options["animation/remove_immutable_tracks"] : true;
_pre_fix_animations(scene, scene, node_data, animation_data, fps);
_post_fix_node(scene, scene, collision_map, occluder_arrays, scanned_meshes, node_data, material_data, animation_data, fps, apply_root ? root_scale : 1.0);
_post_fix_animations(scene, scene, node_data, animation_data, fps);
_post_fix_animations(scene, scene, node_data, animation_data, fps, remove_immutable_tracks);

String root_type = p_options["nodes/root_type"];
if (!root_type.is_empty()) {
Expand Down
2 changes: 1 addition & 1 deletion editor/import/3d/resource_importer_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ class ResourceImporterScene : public ResourceImporter {
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);
Node *_post_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_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);

Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, const String &p_save_to_path, bool p_keep_custom_tracks);
void _create_slices(AnimationPlayer *ap, Ref<Animation> anim, const Array &p_clips, bool p_bake_all);
Expand Down
5 changes: 2 additions & 3 deletions modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,9 @@ Node *EditorSceneFormatImporterFBX2GLTF::import_scene(const String &p_path, uint

#ifndef DISABLE_DEPRECATED
bool trimming = p_options.has("animation/trimming") ? (bool)p_options["animation/trimming"] : false;
bool remove_immutable = p_options.has("animation/remove_immutable_tracks") ? (bool)p_options["animation/remove_immutable_tracks"] : true;
return gltf->generate_scene(state, (float)p_options["animation/fps"], trimming, remove_immutable);
return gltf->generate_scene(state, (float)p_options["animation/fps"], trimming, false);
#else
return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], (bool)p_options["animation/remove_immutable_tracks"]);
return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], false);
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion modules/fbx/editor/editor_scene_importer_ufbx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t
}
return nullptr;
}
return fbx->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], (bool)p_options["animation/remove_immutable_tracks"]);
return fbx->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], false);
}

Variant EditorSceneFormatImporterUFBX::get_option_visibility(const String &p_path, bool p_for_animation,
Expand Down
5 changes: 2 additions & 3 deletions modules/gltf/editor/editor_scene_importer_blend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,9 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_

#ifndef DISABLE_DEPRECATED
bool trimming = p_options.has("animation/trimming") ? (bool)p_options["animation/trimming"] : false;
bool remove_immutable = p_options.has("animation/remove_immutable_tracks") ? (bool)p_options["animation/remove_immutable_tracks"] : true;
return gltf->generate_scene(state, (float)p_options["animation/fps"], trimming, remove_immutable);
return gltf->generate_scene(state, (float)p_options["animation/fps"], trimming, false);
#else
return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], (bool)p_options["animation/remove_immutable_tracks"]);
return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], false);
Copy link
Member

@TokageItLab TokageItLab May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect that the original implementation of remove_immutable_tracks is completely ignored due to enforcing false here and causing the issue in #91893. I wonder if it needs to be enabled depending on the options as (bool)p_options["animation/remove_immutable_tracks"], in this case such as if the external pose is not being used as a reference for rest. Thoughts? @lyuma @fire

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That argument enables the old option which applies before silhouette fixer and hence will remove tracks inappropriately before silhouette fixer changes the pose. When doing retargeting, it is important for this to be false, and it can always be false.

The remove immutable tracks code in resource_importer_scene has code that should remove scale tracks if they match the rest pose.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But has this PR also changed the order of ApplyNodeScale and RemoveImmutableTrack when you changed the order?

#endif
}

Expand Down
5 changes: 2 additions & 3 deletions modules/gltf/editor/editor_scene_importer_gltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,9 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t

#ifndef DISABLE_DEPRECATED
bool trimming = p_options.has("animation/trimming") ? (bool)p_options["animation/trimming"] : false;
bool remove_immutable = p_options.has("animation/remove_immutable_tracks") ? (bool)p_options["animation/remove_immutable_tracks"] : true;
return gltf->generate_scene(state, (float)p_options["animation/fps"], trimming, remove_immutable);
return gltf->generate_scene(state, (float)p_options["animation/fps"], trimming, false);
#else
return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], (bool)p_options["animation/remove_immutable_tracks"]);
return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], false);
#endif
}

Expand Down
Loading