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,13 +502,98 @@ Transform3D Node3D::_get_global_transform_interpolated(real_t p_interpolation_fr
|
|||||||
return res;
|
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() {
|
Transform3D Node3D::get_global_transform_interpolated() {
|
||||||
#if 1
|
#if 1
|
||||||
// Pass through if physics interpolation is switched off.
|
// Pass through if physics interpolation is switched off.
|
||||||
// This is a convenience, as it allows you to easy turn off interpolation
|
// This is a convenience, as it allows you to easy turn off interpolation
|
||||||
// without changing any code.
|
// 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()) {
|
||||||
return data.global_transform_interpolated;
|
// 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();
|
return get_global_transform();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user