Physics Interpolation - Fix non-interpolated resting xforms
Ensure servers are updated for non-interpolated Spatials, either during the scene tree update or a final pass. Ensure properties and xforms are given a final server update in the final resting positions after removal from tick lists. Fixes dirty local xform bug.
This commit is contained in:
@ -179,8 +179,11 @@ void Spatial::_notification(int p_what) {
|
|||||||
|
|
||||||
notification(NOTIFICATION_ENTER_WORLD);
|
notification(NOTIFICATION_ENTER_WORLD);
|
||||||
|
|
||||||
if (is_physics_interpolated_and_enabled()) {
|
if (is_inside_tree() && get_tree()->is_physics_interpolation_enabled()) {
|
||||||
// Always reset FTI when entering tree.
|
// Always reset FTI when entering tree
|
||||||
|
// and update the servers,
|
||||||
|
// both for interpolated and non-interpolated nodes,
|
||||||
|
// to ensure the server xforms are up to date.
|
||||||
fti_pump_xform();
|
fti_pump_xform();
|
||||||
|
|
||||||
// No need to interpolate as we are doing a reset.
|
// No need to interpolate as we are doing a reset.
|
||||||
@ -278,7 +281,7 @@ void Spatial::_notification(int p_what) {
|
|||||||
|
|
||||||
case NOTIFICATION_PAUSED: {
|
case NOTIFICATION_PAUSED: {
|
||||||
if (is_physics_interpolated_and_enabled()) {
|
if (is_physics_interpolated_and_enabled()) {
|
||||||
data.local_transform_prev = data.local_transform;
|
data.local_transform_prev = get_transform();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -310,11 +313,7 @@ void Spatial::set_global_rotation(const Vector3 &p_euler_rad) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Spatial::fti_pump_xform() {
|
void Spatial::fti_pump_xform() {
|
||||||
if (data.dirty & DIRTY_LOCAL) {
|
data.local_transform_prev = get_transform();
|
||||||
_update_local_transform();
|
|
||||||
}
|
|
||||||
|
|
||||||
data.local_transform_prev = data.local_transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spatial::fti_notify_node_changed(bool p_transform_changed) {
|
void Spatial::fti_notify_node_changed(bool p_transform_changed) {
|
||||||
@ -1119,6 +1118,7 @@ Spatial::Spatial() :
|
|||||||
data.fti_on_tick_xform_list = false;
|
data.fti_on_tick_xform_list = false;
|
||||||
data.fti_on_tick_property_list = false;
|
data.fti_on_tick_property_list = false;
|
||||||
data.fti_global_xform_interp_set = false;
|
data.fti_global_xform_interp_set = false;
|
||||||
|
data.fti_frame_xform_force_update = false;
|
||||||
|
|
||||||
data.merging_mode = MERGING_MODE_INHERIT;
|
data.merging_mode = MERGING_MODE_INHERIT;
|
||||||
|
|
||||||
|
|||||||
@ -128,6 +128,7 @@ private:
|
|||||||
bool fti_on_tick_xform_list : 1;
|
bool fti_on_tick_xform_list : 1;
|
||||||
bool fti_on_tick_property_list : 1;
|
bool fti_on_tick_property_list : 1;
|
||||||
bool fti_global_xform_interp_set : 1;
|
bool fti_global_xform_interp_set : 1;
|
||||||
|
bool fti_frame_xform_force_update : 1;
|
||||||
|
|
||||||
bool merging_allowed : 1;
|
bool merging_allowed : 1;
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ void SceneTreeFTI::_reset_flags(Node *p_node) {
|
|||||||
|
|
||||||
// In most cases the later NOTIFICATION_RESET_PHYSICS_INTERPOLATION
|
// In most cases the later NOTIFICATION_RESET_PHYSICS_INTERPOLATION
|
||||||
// will reset this, but this should help cover hidden nodes.
|
// will reset this, but this should help cover hidden nodes.
|
||||||
s->data.local_transform_prev = s->data.local_transform;
|
s->data.local_transform_prev = s->get_transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int n = 0; n < p_node->get_child_count(); n++) {
|
for (int n = 0; n < p_node->get_child_count(); n++) {
|
||||||
@ -101,6 +101,10 @@ void SceneTreeFTI::tick_update() {
|
|||||||
if (s->data.fti_on_frame_xform_list) {
|
if (s->data.fti_on_frame_xform_list) {
|
||||||
s->data.fti_on_frame_xform_list = false;
|
s->data.fti_on_frame_xform_list = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that the spatial gets at least ONE further
|
||||||
|
// update in the resting position in the next frame update.
|
||||||
|
s->data.fti_frame_xform_force_update = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +119,9 @@ void SceneTreeFTI::tick_update() {
|
|||||||
// Needs a reset so jittering will stop.
|
// Needs a reset so jittering will stop.
|
||||||
s->fti_pump_xform();
|
s->fti_pump_xform();
|
||||||
|
|
||||||
|
// Ensure the servers are up to date with the final resting value.
|
||||||
|
s->fti_update_servers_property();
|
||||||
|
|
||||||
// Remove from interpolation list.
|
// Remove from interpolation list.
|
||||||
if (s->data.fti_on_frame_property_list) {
|
if (s->data.fti_on_frame_property_list) {
|
||||||
s->data.fti_on_frame_property_list = false;
|
s->data.fti_on_frame_property_list = false;
|
||||||
@ -184,12 +191,15 @@ void SceneTreeFTI::_spatial_notify_set_property(Spatial &r_spatial) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeFTI::_spatial_notify_set_xform(Spatial &r_spatial) {
|
void SceneTreeFTI::_spatial_notify_set_xform(Spatial &r_spatial) {
|
||||||
|
DEV_CHECK_ONCE(data.enabled);
|
||||||
|
|
||||||
if (!r_spatial.is_physics_interpolated()) {
|
if (!r_spatial.is_physics_interpolated()) {
|
||||||
|
// Force an update of non-interpolated to servers
|
||||||
|
// on the next traversal.
|
||||||
|
r_spatial.data.fti_frame_xform_force_update = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEV_CHECK_ONCE(data.enabled);
|
|
||||||
|
|
||||||
if (!r_spatial.data.fti_on_tick_xform_list) {
|
if (!r_spatial.data.fti_on_tick_xform_list) {
|
||||||
r_spatial.data.fti_on_tick_xform_list = true;
|
r_spatial.data.fti_on_tick_xform_list = true;
|
||||||
|
|
||||||
@ -198,6 +208,14 @@ void SceneTreeFTI::_spatial_notify_set_xform(Spatial &r_spatial) {
|
|||||||
DEV_CHECK_ONCE(data.tick_xform_list[data.mirror].find(&r_spatial) == -1);
|
DEV_CHECK_ONCE(data.tick_xform_list[data.mirror].find(&r_spatial) == -1);
|
||||||
#endif
|
#endif
|
||||||
data.tick_xform_list[data.mirror].push_back(&r_spatial);
|
data.tick_xform_list[data.mirror].push_back(&r_spatial);
|
||||||
|
|
||||||
|
// The following flag could have been previously set
|
||||||
|
// (for removal from the tick list).
|
||||||
|
// We no longer need this guarantee,
|
||||||
|
// however there is probably no downside to leaving it set
|
||||||
|
// as it will be cleared on the next frame anyway.
|
||||||
|
// This line is left for reference.
|
||||||
|
// r_spatial.data.fti_frame_xform_force_update = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!r_spatial.data.fti_on_frame_xform_list) {
|
if (!r_spatial.data.fti_on_frame_xform_list) {
|
||||||
@ -259,6 +277,12 @@ void SceneTreeFTI::_update_dirty_spatials(Node *p_node, uint32_t p_current_frame
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We are going to be using data.global_transform, so
|
||||||
|
// we need to ensure data.global_transform is not dirty!
|
||||||
|
if (s->data.dirty & Spatial::DIRTY_GLOBAL) {
|
||||||
|
_ALLOW_DISCARD_ s->get_global_transform();
|
||||||
|
}
|
||||||
|
|
||||||
// Start the active interpolation chain from here onwards
|
// Start the active interpolation chain from here onwards
|
||||||
// as we recurse further into the SceneTree.
|
// as we recurse further into the SceneTree.
|
||||||
// Once we hit an active (interpolated) node, we have to fully
|
// Once we hit an active (interpolated) node, we have to fully
|
||||||
@ -267,7 +291,7 @@ void SceneTreeFTI::_update_dirty_spatials(Node *p_node, uint32_t p_current_frame
|
|||||||
if (!p_active) {
|
if (!p_active) {
|
||||||
if (data.frame_start) {
|
if (data.frame_start) {
|
||||||
// On the frame start, activate whenever we hit something that requests interpolation.
|
// On the frame start, activate whenever we hit something that requests interpolation.
|
||||||
if (s->data.fti_on_frame_xform_list) {
|
if (s->data.fti_on_frame_xform_list || s->data.fti_frame_xform_force_update) {
|
||||||
p_active = true;
|
p_active = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -303,9 +327,11 @@ void SceneTreeFTI::_update_dirty_spatials(Node *p_node, uint32_t p_current_frame
|
|||||||
// This will either use interpolation, or just use the current local if not interpolated.
|
// This will either use interpolation, or just use the current local if not interpolated.
|
||||||
Transform local_interp;
|
Transform local_interp;
|
||||||
if (s->is_physics_interpolated()) {
|
if (s->is_physics_interpolated()) {
|
||||||
TransformInterpolator::interpolate_transform(s->data.local_transform_prev, s->data.local_transform, local_interp, p_interpolation_fraction);
|
// Make sure to call `get_transform()` rather than using local_transform directly, because
|
||||||
|
// local_transform may be dirty and need updating from rotation / scale.
|
||||||
|
TransformInterpolator::interpolate_transform(s->data.local_transform_prev, s->get_transform(), local_interp, p_interpolation_fraction);
|
||||||
} else {
|
} else {
|
||||||
local_interp = s->data.local_transform;
|
local_interp = s->get_transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concatenate parent xform.
|
// Concatenate parent xform.
|
||||||
@ -329,6 +355,11 @@ void SceneTreeFTI::_update_dirty_spatials(Node *p_node, uint32_t p_current_frame
|
|||||||
// Upload to VisualServer the interpolated global xform.
|
// Upload to VisualServer the interpolated global xform.
|
||||||
s->fti_update_servers_xform();
|
s->fti_update_servers_xform();
|
||||||
|
|
||||||
|
// Only do this at most for one frame,
|
||||||
|
// it is used to catch objects being removed from the tick lists
|
||||||
|
// that have a deferred frame update.
|
||||||
|
s->data.fti_frame_xform_force_update = false;
|
||||||
|
|
||||||
} // if active.
|
} // if active.
|
||||||
|
|
||||||
// Remove the dirty interp flag from EVERYTHING as we go.
|
// Remove the dirty interp flag from EVERYTHING as we go.
|
||||||
|
|||||||
Reference in New Issue
Block a user