Add linear/cubic angle interpolation to Animation interpolation type
This commit is contained in:
parent
4808d01b2b
commit
931fb4dc11
|
@ -253,6 +253,35 @@ public:
|
|||
(-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
|
||||
}
|
||||
|
||||
static _ALWAYS_INLINE_ double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
|
||||
double from_rot = fmod(p_from, Math_TAU);
|
||||
|
||||
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
|
||||
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
|
||||
|
||||
double to_diff = fmod(p_to - from_rot, Math_TAU);
|
||||
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
|
||||
double post_diff = fmod(p_post - to_rot, Math_TAU);
|
||||
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
|
||||
}
|
||||
static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
|
||||
float from_rot = fmod(p_from, (float)Math_TAU);
|
||||
|
||||
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
|
||||
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
|
||||
|
||||
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
|
||||
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
|
||||
|
||||
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
|
||||
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
|
||||
}
|
||||
|
||||
static _ALWAYS_INLINE_ double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
|
||||
double p_to_t, double p_pre_t, double p_post_t) {
|
||||
/* Barry-Goldman method */
|
||||
|
@ -276,6 +305,37 @@ public:
|
|||
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t);
|
||||
}
|
||||
|
||||
static _ALWAYS_INLINE_ double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
|
||||
double p_to_t, double p_pre_t, double p_post_t) {
|
||||
double from_rot = fmod(p_from, Math_TAU);
|
||||
|
||||
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
|
||||
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
|
||||
|
||||
double to_diff = fmod(p_to - from_rot, Math_TAU);
|
||||
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
|
||||
double post_diff = fmod(p_post - to_rot, Math_TAU);
|
||||
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
|
||||
}
|
||||
static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
|
||||
float p_to_t, float p_pre_t, float p_post_t) {
|
||||
float from_rot = fmod(p_from, (float)Math_TAU);
|
||||
|
||||
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
|
||||
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
|
||||
|
||||
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
|
||||
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
|
||||
|
||||
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
|
||||
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
|
||||
|
||||
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
|
||||
}
|
||||
|
||||
static _ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
|
||||
/* Formula from Wikipedia article on Bezier curves. */
|
||||
double omt = (1.0 - p_t);
|
||||
|
|
|
@ -367,11 +367,20 @@ struct VariantUtilityFunctions {
|
|||
return Math::cubic_interpolate(from, to, pre, post, weight);
|
||||
}
|
||||
|
||||
static inline double cubic_interpolate_angle(double from, double to, double pre, double post, double weight) {
|
||||
return Math::cubic_interpolate_angle(from, to, pre, post, weight);
|
||||
}
|
||||
|
||||
static inline double cubic_interpolate_in_time(double from, double to, double pre, double post, double weight,
|
||||
double to_t, double pre_t, double post_t) {
|
||||
return Math::cubic_interpolate_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
|
||||
}
|
||||
|
||||
static inline double cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
|
||||
double to_t, double pre_t, double post_t) {
|
||||
return Math::cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
|
||||
}
|
||||
|
||||
static inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
|
||||
return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t);
|
||||
}
|
||||
|
@ -1419,7 +1428,9 @@ void Variant::_register_variant_utility_functions() {
|
|||
FUNCBINDVR3(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(lerpf, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(cubic_interpolate_angle, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(cubic_interpolate_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
|
||||
|
|
|
@ -260,6 +260,32 @@
|
|||
Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
|
||||
</description>
|
||||
</method>
|
||||
<method name="cubic_interpolate_angle">
|
||||
<return type="float" />
|
||||
<param index="0" name="from" type="float" />
|
||||
<param index="1" name="to" type="float" />
|
||||
<param index="2" name="pre" type="float" />
|
||||
<param index="3" name="post" type="float" />
|
||||
<param index="4" name="weight" type="float" />
|
||||
<description>
|
||||
Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
|
||||
</description>
|
||||
</method>
|
||||
<method name="cubic_interpolate_angle_in_time">
|
||||
<return type="float" />
|
||||
<param index="0" name="from" type="float" />
|
||||
<param index="1" name="to" type="float" />
|
||||
<param index="2" name="pre" type="float" />
|
||||
<param index="3" name="post" type="float" />
|
||||
<param index="4" name="weight" type="float" />
|
||||
<param index="5" name="to_t" type="float" />
|
||||
<param index="6" name="pre_t" type="float" />
|
||||
<param index="7" name="post_t" type="float" />
|
||||
<description>
|
||||
Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
|
||||
It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
|
||||
</description>
|
||||
</method>
|
||||
<method name="cubic_interpolate_in_time">
|
||||
<return type="float" />
|
||||
<param index="0" name="from" type="float" />
|
||||
|
|
|
@ -600,6 +600,14 @@
|
|||
<constant name="INTERPOLATION_CUBIC" value="2" enum="InterpolationType">
|
||||
Cubic interpolation.
|
||||
</constant>
|
||||
<constant name="INTERPOLATION_LINEAR_ANGLE" value="3" enum="InterpolationType">
|
||||
Linear interpolation with shortest path rotation.
|
||||
[b]Note:[/b] The result value is always normalized and may not match the key value.
|
||||
</constant>
|
||||
<constant name="INTERPOLATION_CUBIC_ANGLE" value="4" enum="InterpolationType">
|
||||
Cubic interpolation with shortest path rotation.
|
||||
[b]Note:[/b] The result value is always normalized and may not match the key value.
|
||||
</constant>
|
||||
<constant name="UPDATE_CONTINUOUS" value="0" enum="UpdateMode">
|
||||
Update between keyframes.
|
||||
</constant>
|
||||
|
|
|
@ -2122,10 +2122,12 @@ void AnimationTrackEdit::_notification(int p_what) {
|
|||
get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")),
|
||||
get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")),
|
||||
};
|
||||
Ref<Texture2D> interp_icon[3] = {
|
||||
Ref<Texture2D> interp_icon[5] = {
|
||||
get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")),
|
||||
get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")),
|
||||
get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")),
|
||||
get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")),
|
||||
get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")),
|
||||
};
|
||||
Ref<Texture2D> cont_icon[4] = {
|
||||
get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")),
|
||||
|
@ -2848,6 +2850,23 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
|
||||
// Check is angle property.
|
||||
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||
if (ape) {
|
||||
AnimationPlayer *ap = ape->get_player();
|
||||
if (ap) {
|
||||
NodePath path = animation->track_get_path(track);
|
||||
Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(path.get_concatenated_names()));
|
||||
StringName prop = path.get_concatenated_subnames();
|
||||
PropertyInfo prop_info;
|
||||
ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
|
||||
bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
|
||||
if (is_angle) {
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
|
||||
menu->add_icon_item(get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
menu->reset_size();
|
||||
|
||||
Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
|
||||
|
@ -3188,7 +3207,9 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
|
|||
} break;
|
||||
case MENU_INTERPOLATION_NEAREST:
|
||||
case MENU_INTERPOLATION_LINEAR:
|
||||
case MENU_INTERPOLATION_CUBIC: {
|
||||
case MENU_INTERPOLATION_CUBIC:
|
||||
case MENU_INTERPOLATION_LINEAR_ANGLE:
|
||||
case MENU_INTERPOLATION_CUBIC_ANGLE: {
|
||||
Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST);
|
||||
undo_redo->create_action(TTR("Change Animation Interpolation Mode"));
|
||||
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode);
|
||||
|
@ -6042,6 +6063,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
Vector<int> keys = E->value;
|
||||
int len = keys.size() - 1;
|
||||
|
||||
// Special case for angle interpolation.
|
||||
bool is_using_angle = animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_LINEAR_ANGLE || animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_CUBIC_ANGLE;
|
||||
|
||||
// Make insert queue.
|
||||
Vector<Pair<double, Variant>> insert_queue;
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
@ -6051,6 +6075,12 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
double to_t = animation->track_get_key_time(track, keys[i + 1]);
|
||||
Variant from_v = animation->track_get_key_value(track, keys[i]);
|
||||
Variant to_v = animation->track_get_key_value(track, keys[i + 1]);
|
||||
if (is_using_angle) {
|
||||
real_t a = from_v;
|
||||
real_t b = to_v;
|
||||
real_t to_diff = fmod(b - a, Math_TAU);
|
||||
to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
|
||||
}
|
||||
Variant delta_v;
|
||||
Variant::sub(to_v, from_v, delta_v);
|
||||
double duration = to_t - from_t;
|
||||
|
@ -6192,10 +6222,14 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
do_bake |= b_bs && type == Animation::TYPE_BLEND_SHAPE;
|
||||
do_bake |= b_v && type == Animation::TYPE_VALUE;
|
||||
if (do_bake && !animation->track_is_compressed(i)) {
|
||||
if (animation->track_get_interpolation_type(i) == Animation::INTERPOLATION_NEAREST) {
|
||||
continue; // Nearest interpolation cannot be baked.
|
||||
Animation::InterpolationType it = animation->track_get_interpolation_type(i);
|
||||
if (it == Animation::INTERPOLATION_NEAREST) {
|
||||
continue; // Nearest and Angle interpolation cannot be baked.
|
||||
}
|
||||
|
||||
// Special case for angle interpolation.
|
||||
bool is_using_angle = it == Animation::INTERPOLATION_LINEAR_ANGLE || it == Animation::INTERPOLATION_CUBIC_ANGLE;
|
||||
|
||||
// Make insert queue.
|
||||
Vector<Pair<double, Variant>> insert_queue;
|
||||
|
||||
|
@ -6259,7 +6293,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
}
|
||||
|
||||
// Insert keys.
|
||||
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, Animation::INTERPOLATION_LINEAR);
|
||||
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, is_using_angle ? Animation::INTERPOLATION_LINEAR_ANGLE : Animation::INTERPOLATION_LINEAR);
|
||||
for (int j = insert_queue.size() - 1; j >= 0; j--) {
|
||||
undo_redo->add_do_method(animation.ptr(), "track_insert_key", i, insert_queue[j].first, insert_queue[j].second);
|
||||
undo_redo->add_undo_method(animation.ptr(), "track_remove_key", i, j);
|
||||
|
|
|
@ -144,6 +144,8 @@ class AnimationTrackEdit : public Control {
|
|||
MENU_INTERPOLATION_NEAREST,
|
||||
MENU_INTERPOLATION_LINEAR,
|
||||
MENU_INTERPOLATION_CUBIC,
|
||||
MENU_INTERPOLATION_LINEAR_ANGLE,
|
||||
MENU_INTERPOLATION_CUBIC_ANGLE,
|
||||
MENU_LOOP_WRAP,
|
||||
MENU_LOOP_CLAMP,
|
||||
MENU_KEY_INSERT,
|
||||
|
@ -500,7 +502,7 @@ class AnimationTrackEditor : public VBoxContainer {
|
|||
NodePath full_path;
|
||||
NodePath base_path;
|
||||
Animation::TrackType track_type = Animation::TYPE_ANIMATION;
|
||||
Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC;
|
||||
Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_ANGLE;
|
||||
Animation::UpdateMode update_mode = Animation::UPDATE_CAPTURE;
|
||||
Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG;
|
||||
bool loop_wrap = false;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#5fff95" stroke-linecap="round"><path d="m2 6c5 0 3-4 6-4s1 4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5" stroke-linejoin="round"/></g></svg>
|
After Width: | Height: | Size: 289 B |
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fd995f" stroke-linecap="round" stroke-linejoin="round"><path d="m2 6 6-4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5"/></g></svg>
|
After Width: | Height: | Size: 277 B |
|
@ -602,6 +602,8 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
|
|||
track_value->object = child;
|
||||
}
|
||||
|
||||
track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
|
||||
|
||||
track_value->subpath = leftover_path;
|
||||
track_value->object_id = track_value->object->get_instance_id();
|
||||
|
||||
|
@ -804,6 +806,10 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
|
|||
default: {
|
||||
}
|
||||
}
|
||||
} else if (track_cache_type == Animation::TYPE_VALUE) {
|
||||
// If it has at least one angle interpolation, it also uses angle interpolation for blending.
|
||||
TrackCacheValue *track_value = memnew(TrackCacheValue);
|
||||
track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
|
||||
}
|
||||
|
||||
track->setup_pass = setup_pass;
|
||||
|
@ -1353,8 +1359,28 @@ void AnimationTree::_process_graph(double p_delta) {
|
|||
t->value = t->init_value;
|
||||
}
|
||||
|
||||
Variant::sub(value, t->init_value, value);
|
||||
Variant::blend(t->value, value, blend, t->value);
|
||||
// Special case for angle interpolation.
|
||||
if (t->is_using_angle) {
|
||||
// For blending consistency, it prevents rotation of more than 180 degrees from init_value.
|
||||
// This is the same as for Quaternion blends.
|
||||
float rot_a = t->value;
|
||||
float rot_b = value;
|
||||
float rot_init = t->init_value;
|
||||
rot_a = Math::fposmod(rot_a, (float)Math_TAU);
|
||||
rot_b = Math::fposmod(rot_b, (float)Math_TAU);
|
||||
rot_init = Math::fposmod(rot_init, (float)Math_TAU);
|
||||
if (rot_init < Math_PI) {
|
||||
rot_a = rot_a > rot_init + Math_PI ? rot_a - Math_TAU : rot_a;
|
||||
rot_b = rot_b > rot_init + Math_PI ? rot_b - Math_TAU : rot_b;
|
||||
} else {
|
||||
rot_a = rot_a < rot_init - Math_PI ? rot_a + Math_TAU : rot_a;
|
||||
rot_b = rot_b < rot_init - Math_PI ? rot_b + Math_TAU : rot_b;
|
||||
}
|
||||
t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU);
|
||||
} else {
|
||||
Variant::sub(value, t->init_value, value);
|
||||
Variant::blend(t->value, value, blend, t->value);
|
||||
}
|
||||
} else {
|
||||
if (blend < CMP_EPSILON) {
|
||||
continue; //nothing to blend
|
||||
|
|
|
@ -233,6 +233,7 @@ private:
|
|||
Variant init_value;
|
||||
Variant value;
|
||||
Vector<StringName> subpath;
|
||||
bool is_using_angle = false;
|
||||
TrackCacheValue() { type = Animation::TYPE_VALUE; }
|
||||
};
|
||||
|
||||
|
|
|
@ -2323,7 +2323,20 @@ Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p
|
|||
}
|
||||
|
||||
real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const {
|
||||
return p_a * (1.0 - p_c) + p_b * p_c;
|
||||
return Math::lerp(p_a, p_b, p_c);
|
||||
}
|
||||
|
||||
Variant Animation::_interpolate_angle(const Variant &p_a, const Variant &p_b, real_t p_c) const {
|
||||
Variant::Type type_a = p_a.get_type();
|
||||
Variant::Type type_b = p_b.get_type();
|
||||
uint32_t vformat = 1 << type_a;
|
||||
vformat |= 1 << type_b;
|
||||
if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) {
|
||||
real_t a = p_a;
|
||||
real_t b = p_b;
|
||||
return Math::fposmod((float)Math::lerp_angle(a, b, p_c), (float)Math_TAU);
|
||||
}
|
||||
return _interpolate(p_a, p_b, p_c);
|
||||
}
|
||||
|
||||
// Cubic interpolation for anytype.
|
||||
|
@ -2413,6 +2426,25 @@ Variant Animation::_cubic_interpolate_in_time(const Variant &p_pre_a, const Vari
|
|||
}
|
||||
|
||||
real_t Animation::_cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
|
||||
return Math::cubic_interpolate_in_time(p_a, p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
|
||||
}
|
||||
|
||||
Variant Animation::_cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
|
||||
Variant::Type type_a = p_a.get_type();
|
||||
Variant::Type type_b = p_b.get_type();
|
||||
Variant::Type type_pa = p_pre_a.get_type();
|
||||
Variant::Type type_pb = p_post_b.get_type();
|
||||
uint32_t vformat = 1 << type_a;
|
||||
vformat |= 1 << type_b;
|
||||
vformat |= 1 << type_pa;
|
||||
vformat |= 1 << type_pb;
|
||||
if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) {
|
||||
real_t a = p_a;
|
||||
real_t b = p_b;
|
||||
real_t pa = p_pre_a;
|
||||
real_t pb = p_post_b;
|
||||
return Math::fposmod((float)Math::cubic_interpolate_angle_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t), (float)Math_TAU);
|
||||
}
|
||||
return _interpolate(p_a, p_b, p_c);
|
||||
}
|
||||
|
||||
|
@ -2595,7 +2627,11 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
|
|||
case INTERPOLATION_LINEAR: {
|
||||
return _interpolate(p_keys[idx].value, p_keys[next].value, c);
|
||||
} break;
|
||||
case INTERPOLATION_CUBIC: {
|
||||
case INTERPOLATION_LINEAR_ANGLE: {
|
||||
return _interpolate_angle(p_keys[idx].value, p_keys[next].value, c);
|
||||
} break;
|
||||
case INTERPOLATION_CUBIC:
|
||||
case INTERPOLATION_CUBIC_ANGLE: {
|
||||
int pre = 0;
|
||||
int post = 0;
|
||||
if (!p_backward) {
|
||||
|
@ -2634,19 +2670,27 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
|
|||
}
|
||||
}
|
||||
|
||||
real_t pre_t = 0.0;
|
||||
real_t to_t = 0.0;
|
||||
real_t post_t = 0.0;
|
||||
if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
|
||||
return _cubic_interpolate_in_time(
|
||||
p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
|
||||
pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time,
|
||||
next < idx ? length + p_keys[next].time - p_keys[idx].time : p_keys[next].time - p_keys[idx].time,
|
||||
next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time);
|
||||
pre_t = pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time;
|
||||
to_t = next < idx ? length + p_keys[next].time - p_keys[idx].time : p_keys[next].time - p_keys[idx].time;
|
||||
post_t = next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time;
|
||||
} else {
|
||||
pre_t = p_keys[pre].time - p_keys[idx].time;
|
||||
to_t = p_keys[next].time - p_keys[idx].time;
|
||||
post_t = p_keys[post].time - p_keys[idx].time;
|
||||
}
|
||||
|
||||
if (p_interp == INTERPOLATION_CUBIC_ANGLE) {
|
||||
return _cubic_interpolate_angle_in_time(
|
||||
p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
|
||||
pre_t, to_t, post_t);
|
||||
}
|
||||
return _cubic_interpolate_in_time(
|
||||
p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
|
||||
p_keys[pre].time - p_keys[idx].time,
|
||||
p_keys[next].time - p_keys[idx].time,
|
||||
p_keys[post].time - p_keys[idx].time);
|
||||
pre_t, to_t, post_t);
|
||||
} break;
|
||||
default:
|
||||
return p_keys[idx].value;
|
||||
|
@ -3976,6 +4020,8 @@ void Animation::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(INTERPOLATION_NEAREST);
|
||||
BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR);
|
||||
BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC);
|
||||
BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR_ANGLE);
|
||||
BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC_ANGLE);
|
||||
|
||||
BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS);
|
||||
BIND_ENUM_CONSTANT(UPDATE_DISCRETE);
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
INTERPOLATION_NEAREST,
|
||||
INTERPOLATION_LINEAR,
|
||||
INTERPOLATION_CUBIC,
|
||||
INTERPOLATION_LINEAR_ANGLE,
|
||||
INTERPOLATION_CUBIC_ANGLE,
|
||||
};
|
||||
|
||||
enum UpdateMode {
|
||||
|
@ -236,11 +238,13 @@ private:
|
|||
_FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const;
|
||||
_FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const;
|
||||
_FORCE_INLINE_ real_t _interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const;
|
||||
_FORCE_INLINE_ Variant _interpolate_angle(const Variant &p_a, const Variant &p_b, real_t p_c) const;
|
||||
|
||||
_FORCE_INLINE_ Vector3 _cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
|
||||
_FORCE_INLINE_ Quaternion _cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
|
||||
_FORCE_INLINE_ Variant _cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
|
||||
_FORCE_INLINE_ real_t _cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
|
||||
_FORCE_INLINE_ Variant _cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
|
||||
|
||||
template <class T>
|
||||
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const;
|
||||
|
|
Loading…
Reference in New Issue