Browse Source

Merge pull request #45583 from lawnjelly/optimize_transform_propagate

Optimize transform propagation for hidden 3d objects
Rémi Verschelde 4 years ago
parent
commit
f05e068d6c
3 changed files with 54 additions and 10 deletions
  1. 7 6
      scene/3d/spatial.cpp
  2. 22 0
      scene/3d/spatial.h
  3. 25 4
      scene/3d/visual_instance.cpp

+ 7 - 6
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;

+ 22 - 0
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();
 

+ 25 - 4
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: {