Optimize animations
This commit is contained in:
parent
fd7239cfab
commit
3580ced21e
|
@ -947,14 +947,6 @@ void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {
|
||||||
clear_animation_instances();
|
clear_animation_instances();
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
|
|
||||||
Variant res;
|
|
||||||
if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
|
Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
switch (p_anim->track_get_type(p_track)) {
|
switch (p_anim->track_get_type(p_track)) {
|
||||||
|
@ -974,6 +966,17 @@ Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, in
|
||||||
return p_value;
|
return p_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
|
||||||
|
if (is_GDVIRTUAL_CALL_post_process_key_value) {
|
||||||
|
Variant res;
|
||||||
|
if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
is_GDVIRTUAL_CALL_post_process_key_value = false;
|
||||||
|
}
|
||||||
|
return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx);
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationMixer::_blend_init() {
|
void AnimationMixer::_blend_init() {
|
||||||
// Check all tracks, see if they need modification.
|
// Check all tracks, see if they need modification.
|
||||||
root_motion_position = Vector3(0, 0, 0);
|
root_motion_position = Vector3(0, 0, 0);
|
||||||
|
@ -1080,22 +1083,25 @@ void AnimationMixer::_blend_calc_total_weight() {
|
||||||
for (const AnimationInstance &ai : animation_instances) {
|
for (const AnimationInstance &ai : animation_instances) {
|
||||||
Ref<Animation> a = ai.animation_data.animation;
|
Ref<Animation> a = ai.animation_data.animation;
|
||||||
real_t weight = ai.playback_info.weight;
|
real_t weight = ai.playback_info.weight;
|
||||||
Vector<real_t> track_weights = ai.playback_info.track_weights;
|
const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();
|
||||||
|
int track_weights_count = ai.playback_info.track_weights.size();
|
||||||
Vector<Animation::TypeHash> processed_hashes;
|
Vector<Animation::TypeHash> processed_hashes;
|
||||||
for (int i = 0; i < a->get_track_count(); i++) {
|
const Vector<Animation::Track *> tracks = a->get_tracks();
|
||||||
if (!a->track_is_enabled(i)) {
|
for (const Animation::Track *animation_track : tracks) {
|
||||||
|
if (!animation_track->enabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Animation::TypeHash thash = a->track_get_type_hash(i);
|
Animation::TypeHash thash = animation_track->thash;
|
||||||
if (!track_cache.has(thash) || processed_hashes.has(thash)) {
|
TrackCache **track_ptr = track_cache.getptr(thash);
|
||||||
|
if (track_ptr == nullptr || processed_hashes.has(thash)) {
|
||||||
// No path, but avoid error spamming.
|
// No path, but avoid error spamming.
|
||||||
// Or, there is the case different track type with same path; These can be distinguished by hash. So don't add the weight doubly.
|
// Or, there is the case different track type with same path; These can be distinguished by hash. So don't add the weight doubly.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TrackCache *track = track_cache[thash];
|
TrackCache *track = *track_ptr;
|
||||||
int blend_idx = track_map[track->path];
|
int blend_idx = track_map[track->path];
|
||||||
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
|
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
|
||||||
real_t blend = blend_idx < track_weights.size() ? track_weights[blend_idx] * weight : weight;
|
real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;
|
||||||
track->total_weight += blend;
|
track->total_weight += blend;
|
||||||
processed_hashes.push_back(thash);
|
processed_hashes.push_back(thash);
|
||||||
}
|
}
|
||||||
|
@ -1115,26 +1121,33 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
Animation::LoopedFlag looped_flag = ai.playback_info.looped_flag;
|
Animation::LoopedFlag looped_flag = ai.playback_info.looped_flag;
|
||||||
bool is_external_seeking = ai.playback_info.is_external_seeking;
|
bool is_external_seeking = ai.playback_info.is_external_seeking;
|
||||||
real_t weight = ai.playback_info.weight;
|
real_t weight = ai.playback_info.weight;
|
||||||
Vector<real_t> track_weights = ai.playback_info.track_weights;
|
const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();
|
||||||
|
int track_weights_count = ai.playback_info.track_weights.size();
|
||||||
bool backward = signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.
|
bool backward = signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.
|
||||||
bool seeked_backward = signbit(p_delta);
|
bool seeked_backward = signbit(p_delta);
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
bool calc_root = !seeked || is_external_seeking;
|
bool calc_root = !seeked || is_external_seeking;
|
||||||
#endif // _3D_DISABLED
|
#endif // _3D_DISABLED
|
||||||
|
const Vector<Animation::Track *> tracks = a->get_tracks();
|
||||||
for (int i = 0; i < a->get_track_count(); i++) {
|
Animation::Track *const *tracks_ptr = tracks.ptr();
|
||||||
if (!a->track_is_enabled(i)) {
|
real_t a_length = a->get_length();
|
||||||
|
int count = tracks.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
const Animation::Track *animation_track = tracks_ptr[i];
|
||||||
|
if (!animation_track->enabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Animation::TypeHash thash = a->track_get_type_hash(i);
|
Animation::TypeHash thash = animation_track->thash;
|
||||||
if (!track_cache.has(thash)) {
|
TrackCache **track_ptr = track_cache.getptr(thash);
|
||||||
|
if (track_ptr == nullptr) {
|
||||||
continue; // No path, but avoid error spamming.
|
continue; // No path, but avoid error spamming.
|
||||||
}
|
}
|
||||||
TrackCache *track = track_cache[thash];
|
TrackCache *track = *track_ptr;
|
||||||
ERR_CONTINUE(!track_map.has(track->path));
|
int *blend_idx_ptr = track_map.getptr(track->path);
|
||||||
int blend_idx = track_map[track->path];
|
ERR_CONTINUE(blend_idx_ptr == nullptr);
|
||||||
|
int blend_idx = *blend_idx_ptr;
|
||||||
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
|
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
|
||||||
real_t blend = blend_idx < track_weights.size() ? track_weights[blend_idx] * weight : weight;
|
real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;
|
||||||
if (!deterministic) {
|
if (!deterministic) {
|
||||||
// If non-deterministic, do normalization.
|
// If non-deterministic, do normalization.
|
||||||
// It would be better to make this if statement outside the for loop, but come here since too much code...
|
// It would be better to make this if statement outside the for loop, but come here since too much code...
|
||||||
|
@ -1143,8 +1156,8 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
blend = blend / track->total_weight;
|
blend = blend / track->total_weight;
|
||||||
}
|
}
|
||||||
Animation::TrackType ttype = a->track_get_type(i);
|
Animation::TrackType ttype = animation_track->type;
|
||||||
track->root_motion = root_motion_track == a->track_get_path(i);
|
track->root_motion = root_motion_track == animation_track->path;
|
||||||
switch (ttype) {
|
switch (ttype) {
|
||||||
case Animation::TYPE_POSITION_3D: {
|
case Animation::TYPE_POSITION_3D: {
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
|
@ -1161,26 +1174,26 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_LINEAR: {
|
case Animation::LOOP_LINEAR: {
|
||||||
prev_time = Math::fposmod(prev_time, (double)a->get_length());
|
prev_time = Math::fposmod(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
prev_time = Math::pingpong(prev_time, (double)a->get_length());
|
prev_time = Math::pingpong(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
|
if (Animation::is_greater_approx(prev_time, (double)a_length)) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a_length;
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_LINEAR: {
|
case Animation::LOOP_LINEAR: {
|
||||||
prev_time = Math::fposmod(prev_time, (double)a->get_length());
|
prev_time = Math::fposmod(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
prev_time = Math::pingpong(prev_time, (double)a->get_length());
|
prev_time = Math::pingpong(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1195,7 +1208,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
|
loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
|
||||||
a->try_position_track_interpolate(i, (double)a->get_length(), &loc[1]);
|
a->try_position_track_interpolate(i, (double)a_length, &loc[1]);
|
||||||
loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
|
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;
|
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
|
@ -1210,7 +1223,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
a->try_position_track_interpolate(i, 0, &loc[1]);
|
a->try_position_track_interpolate(i, 0, &loc[1]);
|
||||||
loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
|
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;
|
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
|
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
|
||||||
|
@ -1221,7 +1234,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
a->try_position_track_interpolate(i, time, &loc[1]);
|
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);
|
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;
|
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
|
||||||
prev_time = !backward ? 0 : (double)a->get_length();
|
prev_time = !backward ? 0 : (double)a_length;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Vector3 loc;
|
Vector3 loc;
|
||||||
|
@ -1249,26 +1262,26 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_LINEAR: {
|
case Animation::LOOP_LINEAR: {
|
||||||
prev_time = Math::fposmod(prev_time, (double)a->get_length());
|
prev_time = Math::fposmod(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
prev_time = Math::pingpong(prev_time, (double)a->get_length());
|
prev_time = Math::pingpong(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
|
if (Animation::is_greater_approx(prev_time, (double)a_length)) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a_length;
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_LINEAR: {
|
case Animation::LOOP_LINEAR: {
|
||||||
prev_time = Math::fposmod(prev_time, (double)a->get_length());
|
prev_time = Math::fposmod(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
prev_time = Math::pingpong(prev_time, (double)a->get_length());
|
prev_time = Math::pingpong(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1283,7 +1296,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
|
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
|
||||||
a->try_rotation_track_interpolate(i, (double)a->get_length(), &rot[1]);
|
a->try_rotation_track_interpolate(i, (double)a_length, &rot[1]);
|
||||||
rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
|
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();
|
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
|
@ -1297,7 +1310,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);
|
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
|
||||||
a->try_rotation_track_interpolate(i, 0, &rot[1]);
|
a->try_rotation_track_interpolate(i, 0, &rot[1]);
|
||||||
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
|
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
|
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
|
||||||
|
@ -1308,7 +1321,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
a->try_rotation_track_interpolate(i, time, &rot[1]);
|
a->try_rotation_track_interpolate(i, time, &rot[1]);
|
||||||
rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
|
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();
|
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
|
||||||
prev_time = !backward ? 0 : (double)a->get_length();
|
prev_time = !backward ? 0 : (double)a_length;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Quaternion rot;
|
Quaternion rot;
|
||||||
|
@ -1336,26 +1349,26 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_LINEAR: {
|
case Animation::LOOP_LINEAR: {
|
||||||
prev_time = Math::fposmod(prev_time, (double)a->get_length());
|
prev_time = Math::fposmod(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
prev_time = Math::pingpong(prev_time, (double)a->get_length());
|
prev_time = Math::pingpong(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
|
if (Animation::is_greater_approx(prev_time, (double)a_length)) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a_length;
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_LINEAR: {
|
case Animation::LOOP_LINEAR: {
|
||||||
prev_time = Math::fposmod(prev_time, (double)a->get_length());
|
prev_time = Math::fposmod(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
prev_time = Math::pingpong(prev_time, (double)a->get_length());
|
prev_time = Math::pingpong(prev_time, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1370,7 +1383,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
|
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
|
||||||
a->try_scale_track_interpolate(i, (double)a->get_length(), &scale[1]);
|
a->try_scale_track_interpolate(i, (double)a_length, &scale[1]);
|
||||||
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
|
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);
|
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
|
@ -1385,7 +1398,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
a->try_scale_track_interpolate(i, 0, &scale[1]);
|
a->try_scale_track_interpolate(i, 0, &scale[1]);
|
||||||
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
|
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;
|
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
|
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
|
||||||
|
@ -1396,7 +1409,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
a->try_scale_track_interpolate(i, time, &scale[1]);
|
a->try_scale_track_interpolate(i, time, &scale[1]);
|
||||||
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
|
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;
|
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
|
||||||
prev_time = !backward ? 0 : (double)a->get_length();
|
prev_time = !backward ? 0 : (double)a_length;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Vector3 scale;
|
Vector3 scale;
|
||||||
|
@ -1560,7 +1573,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayingAudioTrackInfo &track_info = t->playing_streams[oid];
|
PlayingAudioTrackInfo &track_info = t->playing_streams[oid];
|
||||||
track_info.length = a->get_length();
|
track_info.length = a_length;
|
||||||
track_info.time = time;
|
track_info.time = time;
|
||||||
track_info.volume += blend;
|
track_info.volume += blend;
|
||||||
track_info.loop = a->get_loop_mode() != Animation::LOOP_NONE;
|
track_info.loop = a->get_loop_mode() != Animation::LOOP_NONE;
|
||||||
|
@ -1679,7 +1692,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
at_anim_pos = Math::fposmod(time - pos, (double)anim->get_length()); // Seek to loop.
|
at_anim_pos = Math::fposmod(time - pos, (double)anim->get_length()); // Seek to loop.
|
||||||
} break;
|
} break;
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
at_anim_pos = Math::pingpong(time - pos, (double)a->get_length());
|
at_anim_pos = Math::pingpong(time - pos, (double)a_length);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1717,6 +1730,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is_GDVIRTUAL_CALL_post_process_key_value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationMixer::_blend_apply() {
|
void AnimationMixer::_blend_apply() {
|
||||||
|
|
|
@ -48,6 +48,7 @@ class AnimationMixer : public Node {
|
||||||
#endif // TOOLS_ENABLED
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
bool reset_on_save = true;
|
bool reset_on_save = true;
|
||||||
|
bool is_GDVIRTUAL_CALL_post_process_key_value = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum AnimationCallbackModeProcess {
|
enum AnimationCallbackModeProcess {
|
||||||
|
|
|
@ -203,10 +203,11 @@ AnimationNode::NodeTimeInfo AnimationNode::_blend_node(Ref<AnimationNode> p_node
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const KeyValue<NodePath, bool> &E : filter) {
|
for (const KeyValue<NodePath, bool> &E : filter) {
|
||||||
if (!process_state->track_map.has(E.key)) {
|
const HashMap<NodePath, int> &map = *process_state->track_map;
|
||||||
|
if (!map.has(E.key)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int idx = process_state->track_map[E.key];
|
int idx = map[E.key];
|
||||||
blendw[idx] = 1.0; // Filtered goes to one.
|
blendw[idx] = 1.0; // Filtered goes to one.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,7 +619,7 @@ bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const
|
||||||
process_state.valid = true;
|
process_state.valid = true;
|
||||||
process_state.invalid_reasons = "";
|
process_state.invalid_reasons = "";
|
||||||
process_state.last_pass = process_pass;
|
process_state.last_pass = process_pass;
|
||||||
process_state.track_map = p_track_map;
|
process_state.track_map = &p_track_map;
|
||||||
|
|
||||||
// Init node state for root AnimationNode.
|
// Init node state for root AnimationNode.
|
||||||
root_animation_node->node_state.track_weights.resize(p_track_count);
|
root_animation_node->node_state.track_weights.resize(p_track_count);
|
||||||
|
|
|
@ -106,7 +106,7 @@ public:
|
||||||
// Temporary state for blending process which needs to be started in the AnimationTree, pass through the AnimationNodes, and then return to the AnimationTree.
|
// Temporary state for blending process which needs to be started in the AnimationTree, pass through the AnimationNodes, and then return to the AnimationTree.
|
||||||
struct ProcessState {
|
struct ProcessState {
|
||||||
AnimationTree *tree = nullptr;
|
AnimationTree *tree = nullptr;
|
||||||
HashMap<NodePath, int> track_map; // TODO: Is there a better way to manage filter/tracks?
|
const HashMap<NodePath, int> *track_map; // TODO: Is there a better way to manage filter/tracks?
|
||||||
bool is_testing = false;
|
bool is_testing = false;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
String invalid_reasons;
|
String invalid_reasons;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
|
|
||||||
static inline String PARAMETERS_BASE_PATH = "parameters/";
|
static inline String PARAMETERS_BASE_PATH = "parameters/";
|
||||||
|
|
||||||
enum TrackType {
|
enum TrackType : uint8_t {
|
||||||
TYPE_VALUE, // Set a value in a property, can be interpolated.
|
TYPE_VALUE, // Set a value in a property, can be interpolated.
|
||||||
TYPE_POSITION_3D, // Position 3D track, can be compressed.
|
TYPE_POSITION_3D, // Position 3D track, can be compressed.
|
||||||
TYPE_ROTATION_3D, // Rotation 3D track, can be compressed.
|
TYPE_ROTATION_3D, // Rotation 3D track, can be compressed.
|
||||||
|
@ -57,7 +57,7 @@ public:
|
||||||
TYPE_ANIMATION,
|
TYPE_ANIMATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum InterpolationType {
|
enum InterpolationType : uint8_t {
|
||||||
INTERPOLATION_NEAREST,
|
INTERPOLATION_NEAREST,
|
||||||
INTERPOLATION_LINEAR,
|
INTERPOLATION_LINEAR,
|
||||||
INTERPOLATION_CUBIC,
|
INTERPOLATION_CUBIC,
|
||||||
|
@ -65,26 +65,26 @@ public:
|
||||||
INTERPOLATION_CUBIC_ANGLE,
|
INTERPOLATION_CUBIC_ANGLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum UpdateMode {
|
enum UpdateMode : uint8_t {
|
||||||
UPDATE_CONTINUOUS,
|
UPDATE_CONTINUOUS,
|
||||||
UPDATE_DISCRETE,
|
UPDATE_DISCRETE,
|
||||||
UPDATE_CAPTURE,
|
UPDATE_CAPTURE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LoopMode {
|
enum LoopMode : uint8_t {
|
||||||
LOOP_NONE,
|
LOOP_NONE,
|
||||||
LOOP_LINEAR,
|
LOOP_LINEAR,
|
||||||
LOOP_PINGPONG,
|
LOOP_PINGPONG,
|
||||||
};
|
};
|
||||||
|
|
||||||
// LoopedFlag is used in Animataion to "process the keys at both ends correct".
|
// LoopedFlag is used in Animataion to "process the keys at both ends correct".
|
||||||
enum LoopedFlag {
|
enum LoopedFlag : uint8_t {
|
||||||
LOOPED_FLAG_NONE,
|
LOOPED_FLAG_NONE,
|
||||||
LOOPED_FLAG_END,
|
LOOPED_FLAG_END,
|
||||||
LOOPED_FLAG_START,
|
LOOPED_FLAG_START,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FindMode {
|
enum FindMode : uint8_t {
|
||||||
FIND_MODE_NEAREST,
|
FIND_MODE_NEAREST,
|
||||||
FIND_MODE_APPROX,
|
FIND_MODE_APPROX,
|
||||||
FIND_MODE_EXACT,
|
FIND_MODE_EXACT,
|
||||||
|
@ -104,7 +104,6 @@ public:
|
||||||
};
|
};
|
||||||
#endif // TOOLS_ENABLED
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
private:
|
|
||||||
struct Track {
|
struct Track {
|
||||||
TrackType type = TrackType::TYPE_ANIMATION;
|
TrackType type = TrackType::TYPE_ANIMATION;
|
||||||
InterpolationType interpolation = INTERPOLATION_LINEAR;
|
InterpolationType interpolation = INTERPOLATION_LINEAR;
|
||||||
|
@ -117,6 +116,7 @@ private:
|
||||||
virtual ~Track() {}
|
virtual ~Track() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
struct Key {
|
struct Key {
|
||||||
real_t transition = 1.0;
|
real_t transition = 1.0;
|
||||||
double time = 0.0; // Time in secs.
|
double time = 0.0; // Time in secs.
|
||||||
|
@ -396,6 +396,10 @@ public:
|
||||||
int add_track(TrackType p_type, int p_at_pos = -1);
|
int add_track(TrackType p_type, int p_at_pos = -1);
|
||||||
void remove_track(int p_track);
|
void remove_track(int p_track);
|
||||||
|
|
||||||
|
_FORCE_INLINE_ const Vector<Track *> get_tracks() {
|
||||||
|
return tracks;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_capture_included() const;
|
bool is_capture_included() const;
|
||||||
|
|
||||||
int get_track_count() const;
|
int get_track_count() const;
|
||||||
|
|
Loading…
Reference in New Issue