From 0d4e27317c1a220646c8433242d7ab63f46640b7 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 2 Jun 2026 14:30:42 +0100 Subject: [PATCH] Phantom Camera: Reduce unnecessary processing Apply the changes I have submitted upstream in https://github.com/ramokz/phantom-camera/pull/657 to avoid processing every frame in the editor, even when the open scene does not use PhantomCamera. As detailed in that PR and in https://github.com/ramokz/phantom-camera/issues/649, I haven't figured out how to avoid the PhantomCameraHost node processing every frame even when the viewfinder is closed. And as also detailed there: any inactive PhantomCamera2D still _process()es every frame, and the PlayerHook has an inactive PhantomCamera2D, so... However in most scenes containing the player we have at least one moving tree or water ripple animation, which causes the scene to render at 60fps anyway. So, oh well! --- .../2D/sub_scenes/playable_character_2d.tscn | 2 + .../scripts/panel/viewfinder/viewfinder.gd | 20 +++++++-- .../phantom_camera/phantom_camera_2d.gd | 22 ++++++++-- .../phantom_camera/phantom_camera_3d.gd | 42 +++++++++---------- .../phantom_camera_host.gd | 23 +++++++--- 5 files changed, 75 insertions(+), 34 deletions(-) diff --git a/addons/phantom_camera/examples/example_scenes/2D/sub_scenes/playable_character_2d.tscn b/addons/phantom_camera/examples/example_scenes/2D/sub_scenes/playable_character_2d.tscn index 9115dfd12..5e2f1c595 100644 --- a/addons/phantom_camera/examples/example_scenes/2D/sub_scenes/playable_character_2d.tscn +++ b/addons/phantom_camera/examples/example_scenes/2D/sub_scenes/playable_character_2d.tscn @@ -106,6 +106,7 @@ script = ExtResource("4_rloon") zoom = Vector2(2, 2) frame_preview = false tween_resource = ExtResource("5_4iyk1") +inactive_update_mode = 1 follow_damping_value = Vector2(0, 0) draw_limits = true @@ -116,5 +117,6 @@ script = ExtResource("4_rloon") zoom = Vector2(2.5, 2.5) frame_preview = false tween_resource = ExtResource("6_2h6fv") +inactive_update_mode = 1 follow_damping_value = Vector2(0, 0) draw_limits = true diff --git a/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd b/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd index 02f39f2de..c73045fd9 100644 --- a/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd +++ b/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd @@ -28,6 +28,7 @@ const _overlay_color_alpha: float = 0.3 @onready var camera_viewport_panel: Panel = aspect_ratio_container.get_child(0) @onready var _viewfinder: Control = %Viewfinder @onready var _dead_zone_h_box_container: Control = %DeadZoneHBoxContainer +@onready var sub_viewport_container: SubViewportContainer = %SubViewportContainer @onready var sub_viewport: SubViewport = %SubViewport @onready var _empty_state_control: Control = %EmptyStateControl @@ -91,7 +92,7 @@ func _ready() -> void: _root_node = get_tree().current_scene if _root_node is Node2D || _root_node is Node3D: - %SubViewportContainer.visible = false + sub_viewport_container.visible = false if _root_node is Node2D: _is_2d = true else: @@ -109,8 +110,8 @@ func _ready() -> void: # PCam Host List _pcam_host_list.visible = false - _assign_manager() _visibility_check() + _update_processing() func _pcam_host_switch(new_pcam_host: PhantomCameraHost) -> void: @@ -131,12 +132,21 @@ func _exit_tree() -> void: if _priority_override_button.pressed.is_connected(_select_override_pcam): _priority_override_button.pressed.disconnect(_select_override_pcam) +func _update_processing() -> void: + if viewfinder_visible and _has_pcam_host: + set_process(not _physics_based) + set_physics_process(_physics_based) + sub_viewport_container.process_mode = ProcessMode.PROCESS_MODE_INHERIT + else: + set_process(false) + set_physics_process(false) + sub_viewport_container.process_mode = ProcessMode.PROCESS_MODE_DISABLED + + func _process(_delta: float) -> void: - if not _has_pcam_host or _physics_based: return _process_viewfinder() func _physics_process(_delta: float) -> void: - if not _has_pcam_host or not _physics_based: return _process_viewfinder() func _process_viewfinder() -> void: @@ -598,6 +608,7 @@ func _set_pcam_host(_pcam_host: PhantomCameraHost) -> void: _has_pcam_host = false _physics_based = false target_point.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_INHERIT + _update_processing() #endregion @@ -610,6 +621,7 @@ func set_visibility(visible: bool) -> void: _visibility_check() else: viewfinder_visible = false + _update_processing() func update_dead_zone() -> void: diff --git a/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd b/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd index e62eb4c73..243dd58c7 100644 --- a/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd +++ b/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd @@ -514,7 +514,8 @@ var _should_rotate_with_target: bool = false var _is_active: bool = false var _should_follow: bool = false -var _follow_target_physics_based: bool = false +var _follow_target_physics_based: bool = false: + set = _set_follow_target_physics_based var _physics_interpolation_enabled: bool = false # NOTE - Enable for Godot 4.3 and when PhysicsInterpolationMode bug is resolved var _follow_target_physics_class: FollowTargetPhysicsClass = FollowTargetPhysicsClass.OTHER @@ -746,14 +747,28 @@ func _ready() -> void: if not Engine.is_editor_hint(): _preview_noise = true + _update_processing() + + +func _set_follow_target_physics_based(value: bool) -> void: + _follow_target_physics_based = value + _update_processing() + + +func _update_processing() -> void: + if _is_active or inactive_update_mode == InactiveUpdateMode.NEVER: + set_process(false) + set_physics_process(false) + else: + set_process(not _follow_target_physics_based) + set_physics_process(_follow_target_physics_based) + func _process(delta: float) -> void: - if _follow_target_physics_based or _is_active: return process_logic(delta) func _physics_process(delta: float) -> void: - if not _follow_target_physics_based or _is_active: return process_logic(delta) @@ -1424,6 +1439,7 @@ func get_tween_ease() -> int: func set_is_active(node, value) -> void: if node is PhantomCameraHost: _is_active = value + _update_processing() queue_redraw() else: printerr("PCams can only be set from the PhantomCameraHost") diff --git a/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd b/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd index 4b9caef9e..6a3892c22 100644 --- a/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd +++ b/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd @@ -1292,27 +1292,27 @@ func _interpolate_rotation(delta: float) -> void: func _smooth_damp(target_axis: float, self_axis: float, index: int, current_velocity: float, set_velocity: Callable, damping_time: float, delta: float) -> float: - damping_time = maxf(0.0001, damping_time) - var omega: float = 2 / damping_time - var x: float = omega * delta - var exponential: float = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x) - var diff: float = self_axis - target_axis - var _target_axis: float = target_axis - - var max_change: float = INF * damping_time - diff = clampf(diff, -max_change, max_change) - target_axis = self_axis - diff - - var temp: float = (current_velocity + omega * diff) * delta - set_velocity.call(index, (current_velocity - omega * temp) * exponential) - var output: float = target_axis + (diff + temp) * exponential - - ## To prevent overshooting - if (_target_axis - self_axis > 0.0) == (output > _target_axis): - output = _target_axis - set_velocity.call(index, (output - _target_axis) / delta) - - return output + damping_time = maxf(0.0001, damping_time) + var omega: float = 2 / damping_time + var x: float = omega * delta + var exponential: float = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x) + var diff: float = self_axis - target_axis + var _target_axis: float = target_axis + + var max_change: float = INF * damping_time + diff = clampf(diff, -max_change, max_change) + target_axis = self_axis - diff + + var temp: float = (current_velocity + omega * diff) * delta + set_velocity.call(index, (current_velocity - omega * temp) * exponential) + var output: float = target_axis + (diff + temp) * exponential + + ## To prevent overshooting + if (_target_axis - self_axis > 0.0) == (output > _target_axis): + output = _target_axis + set_velocity.call(index, (output - _target_axis) / delta) + + return output func _get_raw_unprojected_position() -> Vector2: diff --git a/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd b/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd index ee3d25c1d..cd9327f3b 100644 --- a/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd +++ b/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd @@ -71,9 +71,15 @@ enum InterpolationMode { var _active_pcam_2d: PhantomCamera2D = null var _active_pcam_3d: Node = null ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. var _active_pcam_priority: int = -1 -var _active_pcam_missing: bool = true +var _active_pcam_missing: bool = true: + set(value): + _active_pcam_missing = value + _update_processing() var _active_pcam_has_damping: bool = false -var _follow_target_physics_based: bool = false +var _follow_target_physics_based: bool = false: + set(value): + _follow_target_physics_based = value + _update_processing() var _prev_active_pcam_2d_transform: Transform2D = Transform2D() var _prev_active_pcam_3d_transform: Transform3D = Transform3D() @@ -846,15 +852,20 @@ func _check_pcam_physics() -> void: #else: #_active_pcam_missing = true +func _update_processing() -> void: + if _active_pcam_missing: + set_process(false) + set_physics_process(false) + else: + set_process(not _follow_target_physics_based) + set_physics_process(_follow_target_physics_based) -func _process(delta: float) -> void: - if _active_pcam_missing: return - if not _follow_target_physics_based: _tween_follow_checker(delta) +func _process(delta: float) -> void: + _tween_follow_checker(delta) func _physics_process(delta: float) -> void: - if _active_pcam_missing or not _follow_target_physics_based: return _tween_follow_checker(delta)