Merge pull request #92126 from TokageItLab/reset-dominant
Fix Deterministic blending with Dominant/Recessive doesn't have initial value even if there is no Discrete track
This commit is contained in:
commit
20ad681da2
4 changed files with 31 additions and 15 deletions
|
@ -273,7 +273,7 @@
|
||||||
The number of possible simultaneous sounds for each of the assigned AudioStreamPlayers.
|
The number of possible simultaneous sounds for each of the assigned AudioStreamPlayers.
|
||||||
For example, if this value is [code]32[/code] and the animation has two audio tracks, the two [AudioStreamPlayer]s assigned can play simultaneously up to [code]32[/code] voices each.
|
For example, if this value is [code]32[/code] and the animation has two audio tracks, the two [AudioStreamPlayer]s assigned can play simultaneously up to [code]32[/code] voices each.
|
||||||
</member>
|
</member>
|
||||||
<member name="callback_mode_discrete" type="int" setter="set_callback_mode_discrete" getter="get_callback_mode_discrete" enum="AnimationMixer.AnimationCallbackModeDiscrete" default="0">
|
<member name="callback_mode_discrete" type="int" setter="set_callback_mode_discrete" getter="get_callback_mode_discrete" enum="AnimationMixer.AnimationCallbackModeDiscrete" default="1">
|
||||||
Ordinarily, tracks can be set to [constant Animation.UPDATE_DISCRETE] to update infrequently, usually when using nearest interpolation.
|
Ordinarily, tracks can be set to [constant Animation.UPDATE_DISCRETE] to update infrequently, usually when using nearest interpolation.
|
||||||
However, when blending with [constant Animation.UPDATE_CONTINUOUS] several results are considered. The [member callback_mode_discrete] specify it explicitly. See also [enum AnimationCallbackModeDiscrete].
|
However, when blending with [constant Animation.UPDATE_CONTINUOUS] several results are considered. The [member callback_mode_discrete] specify it explicitly. See also [enum AnimationCallbackModeDiscrete].
|
||||||
To make the blended results look good, it is recommended to set this to [constant ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS] to update every frame during blending. Other values exist for compatibility and they are fine if there is no blending, but not so, may produce artifacts.
|
To make the blended results look good, it is recommended to set this to [constant ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS] to update every frame during blending. Other values exist for compatibility and they are fine if there is no blending, but not so, may produce artifacts.
|
||||||
|
@ -361,14 +361,14 @@
|
||||||
Make method calls immediately when reached in the animation.
|
Make method calls immediately when reached in the animation.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT" value="0" enum="AnimationCallbackModeDiscrete">
|
<constant name="ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT" value="0" enum="AnimationCallbackModeDiscrete">
|
||||||
An [constant Animation.UPDATE_DISCRETE] track value takes precedence when blending [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and [constant Animation.UPDATE_DISCRETE] track values. This is the default behavior for [AnimationPlayer].
|
An [constant Animation.UPDATE_DISCRETE] track value takes precedence when blending [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and [constant Animation.UPDATE_DISCRETE] track values.
|
||||||
[b]Note:[/b] If a value track has non-numeric type key values, it is internally converted to use [constant ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT] with [constant Animation.UPDATE_DISCRETE].
|
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE" value="1" enum="AnimationCallbackModeDiscrete">
|
<constant name="ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE" value="1" enum="AnimationCallbackModeDiscrete">
|
||||||
An [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track value takes precedence when blending the [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and the [constant Animation.UPDATE_DISCRETE] track values.
|
An [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track value takes precedence when blending the [constant Animation.UPDATE_CONTINUOUS] or [constant Animation.UPDATE_CAPTURE] track values and the [constant Animation.UPDATE_DISCRETE] track values. This is the default behavior for [AnimationPlayer].
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS" value="2" enum="AnimationCallbackModeDiscrete">
|
<constant name="ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS" value="2" enum="AnimationCallbackModeDiscrete">
|
||||||
Always treat the [constant Animation.UPDATE_DISCRETE] track value as [constant Animation.UPDATE_CONTINUOUS] with [constant Animation.INTERPOLATION_NEAREST]. This is the default behavior for [AnimationTree].
|
Always treat the [constant Animation.UPDATE_DISCRETE] track value as [constant Animation.UPDATE_CONTINUOUS] with [constant Animation.INTERPOLATION_NEAREST]. This is the default behavior for [AnimationTree].
|
||||||
|
If a value track has non-numeric type key values, it is internally converted to use [constant ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE] with [constant Animation.UPDATE_DISCRETE].
|
||||||
</constant>
|
</constant>
|
||||||
</constants>
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
@ -501,6 +501,7 @@ AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_me
|
||||||
|
|
||||||
void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) {
|
void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) {
|
||||||
callback_mode_discrete = p_mode;
|
callback_mode_discrete = p_mode;
|
||||||
|
_clear_caches();
|
||||||
emit_signal(SNAME("mixer_updated"));
|
emit_signal(SNAME("mixer_updated"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +689,7 @@ bool AnimationMixer::_update_caches() {
|
||||||
track_value->init_value = anim->track_get_key_value(i, 0);
|
track_value->init_value = anim->track_get_key_value(i, 0);
|
||||||
track_value->init_value.zero();
|
track_value->init_value.zero();
|
||||||
|
|
||||||
track_value->init_use_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;
|
track_value->is_init = false;
|
||||||
|
|
||||||
// Can't interpolate them, need to convert.
|
// Can't interpolate them, need to convert.
|
||||||
track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value);
|
track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value);
|
||||||
|
@ -698,7 +699,6 @@ bool AnimationMixer::_update_caches() {
|
||||||
int rt = reset_anim->find_track(path, track_src_type);
|
int rt = reset_anim->find_track(path, track_src_type);
|
||||||
if (rt >= 0) {
|
if (rt >= 0) {
|
||||||
if (track_src_type == Animation::TYPE_VALUE) {
|
if (track_src_type == Animation::TYPE_VALUE) {
|
||||||
track_value->init_use_continuous = track_value->init_use_continuous || (reset_anim->value_track_get_update_mode(rt) != Animation::UPDATE_DISCRETE); // Take precedence Force Continuous.
|
|
||||||
if (reset_anim->track_get_key_count(rt) > 0) {
|
if (reset_anim->track_get_key_count(rt) > 0) {
|
||||||
track_value->init_value = reset_anim->track_get_key_value(rt, 0);
|
track_value->init_value = reset_anim->track_get_key_value(rt, 0);
|
||||||
}
|
}
|
||||||
|
@ -1006,7 +1006,7 @@ void AnimationMixer::_blend_init() {
|
||||||
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
|
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
|
||||||
t->value = Animation::cast_to_blendwise(t->init_value);
|
t->value = Animation::cast_to_blendwise(t->init_value);
|
||||||
t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;
|
t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;
|
||||||
t->use_continuous = t->init_use_continuous;
|
t->use_continuous = false;
|
||||||
t->use_discrete = false;
|
t->use_discrete = false;
|
||||||
} break;
|
} break;
|
||||||
case Animation::TYPE_AUDIO: {
|
case Animation::TYPE_AUDIO: {
|
||||||
|
@ -1462,12 +1462,12 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
t->value = Animation::blend_variant(t->value, value, blend);
|
t->value = Animation::blend_variant(t->value, value, blend);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t->use_discrete = true;
|
|
||||||
if (seeked) {
|
if (seeked) {
|
||||||
int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true);
|
int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
t->use_discrete = true;
|
||||||
Variant value = a->track_get_key_value(i, idx);
|
Variant value = a->track_get_key_value(i, idx);
|
||||||
value = post_process_key_value(a, i, value, t->object_id);
|
value = post_process_key_value(a, i, value, t->object_id);
|
||||||
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
||||||
|
@ -1478,6 +1478,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
List<int> indices;
|
List<int> indices;
|
||||||
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
|
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
|
||||||
for (int &F : indices) {
|
for (int &F : indices) {
|
||||||
|
t->use_discrete = true;
|
||||||
Variant value = a->track_get_key_value(i, F);
|
Variant value = a->track_get_key_value(i, F);
|
||||||
value = post_process_key_value(a, i, value, t->object_id);
|
value = post_process_key_value(a, i, value, t->object_id);
|
||||||
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
||||||
|
@ -1682,7 +1683,8 @@ void AnimationMixer::_blend_apply() {
|
||||||
// Finally, set the tracks.
|
// Finally, set the tracks.
|
||||||
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
||||||
TrackCache *track = K.value;
|
TrackCache *track = K.value;
|
||||||
if (!deterministic && Math::is_zero_approx(track->total_weight)) {
|
bool is_zero_amount = Math::is_zero_approx(track->total_weight);
|
||||||
|
if (!deterministic && is_zero_amount) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (track->type) {
|
switch (track->type) {
|
||||||
|
@ -1742,10 +1744,24 @@ void AnimationMixer::_blend_apply() {
|
||||||
case Animation::TYPE_VALUE: {
|
case Animation::TYPE_VALUE: {
|
||||||
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
|
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
|
||||||
|
|
||||||
if (!t->is_variant_interpolatable || !t->use_continuous || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) {
|
if (t->use_discrete && !t->use_continuous) {
|
||||||
|
t->is_init = true; // If only disctere value is applied, no more RESET.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((t->is_init && (is_zero_amount || !t->use_continuous)) ||
|
||||||
|
(callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS &&
|
||||||
|
!is_zero_amount &&
|
||||||
|
callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT &&
|
||||||
|
t->use_discrete)) {
|
||||||
break; // Don't overwrite the value set by UPDATE_DISCRETE.
|
break; // Don't overwrite the value set by UPDATE_DISCRETE.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {
|
||||||
|
t->is_init = false; // Always update in Force Continuous.
|
||||||
|
} else {
|
||||||
|
t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET.
|
||||||
|
}
|
||||||
|
|
||||||
// Trim unused elements if init array/string is not blended.
|
// Trim unused elements if init array/string is not blended.
|
||||||
if (t->value.is_array()) {
|
if (t->value.is_array()) {
|
||||||
int actual_blended_size = (int)Math::round(Math::abs(t->element_size.operator real_t()));
|
int actual_blended_size = (int)Math::round(Math::abs(t->element_size.operator real_t()));
|
||||||
|
|
|
@ -126,7 +126,7 @@ protected:
|
||||||
/* ---- General settings for animation ---- */
|
/* ---- General settings for animation ---- */
|
||||||
AnimationCallbackModeProcess callback_mode_process = ANIMATION_CALLBACK_MODE_PROCESS_IDLE;
|
AnimationCallbackModeProcess callback_mode_process = ANIMATION_CALLBACK_MODE_PROCESS_IDLE;
|
||||||
AnimationCallbackModeMethod callback_mode_method = ANIMATION_CALLBACK_MODE_METHOD_DEFERRED;
|
AnimationCallbackModeMethod callback_mode_method = ANIMATION_CALLBACK_MODE_METHOD_DEFERRED;
|
||||||
AnimationCallbackModeDiscrete callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT;
|
AnimationCallbackModeDiscrete callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE;
|
||||||
int audio_max_polyphony = 32;
|
int audio_max_polyphony = 32;
|
||||||
NodePath root_node;
|
NodePath root_node;
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ protected:
|
||||||
Vector<StringName> subpath;
|
Vector<StringName> subpath;
|
||||||
|
|
||||||
// TODO: There are many boolean, can be packed into one integer.
|
// TODO: There are many boolean, can be packed into one integer.
|
||||||
bool init_use_continuous = false;
|
bool is_init = false;
|
||||||
bool use_continuous = false;
|
bool use_continuous = false;
|
||||||
bool use_discrete = false;
|
bool use_discrete = false;
|
||||||
bool is_using_angle = false;
|
bool is_using_angle = false;
|
||||||
|
@ -237,7 +237,7 @@ protected:
|
||||||
init_value(p_other.init_value),
|
init_value(p_other.init_value),
|
||||||
value(p_other.value),
|
value(p_other.value),
|
||||||
subpath(p_other.subpath),
|
subpath(p_other.subpath),
|
||||||
init_use_continuous(p_other.init_use_continuous),
|
is_init(p_other.is_init),
|
||||||
use_continuous(p_other.use_continuous),
|
use_continuous(p_other.use_continuous),
|
||||||
use_discrete(p_other.use_discrete),
|
use_discrete(p_other.use_discrete),
|
||||||
is_using_angle(p_other.is_using_angle),
|
is_using_angle(p_other.is_using_angle),
|
||||||
|
|
|
@ -447,10 +447,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
|
||||||
} else {
|
} else {
|
||||||
if (p_from_end && c.current.pos == 0) {
|
if (p_from_end && c.current.pos == 0) {
|
||||||
// Animation reset but played backwards, set position to the end.
|
// Animation reset but played backwards, set position to the end.
|
||||||
c.current.pos = c.current.from->animation->get_length();
|
seek(c.current.from->animation->get_length(), true, true);
|
||||||
} else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) {
|
} else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) {
|
||||||
// Animation resumed but already ended, set position to the beginning.
|
// Animation resumed but already ended, set position to the beginning.
|
||||||
c.current.pos = 0;
|
seek(0, true, true);
|
||||||
} else if (playing) {
|
} else if (playing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue