summaryrefslogtreecommitdiff
path: root/scene/animation
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation')
-rw-r--r--scene/animation/animation_cache.cpp314
-rw-r--r--scene/animation/animation_cache.h84
-rw-r--r--scene/animation/animation_player.cpp168
-rw-r--r--scene/animation/animation_player.h7
-rw-r--r--scene/animation/animation_tree.cpp253
-rw-r--r--scene/animation/animation_tree.h5
6 files changed, 353 insertions, 478 deletions
diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp
deleted file mode 100644
index 56743007e4..0000000000
--- a/scene/animation/animation_cache.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/*************************************************************************/
-/* animation_cache.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 "animation_cache.h"
-
-void AnimationCache::_node_exit_tree(Node *p_node) {
- //it is one shot, so it disconnects upon arrival
-
- ERR_FAIL_COND(!connected_nodes.has(p_node));
-
- connected_nodes.erase(p_node);
-
- for (int i = 0; i < path_cache.size(); i++) {
- if (path_cache[i].node != p_node) {
- continue;
- }
-
- path_cache.write[i].valid = false; //invalidate path cache
- }
-}
-
-void AnimationCache::_animation_changed() {
- _clear_cache();
-}
-
-void AnimationCache::_clear_cache() {
- while (connected_nodes.size()) {
- connected_nodes.front()->get()->disconnect("tree_exiting", callable_mp(this, &AnimationCache::_node_exit_tree));
- connected_nodes.erase(connected_nodes.front());
- }
- path_cache.clear();
- cache_valid = false;
- cache_dirty = true;
-}
-
-void AnimationCache::_update_cache() {
- cache_valid = false;
-
- ERR_FAIL_COND(!root);
- ERR_FAIL_COND(!root->is_inside_tree());
- ERR_FAIL_COND(animation.is_null());
-
- for (int i = 0; i < animation->get_track_count(); i++) {
- NodePath np = animation->track_get_path(i);
-
- Node *node = root->get_node(np);
- if (!node) {
- path_cache.push_back(Path());
- ERR_CONTINUE_MSG(!node, "Invalid track path in animation '" + np + "'.");
- }
-
- Path path;
-
- Ref<Resource> res;
-
- if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D) {
-#ifndef _3D_DISABLED
- if (np.get_subname_count() > 1) {
- path_cache.push_back(Path());
- ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D, "Transform tracks can't have a subpath '" + np + "'.");
- }
-
- Node3D *sp = Object::cast_to<Node3D>(node);
-
- if (!sp) {
- path_cache.push_back(Path());
- ERR_CONTINUE_MSG(!sp, "Transform track not of type Node3D '" + np + "'.");
- }
-
- if (np.get_subname_count() == 1) {
- StringName property = np.get_subname(0);
- String ps = property;
-
- Skeleton3D *sk = Object::cast_to<Skeleton3D>(node);
- if (!sk) {
- path_cache.push_back(Path());
- ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton! '" + np + "'.");
- }
-
- int idx = sk->find_bone(ps);
- if (idx == -1) {
- path_cache.push_back(Path());
- ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone! '" + np + "'.");
- }
-
- path.bone_idx = idx;
- path.skeleton = sk;
- }
-
- path.node_3d = sp;
-#endif // _3D_DISABLED
- } else {
- if (np.get_subname_count() > 0) {
- RES res2;
- Vector<StringName> leftover_subpath;
-
- // We don't want to cache the last resource unless it is a method call
- bool is_method = animation->track_get_type(i) == Animation::TYPE_METHOD;
- root->get_node_and_resource(np, res2, leftover_subpath, is_method);
-
- if (res2.is_valid()) {
- path.resource = res2;
- } else {
- path.node = node;
- }
- path.object = res2.is_valid() ? res2.ptr() : (Object *)node;
- path.subpath = leftover_subpath;
-
- } else {
- path.node = node;
- path.object = node;
- path.subpath = np.get_subnames();
- }
- }
-
- if (animation->track_get_type(i) == Animation::TYPE_VALUE) {
- if (np.get_subname_count() == 0) {
- path_cache.push_back(Path());
- ERR_CONTINUE_MSG(np.get_subname_count() == 0, "Value Track lacks property: " + np + ".");
- }
-
- } else if (animation->track_get_type(i) == Animation::TYPE_METHOD) {
- if (path.subpath.size() != 0) { // Trying to call a method of a non-resource
-
- path_cache.push_back(Path());
- ERR_CONTINUE_MSG(path.subpath.size() != 0, "Method Track has property: " + np + ".");
- }
- }
-
- path.valid = true;
-
- path_cache.push_back(path);
-
- if (!connected_nodes.has(path.node)) {
- connected_nodes.insert(path.node);
- path.node->connect("tree_exiting", callable_mp(this, &AnimationCache::_node_exit_tree), Node::make_binds(path.node), CONNECT_ONESHOT);
- }
- }
-
- cache_dirty = false;
- cache_valid = true;
-}
-
-void AnimationCache::set_track_transform(int p_idx, const Transform3D &p_transform) {
- if (cache_dirty) {
- _update_cache();
- }
-
- ERR_FAIL_COND(!cache_valid);
- ERR_FAIL_INDEX(p_idx, path_cache.size());
- Path &p = path_cache.write[p_idx];
- if (!p.valid) {
- return;
- }
-
-#ifndef _3D_DISABLED
- ERR_FAIL_COND(!p.node);
- ERR_FAIL_COND(!p.node_3d);
-
- if (p.skeleton) {
- p.skeleton->set_bone_pose(p.bone_idx, p_transform);
- } else {
- p.node_3d->set_transform(p_transform);
- }
-#endif // _3D_DISABLED
-}
-
-void AnimationCache::set_track_value(int p_idx, const Variant &p_value) {
- if (cache_dirty) {
- _update_cache();
- }
-
- ERR_FAIL_COND(!cache_valid);
- ERR_FAIL_INDEX(p_idx, path_cache.size());
- Path &p = path_cache.write[p_idx];
- if (!p.valid) {
- return;
- }
-
- ERR_FAIL_COND(!p.object);
- p.object->set_indexed(p.subpath, p_value);
-}
-
-void AnimationCache::call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (cache_dirty) {
- _update_cache();
- }
-
- ERR_FAIL_COND(!cache_valid);
- ERR_FAIL_INDEX(p_idx, path_cache.size());
- Path &p = path_cache.write[p_idx];
- if (!p.valid) {
- return;
- }
-
- ERR_FAIL_COND(!p.object);
- p.object->call(p_method, p_args, p_argcount, r_error);
-}
-
-void AnimationCache::set_all(float p_time, float p_delta) {
- if (cache_dirty) {
- _update_cache();
- }
-
- ERR_FAIL_COND(!cache_valid);
-
- int tc = animation->get_track_count();
- for (int i = 0; i < tc; i++) {
- switch (animation->track_get_type(i)) {
- case Animation::TYPE_TRANSFORM3D: {
- Vector3 loc, scale;
- Quaternion rot;
- animation->transform_track_interpolate(i, p_time, &loc, &rot, &scale);
- Transform3D tr(Basis(rot), loc);
- tr.basis.scale(scale);
-
- set_track_transform(i, tr);
-
- } break;
- case Animation::TYPE_VALUE: {
- if (animation->value_track_get_update_mode(i) == Animation::UPDATE_CONTINUOUS || (animation->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE && p_delta == 0)) {
- Variant v = animation->value_track_interpolate(i, p_time);
- set_track_value(i, v);
- } else {
- List<int> indices;
- animation->value_track_get_key_indices(i, p_time, p_delta, &indices);
-
- for (int &E : indices) {
- Variant v = animation->track_get_key_value(i, E);
- set_track_value(i, v);
- }
- }
-
- } break;
- case Animation::TYPE_METHOD: {
- List<int> indices;
- animation->method_track_get_key_indices(i, p_time, p_delta, &indices);
-
- for (int &E : indices) {
- Vector<Variant> args = animation->method_track_get_params(i, E);
- StringName name = animation->method_track_get_name(i, E);
- Callable::CallError err;
-
- if (!args.size()) {
- call_track(i, name, nullptr, 0, err);
- } else {
- Vector<const Variant *> argptrs;
- argptrs.resize(args.size());
- for (int j = 0; j < args.size(); j++) {
- argptrs.write[j] = &args.write[j];
- }
-
- call_track(i, name, (const Variant **)&argptrs[0], args.size(), err);
- }
- }
-
- } break;
- default: {
- }
- }
- }
-}
-
-void AnimationCache::set_animation(const Ref<Animation> &p_animation) {
- _clear_cache();
-
- if (animation.is_valid()) {
- animation->disconnect("changed", callable_mp(this, &AnimationCache::_animation_changed));
- }
-
- animation = p_animation;
-
- if (animation.is_valid()) {
- animation->connect("changed", callable_mp(this, &AnimationCache::_animation_changed));
- }
-}
-
-void AnimationCache::_bind_methods() {
-}
-
-void AnimationCache::set_root(Node *p_root) {
- _clear_cache();
- root = p_root;
-}
-
-AnimationCache::AnimationCache() {
-}
diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h
deleted file mode 100644
index c856e644f7..0000000000
--- a/scene/animation/animation_cache.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*************************************************************************/
-/* animation_cache.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 ANIMATION_CACHE_H
-#define ANIMATION_CACHE_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/animation.h"
-
-class AnimationCache : public Object {
- GDCLASS(AnimationCache, Object);
-
- struct Path {
- RES resource;
- Object *object = nullptr;
-#ifndef _3D_DISABLED
- Skeleton3D *skeleton = nullptr;
- Node3D *node_3d = nullptr;
-#endif // _3D_DISABLED
- Node *node = nullptr;
-
- int bone_idx = -1;
- Vector<StringName> subpath;
- bool valid = false;
- };
-
- Set<Node *> connected_nodes;
- Vector<Path> path_cache;
-
- Node *root = nullptr;
- Ref<Animation> animation;
- bool cache_dirty = true;
- bool cache_valid = false;
-
- void _node_exit_tree(Node *p_node);
-
- void _clear_cache();
- void _update_cache();
- void _animation_changed();
-
-protected:
- static void _bind_methods();
-
-public:
- void set_track_transform(int p_idx, const Transform3D &p_transform);
- void set_track_value(int p_idx, const Variant &p_value);
- void call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
-
- void set_all(float p_time, float p_delta = 0);
-
- void set_animation(const Ref<Animation> &p_animation);
- void set_root(Node *p_root);
-
- AnimationCache();
-};
-
-#endif // ANIMATION_CACHE_H
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 2c8c4ee788..8407e0dd99 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -60,7 +60,12 @@ void AnimatedValuesBackup::restore() const {
if (entry->bone_idx == -1) {
entry->object->set_indexed(entry->subpath, entry->value);
} else {
- Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose(entry->bone_idx, entry->value);
+ Array arr = entry->value;
+ if (arr.size() == 3) {
+ Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_position(entry->bone_idx, arr[0]);
+ Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_rotation(entry->bone_idx, arr[1]);
+ Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_scale(entry->bone_idx, arr[0]);
+ }
}
}
}
@@ -242,6 +247,8 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
p_anim->node_cache.resize(a->get_track_count());
+ setup_pass++;
+
for (int i = 0; i < a->get_track_count(); i++) {
p_anim->node_cache.write[i] = nullptr;
RES resource;
@@ -275,46 +282,68 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
node_cache_map[key] = TrackNodeCache();
}
- p_anim->node_cache.write[i] = &node_cache_map[key];
- p_anim->node_cache[i]->path = a->track_get_path(i);
- p_anim->node_cache[i]->node = child;
- p_anim->node_cache[i]->resource = resource;
- p_anim->node_cache[i]->node_2d = Object::cast_to<Node2D>(child);
+ TrackNodeCache *node_cache = &node_cache_map[key];
+ p_anim->node_cache.write[i] = node_cache;
+
+ node_cache->path = a->track_get_path(i);
+ node_cache->node = child;
+ node_cache->resource = resource;
+ node_cache->node_2d = Object::cast_to<Node2D>(child);
#ifndef _3D_DISABLED
- if (a->track_get_type(i) == Animation::TYPE_TRANSFORM3D) {
+ if (a->track_get_type(i) == Animation::TYPE_POSITION_3D || a->track_get_type(i) == Animation::TYPE_ROTATION_3D || a->track_get_type(i) == Animation::TYPE_SCALE_3D) {
// special cases and caches for transform tracks
+ if (node_cache->last_setup_pass != setup_pass) {
+ node_cache->loc_used = false;
+ node_cache->rot_used = false;
+ node_cache->scale_used = false;
+ }
+
// cache node_3d
- p_anim->node_cache[i]->node_3d = Object::cast_to<Node3D>(child);
+ node_cache->node_3d = Object::cast_to<Node3D>(child);
// cache skeleton
- p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton3D>(child);
- if (p_anim->node_cache[i]->skeleton) {
+ node_cache->skeleton = Object::cast_to<Skeleton3D>(child);
+ if (node_cache->skeleton) {
if (a->track_get_path(i).get_subname_count() == 1) {
StringName bone_name = a->track_get_path(i).get_subname(0);
- p_anim->node_cache[i]->bone_idx = p_anim->node_cache[i]->skeleton->find_bone(bone_name);
- if (p_anim->node_cache[i]->bone_idx < 0) {
+ node_cache->bone_idx = node_cache->skeleton->find_bone(bone_name);
+ if (node_cache->bone_idx < 0) {
// broken track (nonexistent bone)
- p_anim->node_cache[i]->skeleton = nullptr;
- p_anim->node_cache[i]->node_3d = nullptr;
- ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0);
+ node_cache->skeleton = nullptr;
+ node_cache->node_3d = nullptr;
+ ERR_CONTINUE(node_cache->bone_idx < 0);
}
} else {
// no property, just use spatialnode
- p_anim->node_cache[i]->skeleton = nullptr;
+ node_cache->skeleton = nullptr;
+ }
+ }
+
+ switch (a->track_get_type(i)) {
+ case Animation::TYPE_POSITION_3D: {
+ node_cache->loc_used = true;
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+ node_cache->rot_used = true;
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+ node_cache->scale_used = true;
+ } break;
+ default: {
}
}
}
#endif // _3D_DISABLED
if (a->track_get_type(i) == Animation::TYPE_VALUE) {
- if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
+ if (!node_cache->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
TrackNodeCache::PropertyAnim pa;
pa.subpath = leftover_path;
pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
pa.special = SP_NONE;
pa.owner = p_anim->node_cache[i];
- if (false && p_anim->node_cache[i]->node_2d) {
+ if (false && node_cache->node_2d) {
if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos) {
pa.special = SP_NODE2D_POS;
} else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_rot) {
@@ -323,20 +352,22 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
pa.special = SP_NODE2D_SCALE;
}
}
- p_anim->node_cache[i]->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa;
+ node_cache->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa;
}
}
if (a->track_get_type(i) == Animation::TYPE_BEZIER && leftover_path.size()) {
- if (!p_anim->node_cache[i]->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
+ if (!node_cache->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
TrackNodeCache::BezierAnim ba;
ba.bezier_property = leftover_path;
ba.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
ba.owner = p_anim->node_cache[i];
- p_anim->node_cache[i]->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba;
+ node_cache->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba;
}
}
+
+ node_cache->last_setup_pass = setup_pass;
}
}
@@ -369,17 +400,15 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
switch (a->track_get_type(i)) {
- case Animation::TYPE_TRANSFORM3D: {
+ case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
if (!nc->node_3d) {
continue;
}
Vector3 loc;
- Quaternion rot;
- Vector3 scale;
- Error err = a->transform_track_interpolate(i, p_time, &loc, &rot, &scale);
+ Error err = a->position_track_interpolate(i, p_time, &loc);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err != OK) {
@@ -391,12 +420,63 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
cache_update[cache_update_size++] = nc;
nc->accum_pass = accum_pass;
nc->loc_accum = loc;
- nc->rot_accum = rot;
- nc->scale_accum = scale;
-
+ nc->rot_accum = Quaternion();
+ nc->scale_accum = Vector3();
} else {
nc->loc_accum = nc->loc_accum.lerp(loc, p_interp);
+ }
+#endif // _3D_DISABLED
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+#ifndef _3D_DISABLED
+ if (!nc->node_3d) {
+ continue;
+ }
+
+ Quaternion rot;
+
+ Error err = a->rotation_track_interpolate(i, p_time, &rot);
+ //ERR_CONTINUE(err!=OK); //used for testing, should be removed
+
+ if (err != OK) {
+ continue;
+ }
+
+ if (nc->accum_pass != accum_pass) {
+ ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
+ cache_update[cache_update_size++] = nc;
+ nc->accum_pass = accum_pass;
+ nc->loc_accum = Vector3();
+ nc->rot_accum = rot;
+ nc->scale_accum = Vector3();
+ } else {
nc->rot_accum = nc->rot_accum.slerp(rot, p_interp);
+ }
+#endif // _3D_DISABLED
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+#ifndef _3D_DISABLED
+ if (!nc->node_3d) {
+ continue;
+ }
+
+ Vector3 scale;
+
+ Error err = a->scale_track_interpolate(i, p_time, &scale);
+ //ERR_CONTINUE(err!=OK); //used for testing, should be removed
+
+ if (err != OK) {
+ continue;
+ }
+
+ if (nc->accum_pass != accum_pass) {
+ ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
+ cache_update[cache_update_size++] = nc;
+ nc->accum_pass = accum_pass;
+ nc->loc_accum = Vector3();
+ nc->rot_accum = Quaternion();
+ nc->scale_accum = scale;
+ } else {
nc->scale_accum = nc->scale_accum.lerp(scale, p_interp);
}
#endif // _3D_DISABLED
@@ -855,15 +935,30 @@ void AnimationPlayer::_animation_update_transforms() {
TrackNodeCache *nc = cache_update[i];
ERR_CONTINUE(nc->accum_pass != accum_pass);
-
- t.origin = nc->loc_accum;
- t.basis.set_quaternion_scale(nc->rot_accum, nc->scale_accum);
#ifndef _3D_DISABLED
if (nc->skeleton && nc->bone_idx >= 0) {
- nc->skeleton->set_bone_pose(nc->bone_idx, t);
+ if (nc->loc_used) {
+ nc->skeleton->set_bone_pose_position(nc->bone_idx, nc->loc_accum);
+ }
+ if (nc->rot_used) {
+ nc->skeleton->set_bone_pose_rotation(nc->bone_idx, nc->rot_accum);
+ }
+ if (nc->scale_used) {
+ nc->skeleton->set_bone_pose_scale(nc->bone_idx, nc->scale_accum);
+ }
+
} else if (nc->node_3d) {
- nc->node_3d->set_transform(t);
+ if (nc->loc_used) {
+ nc->node_3d->set_position(nc->loc_accum);
+ }
+ if (nc->rot_used) {
+ nc->node_3d->set_rotation(nc->rot_accum.get_euler());
+ }
+ if (nc->scale_used) {
+ nc->node_3d->set_scale(nc->scale_accum);
+ }
}
+
#endif // _3D_DISABLED
}
}
@@ -1527,7 +1622,12 @@ Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_o
AnimatedValuesBackup::Entry entry;
entry.object = nc->skeleton;
entry.bone_idx = nc->bone_idx;
- entry.value = nc->skeleton->get_bone_pose(nc->bone_idx);
+ Array arr;
+ arr.resize(3);
+ arr[0] = nc->skeleton->get_bone_pose_position(nc->bone_idx);
+ arr[1] = nc->skeleton->get_bone_pose_rotation(nc->bone_idx);
+ arr[2] = nc->skeleton->get_bone_pose_scale(nc->bone_idx);
+ entry.value = nc;
backup->entries.push_back(entry);
} else {
if (nc->node_3d) {
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index b693e29bdf..f8e72a67b6 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -88,6 +88,8 @@ private:
SP_NODE2D_SCALE,
};
+ uint32_t setup_pass = 1;
+
struct TrackNodeCache {
NodePath path;
uint32_t id = 0;
@@ -101,6 +103,10 @@ private:
int bone_idx = -1;
// accumulated transforms
+ bool loc_used = false;
+ bool rot_used = false;
+ bool scale_used = false;
+
Vector3 loc_accum;
Quaternion rot_accum;
Vector3 scale_accum;
@@ -134,6 +140,7 @@ private:
Map<StringName, BezierAnim> bezier_anim;
+ uint32_t last_setup_pass = 0;
TrackNodeCache() {}
};
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 9ca8d478b1..dd5fe46223 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -544,13 +544,18 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
NodePath path = anim->track_get_path(i);
Animation::TrackType track_type = anim->track_get_type(i);
+ Animation::TrackType track_cache_type = track_type;
+ if (track_cache_type == Animation::TYPE_POSITION_3D || track_cache_type == Animation::TYPE_ROTATION_3D || track_cache_type == Animation::TYPE_SCALE_3D) {
+ track_cache_type = Animation::TYPE_POSITION_3D; //reference them as position3D tracks, even if they modify rotation or scale
+ }
+
TrackCache *track = nullptr;
if (track_cache.has(path)) {
track = track_cache.get(path);
}
//if not valid, delete track
- if (track && (track->type != track_type || ObjectDB::get_instance(track->object_id) == nullptr)) {
+ if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {
playing_caches.erase(track);
memdelete(track);
track_cache.erase(path);
@@ -587,7 +592,9 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track = track_value;
} break;
- case Animation::TYPE_TRANSFORM3D: {
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D: {
#ifndef _3D_DISABLED
Node3D *node_3d = Object::cast_to<Node3D>(child);
@@ -597,6 +604,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
}
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
+ track_xform->type = Animation::TYPE_POSITION_3D;
track_xform->node_3d = node_3d;
track_xform->skeleton = nullptr;
@@ -615,6 +623,21 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track_xform->object_id = track_xform->object->get_instance_id();
track = track_xform;
+
+ switch (track_type) {
+ case Animation::TYPE_POSITION_3D: {
+ track_xform->loc_used = true;
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+ track_xform->rot_used = true;
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+ track_xform->scale_used = true;
+ } break;
+ default: {
+ }
+ }
+
#endif // _3D_DISABLED
} break;
case Animation::TYPE_METHOD: {
@@ -670,6 +693,26 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
}
track_cache[path] = track;
+ } else if (track_cache_type == Animation::TYPE_POSITION_3D) {
+ TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track);
+ if (track->setup_pass != setup_pass) {
+ track_xform->loc_used = false;
+ track_xform->rot_used = false;
+ track_xform->scale_used = false;
+ }
+ switch (track_type) {
+ case Animation::TYPE_POSITION_3D: {
+ track_xform->loc_used = true;
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+ track_xform->rot_used = true;
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+ track_xform->scale_used = true;
+ } break;
+ default: {
+ }
+ }
}
track->setup_pass = setup_pass;
@@ -831,8 +874,11 @@ void AnimationTree::_process_graph(real_t p_delta) {
ERR_CONTINUE(!track_cache.has(path));
TrackCache *track = track_cache[path];
- if (track->type != a->track_get_type(i)) {
- continue; //may happen should not
+
+ Animation::TrackType ttype = a->track_get_type(i);
+ if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) {
+ //broken animation, but avoid error spamming
+ continue;
}
track->root_motion = root_motion_track == path;
@@ -848,20 +894,81 @@ void AnimationTree::_process_graph(real_t p_delta) {
continue; //nothing to blend
}
- switch (track->type) {
- case Animation::TYPE_TRANSFORM3D: {
+ switch (ttype) {
+ case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
+ if (t->process_pass != process_pass) {
+ t->process_pass = process_pass;
+ t->loc = Vector3();
+ t->rot = Quaternion();
+ t->rot_blend_accum = 0;
+ t->scale = Vector3(1, 1, 1);
+ }
+
if (track->root_motion) {
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = Vector3();
- t->rot = Quaternion();
- t->rot_blend_accum = 0;
- t->scale = Vector3(1, 1, 1);
+ real_t prev_time = time - delta;
+ if (prev_time < 0) {
+ if (!a->has_loop()) {
+ prev_time = 0;
+ } else {
+ prev_time = a->get_length() + prev_time;
+ }
}
+ Vector3 loc[2];
+
+ if (prev_time > time) {
+ Error err = a->position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+
+ a->position_track_interpolate(i, a->get_length(), &loc[1]);
+
+ t->loc += (loc[1] - loc[0]) * blend;
+ prev_time = 0;
+ }
+
+ Error err = a->position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+
+ a->position_track_interpolate(i, time, &loc[1]);
+
+ t->loc += (loc[1] - loc[0]) * blend;
+
+ prev_time = 0;
+
+ } else {
+ Vector3 loc;
+
+ Error err = a->position_track_interpolate(i, time, &loc);
+ //ERR_CONTINUE(err!=OK); //used for testing, should be removed
+
+ if (err != OK) {
+ continue;
+ }
+
+ t->loc = t->loc.lerp(loc, blend);
+ }
+#endif // _3D_DISABLED
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+#ifndef _3D_DISABLED
+ TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
+
+ if (t->process_pass != process_pass) {
+ t->process_pass = process_pass;
+ t->loc = Vector3();
+ t->rot = Quaternion();
+ t->rot_blend_accum = 0;
+ t->scale = Vector3(1, 1, 1);
+ }
+
+ if (track->root_motion) {
real_t prev_time = time - delta;
if (prev_time < 0) {
if (!a->has_loop()) {
@@ -871,61 +978,44 @@ void AnimationTree::_process_graph(real_t p_delta) {
}
}
- Vector3 loc[2];
Quaternion rot[2];
- Vector3 scale[2];
if (prev_time > time) {
- Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
+ Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]);
if (err != OK) {
continue;
}
- a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]);
+ a->rotation_track_interpolate(i, a->get_length(), &rot[1]);
- t->loc += (loc[1] - loc[0]) * blend;
- t->scale += (scale[1] - scale[0]) * blend;
Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
t->rot = (t->rot * q).normalized();
prev_time = 0;
}
- Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
+ Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]);
if (err != OK) {
continue;
}
- a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]);
+ a->rotation_track_interpolate(i, time, &rot[1]);
- t->loc += (loc[1] - loc[0]) * blend;
- t->scale += (scale[1] - scale[0]) * blend;
Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
t->rot = (t->rot * q).normalized();
prev_time = 0;
} else {
- Vector3 loc;
Quaternion rot;
- Vector3 scale;
- Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale);
+ Error err = a->rotation_track_interpolate(i, time, &rot);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = loc;
- t->rot = rot;
- t->rot_blend_accum = 0;
- t->scale = scale;
- }
-
if (err != OK) {
continue;
}
- t->loc = t->loc.lerp(loc, blend);
if (t->rot_blend_accum == 0) {
t->rot = rot;
t->rot_blend_accum = blend;
@@ -934,6 +1024,67 @@ void AnimationTree::_process_graph(real_t p_delta) {
t->rot = rot.slerp(t->rot, t->rot_blend_accum / rot_total).normalized();
t->rot_blend_accum = rot_total;
}
+ }
+#endif // _3D_DISABLED
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+#ifndef _3D_DISABLED
+ TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
+
+ if (t->process_pass != process_pass) {
+ t->process_pass = process_pass;
+ t->loc = Vector3();
+ t->rot = Quaternion();
+ t->rot_blend_accum = 0;
+ t->scale = Vector3(1, 1, 1);
+ }
+
+ if (track->root_motion) {
+ real_t prev_time = time - delta;
+ if (prev_time < 0) {
+ if (!a->has_loop()) {
+ prev_time = 0;
+ } else {
+ prev_time = a->get_length() + prev_time;
+ }
+ }
+
+ Vector3 scale[2];
+
+ if (prev_time > time) {
+ Error err = a->scale_track_interpolate(i, prev_time, &scale[0]);
+ if (err != OK) {
+ continue;
+ }
+
+ a->scale_track_interpolate(i, a->get_length(), &scale[1]);
+
+ t->scale += (scale[1] - scale[0]) * blend;
+
+ prev_time = 0;
+ }
+
+ Error err = a->scale_track_interpolate(i, prev_time, &scale[0]);
+ if (err != OK) {
+ continue;
+ }
+
+ a->scale_track_interpolate(i, time, &scale[1]);
+
+ t->scale += (scale[1] - scale[0]) * blend;
+
+ prev_time = 0;
+
+ } else {
+ Vector3 scale;
+
+ Error err = a->scale_track_interpolate(i, time, &scale);
+ //ERR_CONTINUE(err!=OK); //used for testing, should be removed
+
+ if (err != OK) {
+ continue;
+ }
+
t->scale = t->scale.lerp(scale, blend);
}
#endif // _3D_DISABLED
@@ -1198,26 +1349,38 @@ void AnimationTree::_process_graph(real_t p_delta) {
}
switch (track->type) {
- case Animation::TYPE_TRANSFORM3D: {
+ case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
- Transform3D xform;
- xform.origin = t->loc;
-
- xform.basis.set_quaternion_scale(t->rot, t->scale);
-
if (t->root_motion) {
+ Transform3D xform;
+ xform.origin = t->loc;
+ xform.basis.set_quaternion_scale(t->rot, t->scale);
+
root_motion_transform = xform;
- if (t->skeleton && t->bone_idx >= 0) {
- root_motion_transform = (t->skeleton->get_bone_rest(t->bone_idx) * root_motion_transform) * t->skeleton->get_bone_rest(t->bone_idx).affine_inverse();
- }
} else if (t->skeleton && t->bone_idx >= 0) {
- t->skeleton->set_bone_pose(t->bone_idx, xform);
+ if (t->loc_used) {
+ t->skeleton->set_bone_pose_position(t->bone_idx, t->loc);
+ }
+ if (t->rot_used) {
+ t->skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);
+ }
+ if (t->scale_used) {
+ t->skeleton->set_bone_pose_scale(t->bone_idx, t->scale);
+ }
} else if (!t->skeleton) {
- t->node_3d->set_transform(xform);
+ if (t->loc_used) {
+ t->node_3d->set_position(t->loc);
+ }
+ if (t->rot_used) {
+ t->node_3d->set_rotation(t->rot.get_euler());
+ }
+ if (t->scale_used) {
+ t->node_3d->set_scale(t->scale);
+ }
}
#endif // _3D_DISABLED
} break;
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 1e0267682e..ed207dfe0c 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -197,13 +197,16 @@ private:
Skeleton3D *skeleton = nullptr;
#endif // _3D_DISABLED
int bone_idx = -1;
+ bool loc_used = false;
+ bool rot_used = false;
+ bool scale_used = false;
Vector3 loc;
Quaternion rot;
real_t rot_blend_accum = 0.0;
Vector3 scale;
TrackCacheTransform() {
- type = Animation::TYPE_TRANSFORM3D;
+ type = Animation::TYPE_POSITION_3D;
}
};