From 50efc7e8b32dc7600082cdaeee4e2cd4021f84da Mon Sep 17 00:00:00 2001 From: MelekTaus Moribundus Date: Fri, 3 Jul 2026 16:04:51 +0200 Subject: [PATCH] Fix: wheel over UI scrolls the list instead of zooming the camera The orbit rig read the wheel unfiltered for zoom, so scrolling a paint-mode scroll list also zoomed the camera. Gate the zoom behind a shared InputUtil.PointerOverUi() helper (EventSystem raycast); MeshPainter's private IsPointerOverUi() now delegates to the same helper (DRY). Co-Authored-By: Claude Opus 4.8 --- .../Components/Controller/ThirdPersonOrbitInput.cs | 12 +++++++----- Assets/Scripts/Components/MeshPainter/MeshPainter.cs | 7 +------ Assets/Scripts/Helper/InputUtil.cs | 10 ++++++++++ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Assets/Scripts/Components/Controller/ThirdPersonOrbitInput.cs b/Assets/Scripts/Components/Controller/ThirdPersonOrbitInput.cs index f089884..b85607c 100644 --- a/Assets/Scripts/Components/Controller/ThirdPersonOrbitInput.cs +++ b/Assets/Scripts/Components/Controller/ThirdPersonOrbitInput.cs @@ -238,11 +238,13 @@ public class ThirdPersonOrbitInput : MonoBehaviour float scale = CurrentScale(); - // Shift/Ctrl+wheel is reserved for the paint brush resize (MeshPainter) - but only in paint - // mode (PanEnabled), where the resize actually claims the wheel. Outside paint mode Shift is - // the sprint key, so the wheel must still zoom. - bool brushResizeClaimsWheel = PanEnabled && (InputUtil.ShiftHeld() || InputUtil.CtrlHeld()); - float scroll = brushResizeClaimsWheel ? 0f : InputUtil.ReadScroll(); + // The wheel belongs to the UI when the pointer is over an interactive element (e.g. a scroll + // list), so it scrolls the UI instead of zooming. Shift/Ctrl+wheel is likewise reserved for the + // paint brush resize (MeshPainter) - but only in paint mode (PanEnabled), where the resize + // actually claims the wheel; outside paint mode Shift is the sprint key, so the wheel must zoom. + bool wheelClaimed = InputUtil.PointerOverUi() + || (PanEnabled && (InputUtil.ShiftHeld() || InputUtil.CtrlHeld())); + float scroll = wheelClaimed ? 0f : InputUtil.ReadScroll(); if (!Mathf.Approximately(scroll, 0f)) { // One wheel notch = one zoom step (sign only, platform-independent). The step scales with diff --git a/Assets/Scripts/Components/MeshPainter/MeshPainter.cs b/Assets/Scripts/Components/MeshPainter/MeshPainter.cs index 18097e9..da23a34 100644 --- a/Assets/Scripts/Components/MeshPainter/MeshPainter.cs +++ b/Assets/Scripts/Components/MeshPainter/MeshPainter.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using UnityEngine; -using UnityEngine.EventSystems; #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif @@ -1123,11 +1122,7 @@ public partial class MeshPainter : MonoBehaviour } /// True if the pointer is currently over an interactive UI element (raycast target). - private static bool IsPointerOverUi() - { - var es = EventSystem.current; - return es && es.IsPointerOverGameObject(); - } + private static bool IsPointerOverUi() => InputUtil.PointerOverUi(); private void OnDestroy() { diff --git a/Assets/Scripts/Helper/InputUtil.cs b/Assets/Scripts/Helper/InputUtil.cs index e154b21..3a0cb9a 100644 --- a/Assets/Scripts/Helper/InputUtil.cs +++ b/Assets/Scripts/Helper/InputUtil.cs @@ -1,4 +1,5 @@ using UnityEngine; +using UnityEngine.EventSystems; #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif @@ -40,6 +41,15 @@ public static class InputUtil Cursor.visible = !locked; } + /// True while the pointer is over an interactive UI element (a raycast target), so the + /// wheel/click belongs to the UI (e.g. a scroll list) and must not also zoom the camera or paint + /// the mesh behind it. False when no EventSystem exists. + public static bool PointerOverUi() + { + var es = EventSystem.current; + return es && es.IsPointerOverGameObject(); + } + public static bool ShiftHeld() { #if ENABLE_INPUT_SYSTEM