Merge pull request #107308 from lawnjelly/scenetreefti_get_interp_hidden4
FTI - `global_transform_interpolated()` on demand for invisible nodes
This commit is contained in:
commit
53da681e89
@ -502,15 +502,100 @@ Transform3D Node3D::_get_global_transform_interpolated(real_t p_interpolation_fr
|
||||
return res;
|
||||
}
|
||||
|
||||
// Visible nodes - get_global_transform_interpolated is cheap.
|
||||
// Invisible nodes - get_global_transform_interpolated is expensive, try to avoid.
|
||||
Transform3D Node3D::get_global_transform_interpolated() {
|
||||
#if 1
|
||||
// Pass through if physics interpolation is switched off.
|
||||
// This is a convenience, as it allows you to easy turn off interpolation
|
||||
// without changing any code.
|
||||
if (data.fti_global_xform_interp_set && is_physics_interpolated_and_enabled() && !Engine::get_singleton()->is_in_physics_frame() && is_visible_in_tree()) {
|
||||
if (is_inside_tree() && get_tree()->is_physics_interpolation_enabled() && !Engine::get_singleton()->is_in_physics_frame()) {
|
||||
// Note that with SceneTreeFTI, we may want to calculate interpolated transform for a node
|
||||
// with physics interpolation set to OFF, if it has a parent that is ON.
|
||||
|
||||
// Cheap case.
|
||||
// We already pre-cache the visible_in_tree for VisualInstances, but NOT for Node3Ds, so we have to
|
||||
// deal with non-VIs the slow way.
|
||||
if (Object::cast_to<VisualInstance3D>(this) && _is_vi_visible() && data.fti_global_xform_interp_set) {
|
||||
return data.global_transform_interpolated;
|
||||
}
|
||||
|
||||
// Find out if visible in tree.
|
||||
// If not visible in tree, find the FIRST ancestor that is visible in tree.
|
||||
const Node3D *visible_parent = nullptr;
|
||||
const Node3D *s = this;
|
||||
bool visible = true;
|
||||
bool visible_in_tree = true;
|
||||
|
||||
while (s) {
|
||||
if (!s->data.visible) {
|
||||
visible_in_tree = false;
|
||||
visible = false;
|
||||
} else {
|
||||
if (!visible) {
|
||||
visible_parent = s;
|
||||
visible = true;
|
||||
}
|
||||
}
|
||||
s = s->data.parent;
|
||||
}
|
||||
|
||||
// Simplest case, we can return the interpolated xform calculated by SceneTreeFTI.
|
||||
if (visible_in_tree) {
|
||||
return data.fti_global_xform_interp_set ? data.global_transform_interpolated : get_global_transform();
|
||||
} else if (visible_parent) {
|
||||
// INVISIBLE case. Not visible, but there is a visible ancestor somewhere in the chain.
|
||||
if (_get_scene_tree_depth() < 1) {
|
||||
// This should not happen unless there a problem has been introduced in the scene tree depth code.
|
||||
// Print a non-spammy error and return something reasonable.
|
||||
ERR_PRINT_ONCE("depth is < 1.");
|
||||
return get_global_transform();
|
||||
}
|
||||
|
||||
// The interpolated xform is not already calculated for invisible nodes, but we can calculate this
|
||||
// manually on demand if there is a visible parent.
|
||||
// First create the chain (backwards), from the node up to first visible parent.
|
||||
const Node3D **parents = (const Node3D **)alloca((sizeof(const Node3D *) * _get_scene_tree_depth()));
|
||||
int32_t num_parents = 0;
|
||||
|
||||
s = this;
|
||||
while (s) {
|
||||
if (s == visible_parent) {
|
||||
// Finished.
|
||||
break;
|
||||
}
|
||||
|
||||
parents[num_parents++] = s;
|
||||
s = s->data.parent;
|
||||
}
|
||||
|
||||
// Now calculate the interpolated chain forwards.
|
||||
float interpolation_fraction = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
|
||||
// Seed the xform with the visible parent.
|
||||
Transform3D xform = visible_parent->data.fti_global_xform_interp_set ? visible_parent->data.global_transform_interpolated : visible_parent->get_global_transform();
|
||||
Transform3D local_interp;
|
||||
|
||||
// Backwards through the list is forwards through the chain through the tree.
|
||||
for (int32_t n = num_parents - 1; n >= 0; n--) {
|
||||
s = parents[n];
|
||||
|
||||
if (s->is_physics_interpolated()) {
|
||||
// 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_3d(s->data.local_transform_prev, s->get_transform(), local_interp, interpolation_fraction);
|
||||
} else {
|
||||
local_interp = s->get_transform();
|
||||
}
|
||||
xform *= local_interp;
|
||||
}
|
||||
|
||||
// We could save this in case of multiple calls,
|
||||
// but probably not necessary.
|
||||
return xform;
|
||||
}
|
||||
}
|
||||
|
||||
return get_global_transform();
|
||||
#else
|
||||
// OLD METHOD - deprecated since moving to SceneTreeFTI,
|
||||
|
Loading…
x
Reference in New Issue
Block a user