diff options
Diffstat (limited to 'scene/animation')
-rw-r--r-- | scene/animation/animation_blend_tree.cpp | 16 | ||||
-rw-r--r-- | scene/animation/animation_blend_tree.h | 7 | ||||
-rw-r--r-- | scene/animation/animation_mixer.cpp | 140 | ||||
-rw-r--r-- | scene/animation/animation_mixer.h | 4 | ||||
-rw-r--r-- | scene/animation/root_motion_view.cpp | 5 |
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; } |