@@ -502,13 +502,98 @@ Transform3D Node3D::_get_global_transform_interpolated(real_t p_interpolation_fr
502502 return res;
503503}
504504
505+ // Visible nodes - get_global_transform_interpolated is cheap.
506+ // Invisible nodes - get_global_transform_interpolated is expensive, try to avoid.
505507Transform3D Node3D::get_global_transform_interpolated () {
506508#if 1
507509 // Pass through if physics interpolation is switched off.
508510 // This is a convenience, as it allows you to easy turn off interpolation
509511 // without changing any code.
510- if (data.fti_global_xform_interp_set && is_physics_interpolated_and_enabled () && !Engine::get_singleton ()->is_in_physics_frame () && is_visible_in_tree ()) {
511- return data.global_transform_interpolated ;
512+ if (is_inside_tree () && get_tree ()->is_physics_interpolation_enabled () && !Engine::get_singleton ()->is_in_physics_frame ()) {
513+ // Note that with SceneTreeFTI, we may want to calculate interpolated transform for a node
514+ // with physics interpolation set to OFF, if it has a parent that is ON.
515+
516+ // Cheap case.
517+ // We already pre-cache the visible_in_tree for VisualInstances, but NOT for Node3Ds, so we have to
518+ // deal with non-VIs the slow way.
519+ if (Object::cast_to<VisualInstance3D>(this ) && _is_vi_visible () && data.fti_global_xform_interp_set ) {
520+ return data.global_transform_interpolated ;
521+ }
522+
523+ // Find out if visible in tree.
524+ // If not visible in tree, find the FIRST ancestor that is visible in tree.
525+ const Node3D *visible_parent = nullptr ;
526+ const Node3D *s = this ;
527+ bool visible = true ;
528+ bool visible_in_tree = true ;
529+
530+ while (s) {
531+ if (!s->data .visible ) {
532+ visible_in_tree = false ;
533+ visible = false ;
534+ } else {
535+ if (!visible) {
536+ visible_parent = s;
537+ visible = true ;
538+ }
539+ }
540+ s = s->data .parent ;
541+ }
542+
543+ // Simplest case, we can return the interpolated xform calculated by SceneTreeFTI.
544+ if (visible_in_tree) {
545+ return data.fti_global_xform_interp_set ? data.global_transform_interpolated : get_global_transform ();
546+ } else if (visible_parent) {
547+ // INVISIBLE case. Not visible, but there is a visible ancestor somewhere in the chain.
548+ if (_get_scene_tree_depth () < 1 ) {
549+ // This should not happen unless there a problem has been introduced in the scene tree depth code.
550+ // Print a non-spammy error and return something reasonable.
551+ ERR_PRINT_ONCE (" depth is < 1." );
552+ return get_global_transform ();
553+ }
554+
555+ // The interpolated xform is not already calculated for invisible nodes, but we can calculate this
556+ // manually on demand if there is a visible parent.
557+ // First create the chain (backwards), from the node up to first visible parent.
558+ const Node3D **parents = (const Node3D **)alloca ((sizeof (const Node3D *) * _get_scene_tree_depth ()));
559+ int32_t num_parents = 0 ;
560+
561+ s = this ;
562+ while (s) {
563+ if (s == visible_parent) {
564+ // Finished.
565+ break ;
566+ }
567+
568+ parents[num_parents++] = s;
569+ s = s->data .parent ;
570+ }
571+
572+ // Now calculate the interpolated chain forwards.
573+ float interpolation_fraction = Engine::get_singleton ()->get_physics_interpolation_fraction ();
574+
575+ // Seed the xform with the visible parent.
576+ Transform3D xform = visible_parent->data .fti_global_xform_interp_set ? visible_parent->data .global_transform_interpolated : visible_parent->get_global_transform ();
577+ Transform3D local_interp;
578+
579+ // Backwards through the list is forwards through the chain through the tree.
580+ for (int32_t n = num_parents - 1 ; n >= 0 ; n--) {
581+ s = parents[n];
582+
583+ if (s->is_physics_interpolated ()) {
584+ // Make sure to call `get_transform()` rather than using local_transform directly, because
585+ // local_transform may be dirty and need updating from rotation / scale.
586+ TransformInterpolator::interpolate_transform_3d (s->data .local_transform_prev , s->get_transform (), local_interp, interpolation_fraction);
587+ } else {
588+ local_interp = s->get_transform ();
589+ }
590+ xform *= local_interp;
591+ }
592+
593+ // We could save this in case of multiple calls,
594+ // but probably not necessary.
595+ return xform;
596+ }
512597 }
513598
514599 return get_global_transform ();
0 commit comments