diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 79a1dc1ac0e4..ccaf58941d6b 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -87,10 +87,10 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { float step; if (p_seek) { + step = p_time - time; time = p_time; - step = 0; } else { - time = MAX(0, time + p_time); + time = time + p_time; step = p_time; } @@ -103,6 +103,10 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { } else if (time > anim_size) { time = anim_size; + step = 0; + } else if (time < 0) { + time = 0; + step = 0; } blend_animation(animation, time, step, p_seek, 1.0); @@ -534,7 +538,7 @@ AnimationNodeBlend3::AnimationNodeBlend3() { ///////////////////////////////// void AnimationNodeTimeScale::get_parameter_list(List *r_list) const { - r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "0,32,0.01,or_greater")); + r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_greater")); } Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const { diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 44f2d38a8426..a7e003d40a11 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -819,6 +819,7 @@ void AnimationTree::_process_graph(float p_delta) { float delta = as.delta; float weight = as.blend; bool seeked = as.seeked; + bool reverse = delta < 0; for (int i = 0; i < a->get_track_count(); i++) { NodePath path = a->track_get_path(i); @@ -857,11 +858,21 @@ void AnimationTree::_process_graph(float p_delta) { } float prev_time = time - delta; - if (prev_time < 0) { - if (!a->has_loop()) { - prev_time = 0; - } else { - prev_time = a->get_length() + prev_time; + if (!reverse) { + if (prev_time < 0) { + if (!a->has_loop()) { + prev_time = 0; + } else { + prev_time = Math::fposmod(prev_time, a->get_length()); + } + } + } else { + if (prev_time > a->get_length()) { + if (!a->has_loop()) { + prev_time = a->get_length(); + } else { + prev_time = Math::fposmod(prev_time, a->get_length()); + } } } @@ -869,42 +880,59 @@ void AnimationTree::_process_graph(float p_delta) { Quat rot[2]; Vector3 scale[2]; - if (prev_time > time) { - Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); - if (err != OK) { - continue; + if (!reverse) { + if (prev_time > time) { + Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0], reverse); + if (err != OK) { + continue; + } + + a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1], reverse); + + t->loc += (loc[1] - loc[0]) * blend; + t->scale += (scale[1] - scale[0]) * blend; + Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); + t->rot = (t->rot * q).normalized(); + + prev_time = 0; } + } else { + if (prev_time < time) { + Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0], reverse); + if (err != OK) { + continue; + } - a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]); + a->transform_track_interpolate(i, 0, &loc[1], &rot[1], &scale[1], reverse); - t->loc += (loc[1] - loc[0]) * blend; - t->scale += (scale[1] - scale[0]) * blend; - Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); - t->rot = (t->rot * q).normalized(); + t->loc += (loc[1] - loc[0]) * blend; + t->scale += (scale[1] - scale[0]) * blend; + Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); + t->rot = (t->rot * q).normalized(); - prev_time = 0; + prev_time = a->get_length(); + } } - Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); + Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0], reverse); if (err != OK) { continue; } - a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]); + a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1], reverse); t->loc += (loc[1] - loc[0]) * blend; t->scale += (scale[1] - scale[0]) * blend; Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); - prev_time = 0; - + prev_time = !reverse ? 0 : a->get_length(); } else { Vector3 loc; Quat rot; Vector3 scale; - Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); + Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale, reverse); //ERR_CONTINUE(err!=OK); //used for testing, should be removed if (t->process_pass != process_pass) { @@ -1082,8 +1110,18 @@ void AnimationTree::_process_graph(float p_delta) { bool stop = false; - if (!loop && time < t->start) { - stop = true; + if (!loop) { + // An audio will be not stopped when animation end. + // You will be able to stop the audio by making 'stop = true' when 'delta == 0'. + if (delta > 0) { + if (time < t->start) { + stop = true; + } + } else if (delta < 0) { + if (time > t->start) { + stop = true; + } + } } else if (t->len > 0) { float len = t->start > time ? (a->get_length() - t->start) + time : time - t->start; @@ -1117,7 +1155,7 @@ void AnimationTree::_process_graph(float p_delta) { continue; } - if (delta == 0 || seeked) { + if (seeked) { //seek int idx = a->track_find_key(i, time); if (idx < 0) { diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 6f64ac6d04ed..284b5eb2921c 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -1412,7 +1412,7 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra } template -int Animation::_find(const Vector &p_keys, float p_time) const { +int Animation::_find(const Vector &p_keys, float p_time, bool reverse) const { int len = p_keys.size(); if (len == 0) { return -2; @@ -1442,8 +1442,14 @@ int Animation::_find(const Vector &p_keys, float p_time) const { } } - if (keys[middle].time > p_time) { - middle--; + if (!reverse) { + if (keys[middle].time > p_time) { + middle--; + } + } else { + if (keys[middle].time < p_time) { + middle++; + } } return middle; @@ -1584,7 +1590,7 @@ float Animation::_cubic_interpolate(const float &p_pre_a, const float &p_a, cons } template -T Animation::_interpolate(const Vector> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const { +T Animation::_interpolate(const Vector> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool reverse) const { int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end) if (len <= 0) { @@ -1602,7 +1608,7 @@ T Animation::_interpolate(const Vector> &p_keys, float p_time, Interpola return p_keys[0].value; } - int idx = _find(p_keys, p_time); + int idx = _find(p_keys, p_time, reverse); ERR_FAIL_COND_V(idx == -2, T()); @@ -1613,22 +1619,40 @@ T Animation::_interpolate(const Vector> &p_keys, float p_time, Interpola if (loop && p_loop_wrap) { // loop - if (idx >= 0) { - if ((idx + 1) < len) { - next = idx + 1; - float delta = p_keys[next].time - p_keys[idx].time; - float from = p_time - p_keys[idx].time; - - if (Math::is_zero_approx(delta)) { - c = 0; + if (!reverse) { + // no reverse + if (idx >= 0) { + if (idx < len - 1) { + next = idx + 1; + float delta = p_keys[next].time - p_keys[idx].time; + float from = p_time - p_keys[idx].time; + + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } } else { - c = from / delta; + next = 0; + float delta = (length - p_keys[idx].time) + p_keys[next].time; + float from = p_time - p_keys[idx].time; + + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } } - } else { + // on loop, behind first key + idx = len - 1; next = 0; - float delta = (length - p_keys[idx].time) + p_keys[next].time; - float from = p_time - p_keys[idx].time; + float endtime = (length - p_keys[idx].time); + if (endtime < 0) { // may be keys past the end + endtime = 0; + } + float delta = endtime + p_keys[next].time; + float from = endtime + p_time; if (Math::is_zero_approx(delta)) { c = 0; @@ -1636,49 +1660,96 @@ T Animation::_interpolate(const Vector> &p_keys, float p_time, Interpola c = from / delta; } } - } else { - // on loop, behind first key - idx = len - 1; - next = 0; - float endtime = (length - p_keys[idx].time); - if (endtime < 0) { // may be keys past the end - endtime = 0; - } - float delta = endtime + p_keys[next].time; - float from = endtime + p_time; - - if (Math::is_zero_approx(delta)) { - c = 0; + // reverse + if (idx <= len - 1) { + if (idx > 0) { + next = idx - 1; + float delta = (length - p_keys[next].time) - (length - p_keys[idx].time); + float from = (length - p_time) - (length - p_keys[idx].time); + + if (Math::is_zero_approx(delta)) + c = 0; + else + c = from / delta; + } else { + next = len - 1; + float delta = p_keys[idx].time + (length - p_keys[next].time); + float from = (length - p_time) - (length - p_keys[idx].time); + + if (Math::is_zero_approx(delta)) + c = 0; + else + c = from / delta; + } } else { - c = from / delta; + // on loop, in front of last key + idx = 0; + next = len - 1; + float endtime = p_keys[idx].time; + if (endtime > length) // may be keys past the end + endtime = length; + float delta = p_keys[next].time - endtime; + float from = p_time - endtime; + + if (Math::is_zero_approx(delta)) + c = 0; + else + c = from / delta; } } } else { // no loop - if (idx >= 0) { - if ((idx + 1) < len) { - next = idx + 1; - float delta = p_keys[next].time - p_keys[idx].time; - float from = p_time - p_keys[idx].time; + if (!reverse) { + if (idx >= 0) { + if (idx < len - 1) { + next = idx + 1; + float delta = p_keys[next].time - p_keys[idx].time; + float from = p_time - p_keys[idx].time; + + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } - if (Math::is_zero_approx(delta)) { - c = 0; } else { - c = from / delta; + next = idx; } } else { - next = idx; + // only allow extending first key to anim start if looping + if (loop) { + idx = next = 0; + } else { + result = false; + } } - } else { - // only allow extending first key to anim start if looping - if (loop) { - idx = next = 0; + if (idx <= len - 1) { + if (idx > 0) { + next = idx - 1; + float delta = (length - p_keys[next].time) - (length - p_keys[idx].time); + float from = (length - p_time) - (length - p_keys[idx].time); + + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } + + } else { + next = idx; + } + } else { - result = false; + // only allow extending last key to anim start if looping + if (loop) { + idx = next = len - 1; + } else { + result = false; + } } } } @@ -1728,7 +1799,7 @@ T Animation::_interpolate(const Vector> &p_keys, float p_time, Interpola // do a barrel roll } -Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const { +Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale, bool reverse) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, ERR_INVALID_PARAMETER); @@ -1737,7 +1808,7 @@ Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 bool ok = false; - TransformKey tk = _interpolate(tt->transforms, p_time, tt->interpolation, tt->loop_wrap, &ok); + TransformKey tk = _interpolate(tt->transforms, p_time, tt->interpolation, tt->loop_wrap, &ok, reverse); if (!ok) { return ERR_UNAVAILABLE; diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 66bc71c83453..db67d349882b 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -181,7 +181,7 @@ class Animation : public Resource { int _insert(float p_time, T &p_keys, const V &p_value); template - inline int _find(const Vector &p_keys, float p_time) const; + inline int _find(const Vector &p_keys, float p_time, bool reverse = false) const; _FORCE_INLINE_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, float p_c) const; @@ -197,7 +197,7 @@ class Animation : public Resource { _FORCE_INLINE_ float _cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const; template - _FORCE_INLINE_ T _interpolate(const Vector> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const; + _FORCE_INLINE_ T _interpolate(const Vector> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool reverse = false) const; template _FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector &p_array, float from_time, float to_time, List *p_indices) const; @@ -211,11 +211,11 @@ class Animation : public Resource { // bind helpers private: - Array _transform_track_interpolate(int p_track, float p_time) const { + Array _transform_track_interpolate(int p_track, float p_time, bool reverse = false) const { Vector3 loc; Quat rot; Vector3 scale; - transform_track_interpolate(p_track, p_time, &loc, &rot, &scale); + transform_track_interpolate(p_track, p_time, &loc, &rot, &scale, reverse); Array ret; ret.push_back(loc); ret.push_back(rot); @@ -321,7 +321,7 @@ class Animation : public Resource { void track_set_interpolation_loop_wrap(int p_track, bool p_enable); bool track_get_interpolation_loop_wrap(int p_track) const; - Error transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const; + Error transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale, bool reverse = false) const; Variant value_track_interpolate(int p_track, float p_time) const; void value_track_get_key_indices(int p_track, float p_time, float p_delta, List *p_indices) const;