@@ -291,7 +291,12 @@ void SceneTreeFTI::_create_depth_lists() {
291
291
}
292
292
#endif
293
293
294
+ // Prevent being added to the dest_list twice when on
295
+ // the frame_xform_list AND the frame_xform_list_forced.
294
296
if ((l == 0 ) && s->data .fti_frame_xform_force_update ) {
297
+ #ifdef GODOT_SCENE_TREE_FTI_EXTRA_CHECKS
298
+ DEV_ASSERT (data.frame_xform_list_forced .find (s) != -1 );
299
+ #endif
295
300
continue ;
296
301
}
297
302
@@ -520,14 +525,14 @@ void SceneTreeFTI::_update_dirty_nodes(Node *p_node, uint32_t p_current_half_fra
520
525
521
526
if (p_active) {
522
527
#ifdef GODOT_SCENE_TREE_FTI_PRINT_TREE
523
- bool dirty = s->data . dirty & Node3D::DIRTY_GLOBAL_INTERPOLATED ;
528
+ bool dirty = s->_test_dirty_bits ( Node3D::DIRTY_GLOBAL_INTERPOLATED_TRANSFORM) ;
524
529
525
530
if (data.periodic_debug_log && !data.use_optimized_traversal_method && !data.frame_start ) {
526
531
String sz;
527
532
for (int n = 0 ; n < p_depth; n++) {
528
533
sz += " \t " ;
529
534
}
530
- print_line (sz + p_node->get_name () + (dirty ? " DIRTY" : " " ) + (s->get_transform () == Transform () ? " \t [IDENTITY]" : " " ));
535
+ print_line (sz + p_node->get_name () + (dirty ? " DIRTY" : " " ) + (s->get_transform () == Transform3D () ? " \t [IDENTITY]" : " " ));
531
536
}
532
537
#endif
533
538
@@ -575,11 +580,6 @@ void SceneTreeFTI::_update_dirty_nodes(Node *p_node, uint32_t p_current_half_fra
575
580
// Upload to RenderingServer the interpolated global xform.
576
581
s->fti_update_servers_xform ();
577
582
578
- // Only do this at most for one frame,
579
- // it is used to catch objects being removed from the tick lists
580
- // that have a deferred frame update.
581
- s->data .fti_frame_xform_force_update = false ;
582
-
583
583
// Ensure branches are only processed once on each traversal.
584
584
s->data .fti_processed = true ;
585
585
@@ -719,6 +719,17 @@ void SceneTreeFTI::frame_update(Node *p_root, bool p_frame_start) {
719
719
720
720
#endif // not GODOT_SCENE_TREE_FTI_VERIFY
721
721
722
+ // In theory we could clear the `force_update` flags from the nodes in the traversal.
723
+ // The problem is that hidden nodes are not recursed into, therefore the flags would
724
+ // never get cleared and could get out of sync with the forced list.
725
+ // So instead we are clearing them here manually.
726
+ // This is not ideal in terms of cache coherence so perhaps another method can be
727
+ // explored in future.
728
+ uint32_t forced_list_size = data.frame_xform_list_forced .size ();
729
+ for (uint32_t n = 0 ; n < forced_list_size; n++) {
730
+ Node3D *s = data.frame_xform_list_forced [n];
731
+ s->data .fti_frame_xform_force_update = false ;
732
+ }
722
733
data.frame_xform_list_forced .clear ();
723
734
724
735
if (!p_frame_start && data.periodic_debug_log ) {
0 commit comments