diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index dd417c4ebf1..5d09bb8e4cb 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -246,10 +246,7 @@ void Spatial::set_transform(const Transform &p_transform) { void Spatial::set_global_transform(const Transform &p_transform) { - Transform xform = - (data.parent && !data.toplevel_active) ? - data.parent->get_global_transform().affine_inverse() * p_transform : - p_transform; + Transform xform = (data.parent && !data.toplevel_active) ? data.parent->get_global_transform().affine_inverse() * p_transform : p_transform; set_transform(xform); } @@ -541,8 +538,9 @@ void Spatial::show() { data.visible = true; - if (!is_inside_tree()) + if (!is_inside_tree()) { return; + } _propagate_visibility_changed(); } @@ -554,8 +552,9 @@ void Spatial::hide() { data.visible = false; - if (!is_inside_tree()) + if (!is_inside_tree()) { return; + } _propagate_visibility_changed(); } @@ -834,6 +833,8 @@ Spatial::Spatial() : data.visible = true; data.disable_scale = false; + data.spatial_flags = SPATIAL_FLAG_VI_VISIBLE; + #ifdef TOOLS_ENABLED data.gizmo_disabled = false; data.gizmo_dirty = false; diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 889e97309b8..795d171f9c4 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -54,6 +54,15 @@ class Spatial : public Node { GDCLASS(Spatial, Node); OBJ_CATEGORY("3D"); +public: + enum SpatialFlags { + // this is cached, and only currently kept up to date in visual instances + // this is set if a visual instance is + // (a) in the tree AND (b) visible via is_visible_in_tree() call + SPATIAL_FLAG_VI_VISIBLE = 1 << 0, + }; + +private: enum TransformDirty { DIRTY_NONE = 0, DIRTY_VECTORS = 1, @@ -65,6 +74,9 @@ class Spatial : public Node { struct Data { + // defined in Spatial::SpatialFlags + uint32_t spatial_flags; + mutable Transform global_transform; mutable Transform local_transform; mutable Vector3 rotation; @@ -109,6 +121,16 @@ protected: _FORCE_INLINE_ void _update_local_transform() const; + uint32_t _get_spatial_flags() const { return data.spatial_flags; } + void _replace_spatial_flags(uint32_t p_flags) { data.spatial_flags = p_flags; } + void _set_spatial_flag(uint32_t p_flag, bool p_set) { + if (p_set) { + data.spatial_flags |= p_flag; + } else { + data.spatial_flags &= ~p_flag; + } + } + void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 7bea31af214..d5eef744a29 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -41,11 +41,26 @@ AABB VisualInstance::get_transformed_aabb() const { void VisualInstance::_update_visibility() { - if (!is_inside_tree()) + if (!is_inside_tree()) { return; + } + + bool visible = is_visible_in_tree(); + + // keep a quick flag available in each node. + // no need to call is_visible_in_tree all over the place, + // providing it is propagated with a notification. + bool already_visible = (_get_spatial_flags() & SPATIAL_FLAG_VI_VISIBLE) != 0; + _set_spatial_flag(SPATIAL_FLAG_VI_VISIBLE, visible); + + // if making visible, make sure the visual server is up to date with the transform + if (visible && (!already_visible)) { + Transform gt = get_global_transform(); + VisualServer::get_singleton()->instance_set_transform(instance, gt); + } _change_notify("visible"); - VS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree()); + VS::get_singleton()->instance_set_visible(get_instance(), visible); } void VisualInstance::_notification(int p_what) { @@ -67,8 +82,10 @@ void VisualInstance::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - Transform gt = get_global_transform(); - VisualServer::get_singleton()->instance_set_transform(instance, gt); + if (_get_spatial_flags() & SPATIAL_FLAG_VI_VISIBLE) { + Transform gt = get_global_transform(); + VisualServer::get_singleton()->instance_set_transform(instance, gt); + } } break; case NOTIFICATION_EXIT_WORLD: { @@ -76,6 +93,10 @@ void VisualInstance::_notification(int p_what) { VisualServer::get_singleton()->instance_attach_skeleton(instance, RID()); //VS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() ); + // the vi visible flag is always set to invisible when outside the tree, + // so it can detect re-entering the tree and becoming visible, and send + // the transform to the visual server + _set_spatial_flag(SPATIAL_FLAG_VI_VISIBLE, false); } break; case NOTIFICATION_VISIBILITY_CHANGED: {