summaryrefslogtreecommitdiffstats
path: root/scene/animation
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation')
-rw-r--r--scene/animation/animation_blend_tree.cpp16
-rw-r--r--scene/animation/animation_blend_tree.h7
-rw-r--r--scene/animation/animation_mixer.cpp140
-rw-r--r--scene/animation/animation_mixer.h4
-rw-r--r--scene/animation/root_motion_view.cpp5
5 files changed, 138 insertions, 34 deletions
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index e172286d05..d0773fc83f 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1003,6 +1003,14 @@ String AnimationNodeTimeSeek::get_caption() const {
return "TimeSeek";
}
+void AnimationNodeTimeSeek::set_explicit_elapse(bool p_enable) {
+ explicit_elapse = p_enable;
+}
+
+bool AnimationNodeTimeSeek::is_explicit_elapse() const {
+ return explicit_elapse;
+}
+
AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
double cur_seek_pos = get_parameter(seek_pos_request);
@@ -1011,7 +1019,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer
if (Animation::is_greater_or_equal_approx(cur_seek_pos, 0)) {
pi.time = cur_seek_pos;
pi.seeked = true;
- pi.is_external_seeking = true;
+ pi.is_external_seeking = explicit_elapse;
set_parameter(seek_pos_request, -1.0); // Reset.
}
@@ -1022,6 +1030,12 @@ AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
add_input("in");
}
+void AnimationNodeTimeSeek::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_explicit_elapse", "enable"), &AnimationNodeTimeSeek::set_explicit_elapse);
+ ClassDB::bind_method(D_METHOD("is_explicit_elapse"), &AnimationNodeTimeSeek::is_explicit_elapse);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "explicit_elapse"), "set_explicit_elapse", "is_explicit_elapse");
+}
+
/////////////////////////////////////////////////
bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_value) {
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 5c912f0095..c48d799eea 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -302,6 +302,10 @@ class AnimationNodeTimeSeek : public AnimationNode {
GDCLASS(AnimationNodeTimeSeek, AnimationNode);
StringName seek_pos_request = PNAME("seek_request");
+ bool explicit_elapse = true;
+
+protected:
+ static void _bind_methods();
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
@@ -311,6 +315,9 @@ public:
virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override;
+ void set_explicit_elapse(bool p_enable);
+ bool is_explicit_elapse() const;
+
AnimationNodeTimeSeek();
};
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index 3a2adead98..3e09e425b0 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -129,6 +129,9 @@ void AnimationMixer::_validate_property(PropertyInfo &p_property) const {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
#endif // TOOLS_ENABLED
+ if (root_motion_track.is_empty() && p_property.name == "root_motion_local") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
}
/* -------------------------------------------- */
@@ -745,6 +748,15 @@ bool AnimationMixer::_update_caches() {
}
}
+ if (is_value && callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {
+ if (child) {
+ PropertyInfo prop_info;
+ ClassDB::get_property_info(child->get_class_name(), path.get_concatenated_subnames(), &prop_info);
+ if (prop_info.hint == PROPERTY_HINT_ONESHOT) {
+ WARN_PRINT_ED(vformat("%s: '%s', Value Track: '%s' is oneshot property, but will be continuously updated. Consider setting a value other than ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS to AnimationMixer.callback_mode_dominant.", mixer_name, String(E), String(path)));
+ }
+ }
+ }
} break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
@@ -1212,6 +1224,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
+ int rot_track = -1;
+ if (root_motion_local) {
+ rot_track = a->find_track(a->track_get_path(i), Animation::TYPE_ROTATION_3D);
+ }
double prev_time = time - delta;
if (!backward) {
if (Animation::is_less_approx(prev_time, start)) {
@@ -1246,41 +1262,92 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
}
}
- Vector3 loc[2];
- if (!backward) {
- if (Animation::is_greater_approx(prev_time, time)) {
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
+ if (rot_track >= 0) {
+ Vector3 loc[2];
+ Quaternion rot;
+ if (!backward) {
+ if (Animation::is_greater_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, end, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, end, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = start;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, end, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = start;
+ } else {
+ if (Animation::is_less_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, start, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, start, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = end;
+ }
+ }
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
}
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, time, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, time, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = !backward ? start : end;
} else {
- if (Animation::is_less_approx(prev_time, time)) {
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
+ Vector3 loc[2];
+ if (!backward) {
+ if (Animation::is_greater_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, end, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = start;
+ }
+ } else {
+ if (Animation::is_less_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, start, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = end;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, start, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = end;
}
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, time, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = !backward ? start : end;
}
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
- }
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, time, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = !backward ? start : end;
}
{
Vector3 loc;
@@ -1355,6 +1422,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
a->try_rotation_track_interpolate(i, start, &rot[1]);
+ rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
prev_time = end;
}
@@ -1430,8 +1498,8 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
a->try_scale_track_interpolate(i, end, &scale[1]);
- root_motion_cache.scale += (scale[1] - scale[0]) * blend;
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
+ root_motion_cache.scale += (scale[1] - scale[0]) * blend;
prev_time = start;
}
} else {
@@ -2002,12 +2070,21 @@ void AnimationMixer::clear_caches() {
void AnimationMixer::set_root_motion_track(const NodePath &p_track) {
root_motion_track = p_track;
+ notify_property_list_changed();
}
NodePath AnimationMixer::get_root_motion_track() const {
return root_motion_track;
}
+void AnimationMixer::set_root_motion_local(bool p_enabled) {
+ root_motion_local = p_enabled;
+}
+
+bool AnimationMixer::is_root_motion_local() const {
+ return root_motion_local;
+}
+
Vector3 AnimationMixer::get_root_motion_position() const {
return root_motion_position;
}
@@ -2353,6 +2430,8 @@ void AnimationMixer::_bind_methods() {
/* ---- Root motion accumulator for Skeleton3D ---- */
ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationMixer::set_root_motion_track);
ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationMixer::get_root_motion_track);
+ ClassDB::bind_method(D_METHOD("set_root_motion_local", "enabled"), &AnimationMixer::set_root_motion_local);
+ ClassDB::bind_method(D_METHOD("is_root_motion_local"), &AnimationMixer::is_root_motion_local);
ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationMixer::get_root_motion_position);
ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationMixer::get_root_motion_rotation);
@@ -2380,6 +2459,7 @@ void AnimationMixer::_bind_methods() {
ADD_GROUP("Root Motion", "root_motion_");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "root_motion_local"), "set_root_motion_local", "is_root_motion_local");
ADD_GROUP("Audio", "audio_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");
diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h
index 822a7aef25..82deccaa95 100644
--- a/scene/animation/animation_mixer.h
+++ b/scene/animation/animation_mixer.h
@@ -334,6 +334,7 @@ protected:
/* ---- Root motion accumulator for Skeleton3D ---- */
NodePath root_motion_track;
+ bool root_motion_local = false;
Vector3 root_motion_position = Vector3(0, 0, 0);
Quaternion root_motion_rotation = Quaternion(0, 0, 0, 1);
Vector3 root_motion_scale = Vector3(0, 0, 0);
@@ -447,6 +448,9 @@ public:
void set_root_motion_track(const NodePath &p_track);
NodePath get_root_motion_track() const;
+ void set_root_motion_local(bool p_enabled);
+ bool is_root_motion_local() const;
+
Vector3 get_root_motion_position() const;
Quaternion get_root_motion_rotation() const;
Vector3 get_root_motion_scale() const;
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index fd520dadd6..2c0222b3b8 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -94,7 +94,6 @@ void RootMotionView::_notification(int p_what) {
if (has_node(path)) {
Node *node = get_node(path);
-
AnimationMixer *mixer = Object::cast_to<AnimationMixer>(node);
if (mixer && mixer->is_active() && mixer->get_root_motion_track() != NodePath()) {
if (is_processing_internal() && mixer->get_callback_mode_process() == AnimationMixer::ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS) {
@@ -106,12 +105,12 @@ void RootMotionView::_notification(int p_what) {
set_process_internal(true);
set_physics_process_internal(false);
}
+
transform.origin = mixer->get_root_motion_position();
transform.basis = mixer->get_root_motion_rotation(); // Scale is meaningless.
- diff = mixer->get_root_motion_rotation_accumulator();
+ diff = mixer->is_root_motion_local() ? Quaternion() : mixer->get_root_motion_rotation_accumulator();
}
}
-
if (!first && transform == Transform3D()) {
return;
}