summaryrefslogtreecommitdiff
path: root/editor/import
diff options
context:
space:
mode:
Diffstat (limited to 'editor/import')
-rw-r--r--editor/import/editor_import_collada.cpp148
-rw-r--r--editor/import/editor_importer_bake_reset.cpp234
-rw-r--r--editor/import/editor_importer_bake_reset.h54
-rw-r--r--editor/import/resource_importer_scene.cpp230
-rw-r--r--editor/import/resource_importer_scene.h14
5 files changed, 295 insertions, 385 deletions
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 4b01595028..d1bacf54de 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -91,8 +91,8 @@ struct ColladaImport {
Error _create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ImporterMesh>> p_morph_meshes = Vector<Ref<ImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false);
void _fix_param_animation_tracks();
- void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks);
- void create_animations(bool p_make_tracks_in_all_bones, bool p_import_value_tracks);
+ void create_animation(int p_clip, bool p_import_value_tracks);
+ void create_animations(bool p_import_value_tracks);
Set<String> tracks_in_clips;
Vector<String> missing_textures;
@@ -120,6 +120,15 @@ Error ColladaImport::_populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p
skeleton_bone_map[p_skeleton][joint->sid] = r_bone;
+ {
+ Transform3D xform = joint->compute_transform(collada);
+ collada.fix_transform(xform) * joint->post_transform;
+
+ p_skeleton->set_bone_pose_position(r_bone, xform.origin);
+ p_skeleton->set_bone_pose_rotation(r_bone, xform.basis.get_rotation_quaternion());
+ p_skeleton->set_bone_pose_scale(r_bone, xform.basis.get_scale());
+ }
+
if (collada.state.bone_rest_map.has(joint->sid)) {
p_skeleton->set_bone_rest(r_bone, collada.fix_transform(collada.state.bone_rest_map[joint->sid]));
//should map this bone to something for animation?
@@ -1384,7 +1393,7 @@ void ColladaImport::_fix_param_animation_tracks() {
}
}
-void ColladaImport::create_animations(bool p_make_tracks_in_all_bones, bool p_import_value_tracks) {
+void ColladaImport::create_animations(bool p_import_value_tracks) {
_fix_param_animation_tracks();
for (int i = 0; i < collada.state.animation_clips.size(); i++) {
for (int j = 0; j < collada.state.animation_clips[i].tracks.size(); j++) {
@@ -1417,13 +1426,13 @@ void ColladaImport::create_animations(bool p_make_tracks_in_all_bones, bool p_im
}
}
- create_animation(-1, p_make_tracks_in_all_bones, p_import_value_tracks);
+ create_animation(-1, p_import_value_tracks);
for (int i = 0; i < collada.state.animation_clips.size(); i++) {
- create_animation(i, p_make_tracks_in_all_bones, p_import_value_tracks);
+ create_animation(i, p_import_value_tracks);
}
}
-void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks) {
+void ColladaImport::create_animation(int p_clip, bool p_import_value_tracks) {
Ref<Animation> animation = Ref<Animation>(memnew(Animation));
if (p_clip == -1) {
@@ -1522,10 +1531,55 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
continue;
}
- animation->add_track(Animation::TYPE_TRANSFORM3D);
- int track = animation->get_track_count() - 1;
- animation->track_set_path(track, path);
- animation->track_set_imported(track, true); //helps merging later
+ bool has_position = false;
+ bool has_rotation = false;
+ bool has_scale = false;
+
+ for (int i = 0; cn->xform_list.size(); i++) {
+ switch (cn->xform_list[i].op) {
+ case Collada::Node::XForm::OP_ROTATE: {
+ has_rotation = true;
+ } break;
+ case Collada::Node::XForm::OP_SCALE: {
+ has_scale = true;
+ } break;
+ case Collada::Node::XForm::OP_TRANSLATE: {
+ has_position = true;
+ } break;
+ case Collada::Node::XForm::OP_MATRIX: {
+ has_position = true;
+ has_rotation = true;
+ has_scale = true;
+ } break;
+ case Collada::Node::XForm::OP_VISIBILITY: {
+ } break;
+ }
+ }
+
+ int base_track = animation->get_track_count();
+ int position_idx = -1;
+ if (has_position) {
+ position_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_POSITION_3D);
+ animation->track_set_path(position_idx, path);
+ animation->track_set_imported(position_idx, true); //helps merging later
+ }
+
+ int rotation_idx = -1;
+ if (has_rotation) {
+ rotation_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_ROTATION_3D);
+ animation->track_set_path(rotation_idx, path);
+ animation->track_set_imported(rotation_idx, true); //helps merging later
+ }
+
+ int scale_idx = -1;
+ if (has_scale) {
+ scale_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_SCALE_3D);
+ animation->track_set_path(scale_idx, path);
+ animation->track_set_imported(scale_idx, true); //helps merging later
+ }
Vector<real_t> snapshots = base_snapshots;
@@ -1594,22 +1648,21 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
Transform3D xform = cn->compute_transform(collada);
xform = collada.fix_transform(xform) * cn->post_transform;
- if (nm.bone >= 0) {
- //make bone transform relative to rest (in case of skeleton)
- Skeleton3D *sk = Object::cast_to<Skeleton3D>(nm.node);
- if (sk) {
- xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
- } else {
- ERR_PRINT("Collada: Invalid skeleton");
- }
- }
-
Vector3 s = xform.basis.get_scale();
bool singular_matrix = Math::is_zero_approx(s.x) || Math::is_zero_approx(s.y) || Math::is_zero_approx(s.z);
- Quaternion q = singular_matrix ? Quaternion() : xform.basis.get_rotation_quaternion();
+ Quaternion q = singular_matrix ? Quaternion() :
+ xform.basis.get_rotation_quaternion();
Vector3 l = xform.origin;
- animation->transform_track_insert_key(track, snapshots[i], l, q, s);
+ if (position_idx >= 0) {
+ animation->position_track_insert_key(position_idx, snapshots[i], l);
+ }
+ if (rotation_idx >= 0) {
+ animation->rotation_track_insert_key(rotation_idx, snapshots[i], q);
+ }
+ if (scale_idx >= 0) {
+ animation->scale_track_insert_key(scale_idx, snapshots[i], s);
+ }
}
if (nm.bone >= 0) {
@@ -1621,48 +1674,15 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
if (found_anim) {
tracks_found = true;
} else {
- animation->remove_track(track);
- }
- }
-
- if (p_make_tracks_in_all_bones) {
- //some bones may lack animation, but since we don't store pose as a property, we must add keyframes!
- for (const KeyValue<String, bool> &E : bones_with_animation) {
- if (E.value) {
- continue;
+ if (position_idx >= 0) {
+ animation->remove_track(base_track);
}
-
- NodeMap &nm = node_map[E.key];
- String path = scene->get_path_to(nm.node);
- ERR_CONTINUE(nm.bone < 0);
- Skeleton3D *sk = static_cast<Skeleton3D *>(nm.node);
- String name = sk->get_bone_name(nm.bone);
- path = path + ":" + name;
-
- Collada::Node *cn = collada.state.scene_map[E.key];
- if (cn->ignore_anim) {
- WARN_PRINT("Collada: Ignoring animation on node: " + path);
- continue;
+ if (rotation_idx >= 0) {
+ animation->remove_track(base_track);
+ }
+ if (scale_idx >= 0) {
+ animation->remove_track(base_track);
}
-
- animation->add_track(Animation::TYPE_TRANSFORM3D);
- int track = animation->get_track_count() - 1;
- animation->track_set_path(track, path);
- animation->track_set_imported(track, true); //helps merging later
-
- Transform3D xform = cn->compute_transform(collada);
- xform = collada.fix_transform(xform) * cn->post_transform;
-
- xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
-
- Vector3 s = xform.basis.get_scale();
- bool singular_matrix = Math::is_zero_approx(s.x) || Math::is_zero_approx(s.y) || Math::is_zero_approx(s.z);
- Quaternion q = singular_matrix ? Quaternion() : xform.basis.get_rotation_quaternion();
- Vector3 l = xform.origin;
-
- animation->transform_track_insert_key(track, 0, l, q, s);
-
- tracks_found = true;
}
}
@@ -1773,7 +1793,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
}
if (p_flags & IMPORT_ANIMATION) {
- state.create_animations(true, true);
+ state.create_animations(true);
AnimationPlayer *ap = memnew(AnimationPlayer);
for (int i = 0; i < state.animations.size(); i++) {
String name;
@@ -1800,7 +1820,7 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
Error err = state.load(p_path, Collada::IMPORT_FLAG_ANIMATION, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS);
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load animation from file '" + p_path + "'.");
- state.create_animations(true, true);
+ state.create_animations(true);
if (state.scene) {
memdelete(state.scene);
}
diff --git a/editor/import/editor_importer_bake_reset.cpp b/editor/import/editor_importer_bake_reset.cpp
deleted file mode 100644
index 451a07351c..0000000000
--- a/editor/import/editor_importer_bake_reset.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*************************************************************************/
-/* editor_importer_bake_reset.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "editor/import/editor_importer_bake_reset.h"
-
-#include "core/error/error_list.h"
-#include "core/error/error_macros.h"
-#include "core/math/transform_3d.h"
-#include "resource_importer_scene.h"
-#include "scene/3d/importer_mesh_instance_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/node_3d.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/animation/animation_player.h"
-
-// Given that an engineering team has made a reference character, one wants ten animators to create animations.
-// Currently, a tech artist needs to combine the ten files into one exported gltf2 to import into Godot Engine.
-// We bake the RESET animation and then set it to identity,
-// so that rigs with corresponding RESET animation can have their animations transferred with ease.
-//
-// The original algorithm for the code was used to change skeleton bone rolls to be parent to child.
-//
-// Reference https://github.com/godotengine/godot-proposals/issues/2961
-void BakeReset::_bake_animation_pose(Node *scene, const String &p_bake_anim) {
- Map<StringName, BakeResetRestBone> r_rest_bones;
- Vector<Node3D *> r_meshes;
- List<Node *> queue;
- queue.push_back(scene);
- while (!queue.is_empty()) {
- List<Node *>::Element *E = queue.front();
- Node *node = E->get();
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(node);
- // Step 1: import scene with animations into the rest bones data structure.
- _fetch_reset_animation(ap, r_rest_bones, p_bake_anim);
-
- int child_count = node->get_child_count();
- for (int i = 0; i < child_count; i++) {
- queue.push_back(node->get_child(i));
- }
- queue.pop_front();
- }
-
- queue.push_back(scene);
- while (!queue.is_empty()) {
- List<Node *>::Element *E = queue.front();
- Node *node = E->get();
- ImporterMeshInstance3D *editor_mesh_3d = scene->cast_to<ImporterMeshInstance3D>(node);
- MeshInstance3D *mesh_3d = scene->cast_to<MeshInstance3D>(node);
- if (scene->cast_to<Skeleton3D>(node)) {
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
-
- // Step 2: Bake the RESET animation from the RestBone to the skeleton.
- _fix_skeleton(skeleton, r_rest_bones);
- }
- if (editor_mesh_3d) {
- NodePath path = editor_mesh_3d->get_skeleton_path();
- if (!path.is_empty() && editor_mesh_3d->get_node_or_null(path) && Object::cast_to<Skeleton3D>(editor_mesh_3d->get_node_or_null(path))) {
- r_meshes.push_back(editor_mesh_3d);
- }
- } else if (mesh_3d) {
- NodePath path = mesh_3d->get_skeleton_path();
- if (!path.is_empty() && mesh_3d->get_node_or_null(path) && Object::cast_to<Skeleton3D>(mesh_3d->get_node_or_null(path))) {
- r_meshes.push_back(mesh_3d);
- }
- }
- int child_count = node->get_child_count();
- for (int i = 0; i < child_count; i++) {
- queue.push_back(node->get_child(i));
- }
- queue.pop_front();
- }
-
- queue.push_back(scene);
- while (!queue.is_empty()) {
- List<Node *>::Element *E = queue.front();
- Node *node = E->get();
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(node);
- if (ap) {
- // Step 3: Key all RESET animation frames to identity.
- _align_animations(ap, r_rest_bones);
- }
-
- int child_count = node->get_child_count();
- for (int i = 0; i < child_count; i++) {
- queue.push_back(node->get_child(i));
- }
- queue.pop_front();
- }
-}
-
-void BakeReset::_align_animations(AnimationPlayer *p_ap, const Map<StringName, BakeResetRestBone> &r_rest_bones) {
- ERR_FAIL_NULL(p_ap);
- List<StringName> anim_names;
- p_ap->get_animation_list(&anim_names);
- for (List<StringName>::Element *anim_i = anim_names.front(); anim_i; anim_i = anim_i->next()) {
- Ref<Animation> a = p_ap->get_animation(anim_i->get());
- ERR_CONTINUE(a.is_null());
- for (const KeyValue<StringName, BakeResetRestBone> &rest_bone_i : r_rest_bones) {
- int track = a->find_track(NodePath(rest_bone_i.key));
- if (track == -1) {
- continue;
- }
- int new_track = a->add_track(Animation::TYPE_TRANSFORM3D);
- NodePath new_path = NodePath(rest_bone_i.key);
- const BakeResetRestBone rest_bone = rest_bone_i.value;
- a->track_set_path(new_track, new_path);
- for (int key_i = 0; key_i < a->track_get_key_count(track); key_i++) {
- Vector3 loc;
- Quaternion rot;
- Vector3 scale;
- Error err = a->transform_track_get_key(track, key_i, &loc, &rot, &scale);
- ERR_CONTINUE(err);
- real_t time = a->track_get_key_time(track, key_i);
- rot.normalize();
- loc = loc - rest_bone.loc;
- rot = rest_bone.rest_delta.get_rotation_quaternion().inverse() * rot;
- rot.normalize();
- scale = Vector3(1, 1, 1) - (rest_bone.rest_delta.get_scale() - scale);
- // Apply the reverse of the rest changes to make the key be close to identity transform.
- a->transform_track_insert_key(new_track, time, loc, rot, scale);
- }
- a->remove_track(track);
- }
- }
-}
-
-void BakeReset::_fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, BakeResetRestBone> &r_rest_bones, const String &p_bake_anim) {
- if (!p_ap) {
- return;
- }
- List<StringName> anim_names;
- p_ap->get_animation_list(&anim_names);
- Node *root = p_ap->get_owner();
- ERR_FAIL_NULL(root);
- if (!p_ap->has_animation(p_bake_anim)) {
- return;
- }
- Ref<Animation> a = p_ap->get_animation(p_bake_anim);
- if (a.is_null()) {
- return;
- }
- for (int32_t track = 0; track < a->get_track_count(); track++) {
- NodePath path = a->track_get_path(track);
- String string_path = path;
- Skeleton3D *skeleton = root->cast_to<Skeleton3D>(root->get_node(string_path.get_slice(":", 0)));
- if (!skeleton) {
- continue;
- }
- String bone_name = string_path.get_slice(":", 1);
- for (int key_i = 0; key_i < a->track_get_key_count(track); key_i++) {
- Vector3 loc;
- Quaternion rot;
- Vector3 scale;
- Error err = a->transform_track_get_key(track, key_i, &loc, &rot, &scale);
- if (err != OK) {
- ERR_PRINT_ONCE("Reset animation baker can't get key.");
- continue;
- }
- rot.normalize();
- Basis rot_basis = Basis(rot, scale);
- BakeResetRestBone rest_bone;
- rest_bone.rest_delta = rot_basis;
- rest_bone.loc = loc;
- // Store the animation into the RestBone.
- r_rest_bones[StringName(String(skeleton->get_owner()->get_path_to(skeleton)) + ":" + bone_name)] = rest_bone;
- break;
- }
- }
-}
-
-void BakeReset::_fix_skeleton(Skeleton3D *p_skeleton, Map<StringName, BakeReset::BakeResetRestBone> &r_rest_bones) {
- int bone_count = p_skeleton->get_bone_count();
-
- // First iterate through all the bones and update the RestBone.
- for (int j = 0; j < bone_count; j++) {
- StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(j);
- BakeResetRestBone &rest_bone = r_rest_bones[final_path];
- rest_bone.rest_local = p_skeleton->get_bone_rest(j);
- }
- for (int i = 0; i < bone_count; i++) {
- int parent_bone = p_skeleton->get_bone_parent(i);
- String path = p_skeleton->get_owner()->get_path_to(p_skeleton);
- StringName final_path = String(path) + String(":") + p_skeleton->get_bone_name(parent_bone);
- if (parent_bone >= 0) {
- r_rest_bones[path].children.push_back(i);
- }
- }
-
- // When we apply transform to a bone, we also have to move all of its children in the opposite direction.
- for (int i = 0; i < bone_count; i++) {
- StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(i);
- r_rest_bones[final_path].rest_local = r_rest_bones[final_path].rest_local * Transform3D(r_rest_bones[final_path].rest_delta, r_rest_bones[final_path].loc);
- // Iterate through the children and move in the opposite direction.
- for (int j = 0; j < r_rest_bones[final_path].children.size(); j++) {
- int child_index = r_rest_bones[final_path].children[j];
- StringName children_path = String(p_skeleton->get_name()) + String(":") + p_skeleton->get_bone_name(child_index);
- r_rest_bones[children_path].rest_local = Transform3D(r_rest_bones[final_path].rest_delta, r_rest_bones[final_path].loc).affine_inverse() * r_rest_bones[children_path].rest_local;
- }
- }
-
- for (int i = 0; i < bone_count; i++) {
- StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(i);
- ERR_CONTINUE(!r_rest_bones.has(final_path));
- Transform3D rest_transform = r_rest_bones[final_path].rest_local;
- p_skeleton->set_bone_rest(i, rest_transform);
- }
-}
diff --git a/editor/import/editor_importer_bake_reset.h b/editor/import/editor_importer_bake_reset.h
deleted file mode 100644
index e36ae86181..0000000000
--- a/editor/import/editor_importer_bake_reset.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*************************************************************************/
-/* editor_importer_bake_reset.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef RESOURCE_IMPORTER_BAKE_RESET_H
-#define RESOURCE_IMPORTER_BAKE_RESET_H
-
-#include "scene/main/node.h"
-
-class Skeleton3D;
-class AnimationPlayer;
-class BakeReset {
- struct BakeResetRestBone {
- Transform3D rest_local;
- Basis rest_delta;
- Vector3 loc;
- Vector<int> children;
- };
-
-public:
- void _bake_animation_pose(Node *scene, const String &p_bake_anim);
-
-private:
- void _fix_skeleton(Skeleton3D *p_skeleton, Map<StringName, BakeReset::BakeResetRestBone> &r_rest_bones);
- void _align_animations(AnimationPlayer *p_ap, const Map<StringName, BakeResetRestBone> &r_rest_bones);
- void _fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, BakeResetRestBone> &r_rest_bones, const String &p_bake_anim);
-};
-#endif
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 1e93113488..1780aed4cb 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -32,7 +32,7 @@
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
-#include "editor/import/editor_importer_bake_reset.h"
+
#include "editor/import/scene_import_settings.h"
#include "scene/3d/area_3d.h"
#include "scene/3d/collision_shape_3d.h"
@@ -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);
+ }
}
}
@@ -851,42 +861,57 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
if (kt > (from + 0.01) && k > 0) {
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
- Quaternion q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
+ default_anim->position_track_interpolate(j, from, &p);
+ new_anim->position_track_insert_key(dtrack, 0, p);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ Quaternion r;
+ default_anim->rotation_track_interpolate(j, from, &r);
+ new_anim->rotation_track_insert_key(dtrack, 0, r);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->transform_track_interpolate(j, from, &p, &q, &s);
- new_anim->transform_track_insert_key(dtrack, 0, p, q, s);
- }
- if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ default_anim->scale_track_interpolate(j, from, &s);
+ new_anim->scale_track_insert_key(dtrack, 0, s);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->value_track_interpolate(j, from);
new_anim->track_insert_key(dtrack, 0, var);
}
}
}
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
- Quaternion q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
+ default_anim->position_track_get_key(j, k, &p);
+ new_anim->position_track_insert_key(dtrack, kt - from, p);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ Quaternion r;
+ default_anim->rotation_track_get_key(j, k, &r);
+ new_anim->rotation_track_insert_key(dtrack, kt - from, r);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->transform_track_get_key(j, k, &p, &q, &s);
- new_anim->transform_track_insert_key(dtrack, kt - from, p, q, s);
- }
- if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ default_anim->scale_track_get_key(j, k, &s);
+ new_anim->scale_track_insert_key(dtrack, kt - from, s);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->track_get_key_value(j, k);
new_anim->track_insert_key(dtrack, kt - from, var);
}
}
if (dtrack != -1 && kt >= to) {
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
- Quaternion q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
+ default_anim->position_track_interpolate(j, to, &p);
+ new_anim->position_track_insert_key(dtrack, to - from, p);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ Quaternion r;
+ default_anim->rotation_track_interpolate(j, to, &r);
+ new_anim->rotation_track_insert_key(dtrack, to - from, r);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->transform_track_interpolate(j, to, &p, &q, &s);
- new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
- }
- if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ default_anim->scale_track_interpolate(j, to, &s);
+ new_anim->scale_track_insert_key(dtrack, to - from, s);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->value_track_interpolate(j, to);
new_anim->track_insert_key(dtrack, to - from, var);
}
@@ -897,16 +922,25 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
new_anim->add_track(default_anim->track_get_type(j));
dtrack = new_anim->get_track_count() - 1;
new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
- Quaternion q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
+ default_anim->position_track_interpolate(j, from, &p);
+ new_anim->position_track_insert_key(dtrack, 0, p);
+ default_anim->position_track_interpolate(j, to, &p);
+ new_anim->position_track_insert_key(dtrack, to - from, p);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ Quaternion r;
+ default_anim->rotation_track_interpolate(j, from, &r);
+ new_anim->rotation_track_insert_key(dtrack, 0, r);
+ default_anim->rotation_track_interpolate(j, to, &r);
+ new_anim->rotation_track_insert_key(dtrack, to - from, r);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->transform_track_interpolate(j, from, &p, &q, &s);
- new_anim->transform_track_insert_key(dtrack, 0, p, q, s);
- default_anim->transform_track_interpolate(j, to, &p, &q, &s);
- new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
- }
- if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ default_anim->scale_track_interpolate(j, from, &s);
+ new_anim->scale_track_insert_key(dtrack, 0, s);
+ default_anim->scale_track_interpolate(j, to, &s);
+ new_anim->scale_track_insert_key(dtrack, to - from, s);
+ } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->value_track_interpolate(j, from);
new_anim->track_insert_key(dtrack, 0, var);
Variant to_var = default_anim->value_track_interpolate(j, to);
@@ -1000,6 +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,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++) {
@@ -1171,7 +1208,6 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/bake_reset_animation"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
@@ -1422,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();
@@ -1533,11 +1702,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
_pre_fix_node(scene, scene, collision_map);
_post_fix_node(scene, scene, collision_map, scanned_meshes, node_data, material_data, animation_data, fps);
- bool use_bake_reset_animation = p_options["animation/bake_reset_animation"];
- if (use_bake_reset_animation) {
- BakeReset bake_reset;
- bake_reset._bake_animation_pose(scene, "RESET");
- }
String root_type = p_options["nodes/root_type"];
root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class.
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 2a67fa9aae..a612de940a 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -144,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; }