Optimize transform propagation for hidden objects

When visual instances are hidden, there is no need to update their global transforms and send these to the visual server. This only needs to be done when the objects are reshown.
This commit is contained in:
lawnjelly 2021-01-30 15:17:58 +00:00
parent b1c7078551
commit cb8134f371
3 changed files with 54 additions and 10 deletions

View file

@ -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;

View file

@ -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();

View file

@ -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: {