Merge pull request #53782 from reduz/animation-track-type-import-actions

This commit is contained in:
Rémi Verschelde 2021-10-15 13:47:31 +02:00 committed by GitHub
commit e53e897b8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 160 additions and 10 deletions

View file

@ -779,6 +779,16 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
}
}
}
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"]))
};
if (anims.size() > 1 && (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)) {
_optimize_track_usage(ap, import_tracks_mode);
}
}
}
@ -1024,9 +1034,9 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_linear_error"), 0.05));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error"), 0.01));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angle"), 22));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Always,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/rotation", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Always,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/scale", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Always,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/rotation", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/scale", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
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));
for (int i = 0; i < 256; i++) {
@ -1448,6 +1458,139 @@ void ResourceImporterScene::_add_shapes(Node *p_node, const Vector<Ref<Shape3D>>
}
}
void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions) {
List<StringName> anims;
p_player->get_animation_list(&anims);
Node *parent = p_player->get_parent();
ERR_FAIL_COND(parent == nullptr);
OrderedHashMap<NodePath, uint32_t> used_tracks[TRACK_CHANNEL_MAX];
bool tracks_to_add = false;
static const Animation::TrackType track_types[TRACK_CHANNEL_MAX] = { Animation::TYPE_POSITION_3D, Animation::TYPE_ROTATION_3D, Animation::TYPE_SCALE_3D };
for (const StringName &I : anims) {
Ref<Animation> anim = p_player->get_animation(I);
for (int i = 0; i < anim->get_track_count(); i++) {
for (int j = 0; j < TRACK_CHANNEL_MAX; j++) {
if (anim->track_get_type(i) != track_types[j]) {
continue;
}
switch (p_track_actions[j]) {
case ANIMATION_IMPORT_TRACKS_IF_PRESENT: {
// Do Nothing.
} break;
case ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL: {
used_tracks[j].insert(anim->track_get_path(i), 0);
tracks_to_add = true;
} break;
case ANIMATION_IMPORT_TRACKS_NEVER: {
anim->remove_track(i);
i--;
} break;
}
}
}
}
if (!tracks_to_add) {
return;
}
uint32_t pass = 0;
for (const StringName &I : anims) {
Ref<Animation> anim = p_player->get_animation(I);
for (int j = 0; j < TRACK_CHANNEL_MAX; j++) {
if (p_track_actions[j] != ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL) {
continue;
}
pass++;
for (int i = 0; i < anim->get_track_count(); i++) {
if (anim->track_get_type(i) != track_types[j]) {
continue;
}
NodePath path = anim->track_get_path(i);
ERR_CONTINUE(!used_tracks[j].has(path)); // Should never happen.
used_tracks[j][path] = pass;
}
for (OrderedHashMap<NodePath, uint32_t>::Element J = used_tracks[j].front(); J; J = J.next()) {
if (J.get() == pass) {
continue;
}
NodePath path = J.key();
Node *n = parent->get_node(path);
Skeleton3D *skel = Object::cast_to<Skeleton3D>(n);
Node3D *n3d = Object::cast_to<Node3D>(n);
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;
}
skel->get_bone_pose(bone_idx);
loc = skel->get_bone_pose_position(bone_idx);
rot = skel->get_bone_pose_rotation(bone_idx);
scale = skel->get_bone_pose_scale(bone_idx);
} else if (n3d) {
loc = n3d->get_position();
rot = n3d->get_transform().basis.get_rotation_quaternion();
scale = n3d->get_scale();
} else {
continue;
}
// Ensure insertion keeps tracks together and ordered by type (loc/rot/scale)
int insert_at_pos = -1;
for (int k = 0; k < anim->get_track_count(); k++) {
NodePath tpath = anim->track_get_path(k);
if (path == tpath) {
Animation::TrackType ttype = anim->track_get_type(k);
if (insert_at_pos == -1) {
// First insert, determine whether replacing or kicking back
if (track_types[j] < ttype) {
insert_at_pos = k;
break; // No point in continuing.
} else {
insert_at_pos = k + 1;
}
} else if (ttype < track_types[j]) {
// Kick back.
insert_at_pos = k + 1;
}
} else if (insert_at_pos >= 0) {
break;
}
}
int track_idx = anim->add_track(track_types[j], insert_at_pos);
anim->track_set_path(track_idx, path);
anim->track_set_imported(track_idx, true);
switch (j) {
case TRACK_CHANNEL_POSITION: {
anim->position_track_insert_key(track_idx, 0, loc);
} break;
case TRACK_CHANNEL_ROTATION: {
anim->rotation_track_insert_key(track_idx, 0, rot);
} break;
case TRACK_CHANNEL_SCALE: {
anim->scale_track_insert_key(track_idx, 0, scale);
} break;
default: {
}
}
}
}
}
}
Node *ResourceImporterScene::pre_import(const String &p_source_file) {
Ref<EditorSceneImporter> importer;
String ext = p_source_file.get_extension().to_lower();

View file

@ -65,13 +65,6 @@ public:
IMPORT_USE_NAMED_SKIN_BINDS = 16,
};
enum AnimationImportBoneTracks {
ANIMATION_IMPORT_BONE_TRACKS_IF_PRESENT,
ANIMATION_IMPORT_BONE_TRACKS_IF_PRESENT_FOR_ALL,
ANIMATION_IMPORT_BONE_TRACKS_ALWAYS,
ANIMATION_IMPORT_BONE_TRACKS_NEVER,
};
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
@ -151,6 +144,20 @@ class ResourceImporterScene : public ResourceImporter {
void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
void _add_shapes(Node *p_node, const Vector<Ref<Shape3D>> &p_shapes);
enum AnimationImportTracks {
ANIMATION_IMPORT_TRACKS_IF_PRESENT,
ANIMATION_IMPORT_TRACKS_IF_PRESENT_FOR_ALL,
ANIMATION_IMPORT_TRACKS_NEVER,
};
enum TrackChannel {
TRACK_CHANNEL_POSITION,
TRACK_CHANNEL_ROTATION,
TRACK_CHANNEL_SCALE,
TRACK_CHANNEL_MAX
};
void _optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions);
public:
static ResourceImporterScene *get_singleton() { return singleton; }