Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement reverse playback for animtree #41723

6 changes: 3 additions & 3 deletions scene/animation/animation_blend_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,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;
}

Expand Down Expand Up @@ -559,7 +559,7 @@ AnimationNodeBlend3::AnimationNodeBlend3() {
/////////////////////////////////

void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *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 {
Expand Down
80 changes: 61 additions & 19 deletions scene/animation/animation_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ void AnimationTree::_process_graph(float p_delta) {
float time = as.time;
float delta = as.delta;
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);
Expand Down Expand Up @@ -860,54 +861,95 @@ 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());
}
}
}

Vector3 loc[2];
Quat rot[2];
Vector3 scale[2];

if (prev_time > time) {
if (!reverse) {
if (prev_time > time) {
Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
if (err != OK) {
continue;
}

a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]);

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;
}

Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
if (err != OK) {
continue;
}

a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]);
a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]);

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;
}

Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
if (err != OK) {
continue;
}
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();

prev_time = a->get_length();
}

a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]);
Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0], reverse);
if (err != OK) {
continue;
}

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();
a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1], reverse);

prev_time = 0;
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 = 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) {
Expand Down
110 changes: 77 additions & 33 deletions scene/resources/animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,7 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra
}

template <class K>
int Animation::_find(const Vector<K> &p_keys, float p_time) const {
int Animation::_find(const Vector<K> &p_keys, float p_time, bool reverse) const {
int len = p_keys.size();
if (len == 0) {
return -2;
Expand Down Expand Up @@ -1443,8 +1443,14 @@ int Animation::_find(const Vector<K> &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;
Expand Down Expand Up @@ -1585,7 +1591,7 @@ float Animation::_cubic_interpolate(const float &p_pre_a, const float &p_a, cons
}

template <class T>
T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const {
T Animation::_interpolate(const Vector<TKey<T>> &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) {
Expand All @@ -1603,7 +1609,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &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());

Expand All @@ -1614,45 +1620,83 @@ T Animation::_interpolate(const Vector<TKey<T>> &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;
} else {
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;
}
}

Expand Down Expand Up @@ -1729,7 +1773,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &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);
Expand All @@ -1738,7 +1782,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;
Expand Down
10 changes: 5 additions & 5 deletions scene/resources/animation.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class Animation : public Resource {
int _insert(float p_time, T &p_keys, const V &p_value);

template <class K>
inline int _find(const Vector<K> &p_keys, float p_time) const;
inline int _find(const Vector<K> &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;

Expand All @@ -207,7 +207,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 <class T>
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const;
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool reverse = false) const;

template <class T>
_FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, float from_time, float to_time, List<int> *p_indices) const;
Expand All @@ -221,11 +221,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);
Expand Down Expand Up @@ -329,7 +329,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<int> *p_indices) const;
Expand Down