From 4c730583b3fa03ef1edebd2b777cf705c964e49d Mon Sep 17 00:00:00 2001 From: CuongNV <> Date: Mon, 18 May 2026 14:25:08 +0700 Subject: [PATCH] fix logic set pos camera in intentory --- .../UI/Inventory/InventoryCharacterPreview.cs | 190 +++++++++++++++++- Assets/Prefabs/UI/InventoryUI.prefab | 60 +++--- 2 files changed, 223 insertions(+), 27 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs index a90461ec17..a16ce4351a 100644 --- a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs +++ b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs @@ -5,6 +5,12 @@ using UnityEngine.UI; namespace BrewMonster.Scripts.UI.Inventory { + public enum PreviewDistanceScaleMode + { + AspectRatio, + ViewportHeight + } + /// /// Clones the current host-player visual model into a dedicated preview rig for the inventory UI. /// @@ -45,6 +51,17 @@ namespace BrewMonster.Scripts.UI.Inventory [SerializeField] private float minAutoCameraDistance = 1.25f; [SerializeField] private float maxAutoCameraDistance = 8f; + [Header("Device Framing")] + [Tooltip("Design-time screen width (1920x1080 baseline); previewCameraDistance/offset tuned for this.")] + [SerializeField] private float referenceScreenWidth = 1920f; + [Tooltip("Design-time screen height (1920x1080 baseline); previewCameraDistance/offset tuned for this.")] + [SerializeField] private float referenceScreenHeight = 1080f; + [Tooltip("Use previewFrame pixel size when available; otherwise Screen.width/height.")] + [SerializeField] private bool useRawImageViewport = true; + [SerializeField] private PreviewDistanceScaleMode distanceScaleMode = PreviewDistanceScaleMode.AspectRatio; + [Tooltip("Scale previewCameraOffset.y by viewport height vs 1080p reference (1.0 at 1920x1080).")] + [SerializeField] private bool scaleCameraOffsetYByViewport = true; + private bool _cameraStateCached; private Vector3 _cachedCameraPosition; private Quaternion _cachedCameraRotation; @@ -396,7 +413,8 @@ namespace BrewMonster.Scripts.UI.Inventory return; } - Vector3 focusPoint = modelRoot.TransformPoint(cameraFocusOffset) + previewCameraOffset; + Vector3 effectiveOffset = ComputeEffectiveCameraOffset(); + Vector3 focusPoint = modelRoot.TransformPoint(cameraFocusOffset) + effectiveOffset; Vector3 viewDirection = modelRoot.forward; viewDirection.y = 0f; @@ -407,10 +425,178 @@ namespace BrewMonster.Scripts.UI.Inventory viewDirection.Normalize(); - _previewCamera.transform.position = focusPoint + viewDirection * previewCameraDistance; + float effectiveDistance = ComputeEffectiveCameraDistance(modelRoot, focusPoint, viewDirection); + _previewCamera.transform.position = focusPoint + viewDirection * effectiveDistance; _previewCamera.transform.LookAt(focusPoint); } + private bool TryGetViewportSize(out float width, out float height) + { + if (useRawImageViewport && previewFrame != null) + { + RectTransform rt = previewFrame.rectTransform; + Canvas canvas = previewFrame.canvas; + float scale = canvas != null ? canvas.scaleFactor : 1f; + width = rt.rect.width * scale; + height = rt.rect.height * scale; + + if (width > 1f && height > 1f) + { + return true; + } + } + + width = Screen.width; + height = Screen.height; + return width > 0f && height > 0f; + } + + private float ComputeAspectScaledDistance() + { + float distance = previewCameraDistance * ComputeViewportFramingScale(); + return Mathf.Clamp(distance, minAutoCameraDistance, maxAutoCameraDistance); + } + + private float ComputeViewportFramingScale() + { + if (!TryGetViewportSize(out float viewportWidth, out float viewportHeight)) + { + return 1f; + } + + float refWidth = Mathf.Max(1f, referenceScreenWidth); + float refHeight = Mathf.Max(1f, referenceScreenHeight); + + switch (distanceScaleMode) + { + case PreviewDistanceScaleMode.ViewportHeight: + return viewportHeight / refHeight; + default: + float refAspect = refWidth / refHeight; + float viewAspect = viewportWidth / viewportHeight; + return viewAspect / refAspect; + } + } + + private float ComputeViewportHeightScale() + { + if (!TryGetViewportSize(out _, out float viewportHeight)) + { + return 1f; + } + + float refHeight = Mathf.Max(1f, referenceScreenHeight); + return viewportHeight / refHeight; + } + + private Vector3 ComputeEffectiveCameraOffset() + { + if (!scaleCameraOffsetYByViewport) + { + return previewCameraOffset; + } + + // Tuned at 1920x1080: scale is 1.0 so previewCameraOffset.y is unchanged on reference resolution. + float offsetYScale = ComputeViewportHeightScale(); + return new Vector3( + previewCameraOffset.x, + previewCameraOffset.y * offsetYScale, + previewCameraOffset.z); + } + + private float ComputeBoundsFitDistance(Transform modelRoot, Vector3 focusPoint, Vector3 viewDirection) + { + if (modelRoot == null) + { + return previewCameraDistance; + } + + var renderers = modelRoot.GetComponentsInChildren(true); + if (renderers == null || renderers.Length == 0) + { + return previewCameraDistance; + } + + Bounds bounds = renderers[0].bounds; + for (int i = 1; i < renderers.Length; i++) + { + if (renderers[i] != null) + { + bounds.Encapsulate(renderers[i].bounds); + } + } + + if (bounds.size.sqrMagnitude < 0.0001f) + { + return previewCameraDistance; + } + + if (!TryGetViewportSize(out float viewportWidth, out float viewportHeight)) + { + return previewCameraDistance; + } + + Vector3 cameraForward = -viewDirection; + Vector3 cameraRight = Vector3.Cross(cameraForward, Vector3.up); + if (cameraRight.sqrMagnitude < 0.0001f) + { + cameraRight = Vector3.Cross(cameraForward, Vector3.forward); + } + cameraRight.Normalize(); + Vector3 cameraUp = Vector3.Cross(cameraRight, cameraForward).normalized; + + Vector3 boundsMin = bounds.min; + Vector3 boundsMax = bounds.max; + float maxHorizontal = 0f; + float maxVertical = 0f; + + for (int x = 0; x <= 1; x++) + { + for (int y = 0; y <= 1; y++) + { + for (int z = 0; z <= 1; z++) + { + Vector3 corner = new Vector3( + x == 0 ? boundsMin.x : boundsMax.x, + y == 0 ? boundsMin.y : boundsMax.y, + z == 0 ? boundsMin.z : boundsMax.z); + Vector3 offset = corner - focusPoint; + maxHorizontal = Mathf.Max(maxHorizontal, Mathf.Abs(Vector3.Dot(offset, cameraRight))); + maxVertical = Mathf.Max(maxVertical, Mathf.Abs(Vector3.Dot(offset, cameraUp))); + } + } + } + + float viewAspect = viewportWidth / viewportHeight; + float verticalFovRad = previewFieldOfView * Mathf.Deg2Rad; + float halfVerticalTan = Mathf.Tan(verticalFovRad * 0.5f); + if (halfVerticalTan < 0.0001f) + { + return previewCameraDistance; + } + + float halfHorizontalTan = halfVerticalTan * viewAspect; + float distanceForHeight = maxVertical / halfVerticalTan; + float distanceForWidth = maxHorizontal / Mathf.Max(halfHorizontalTan, 0.0001f); + float boundsDistance = Mathf.Max(distanceForHeight, distanceForWidth); + + return boundsDistance * autoFramePadding; + } + + private float ComputeEffectiveCameraDistance(Transform modelRoot, Vector3 focusPoint, Vector3 viewDirection) + { + float aspectScaledDistance = ComputeAspectScaledDistance(); + float effectiveDistance = aspectScaledDistance; + + if (autoFrameByBounds) + { + float boundsDistance = ComputeBoundsFitDistance(modelRoot, focusPoint, viewDirection); + effectiveDistance = Mathf.Max(aspectScaledDistance, boundsDistance); + } + + return Mathf.Clamp(effectiveDistance, minAutoCameraDistance, maxAutoCameraDistance); + } + //private void StripRuntimeScripts(GameObject cloneRoot) //{ // if (cloneRoot == null) diff --git a/Assets/Prefabs/UI/InventoryUI.prefab b/Assets/Prefabs/UI/InventoryUI.prefab index d2316b9ab4..0c16515ba0 100644 --- a/Assets/Prefabs/UI/InventoryUI.prefab +++ b/Assets/Prefabs/UI/InventoryUI.prefab @@ -500,10 +500,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 588.35, y: -59.5} - m_SizeDelta: {x: 85, y: 85} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &9112205963990496432 CanvasRenderer: @@ -907,10 +907,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 479.18, y: -59.5} - m_SizeDelta: {x: 85, y: 85} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &3997873020355048166 CanvasRenderer: @@ -1238,10 +1238,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 370.01, y: -59.5} - m_SizeDelta: {x: 85, y: 85} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &4479228720555407959 CanvasRenderer: @@ -4929,10 +4929,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 42.5, y: -59.5} - m_SizeDelta: {x: 85, y: 85} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &7052320096474271168 CanvasRenderer: @@ -11103,9 +11103,18 @@ MonoBehaviour: autoFocusCamera: 1 cameraFocusOffset: {x: 0, y: 0, z: 0} previewCameraDistance: 3.3 - previewCameraOffset: {x: 0.06, y: 1.07, z: 0} + previewCameraOffset: {x: 0.06, y: 2.04, z: 0} overrideFieldOfView: 1 previewFieldOfView: 44 + autoFrameByBounds: 1 + autoFramePadding: 1.15 + minAutoCameraDistance: 1.25 + maxAutoCameraDistance: 8 + referenceScreenWidth: 1920 + referenceScreenHeight: 1080 + useRawImageViewport: 1 + distanceScaleMode: 0 + scaleCameraOffsetYByViewport: 1 --- !u!1 &5473020210238587200 GameObject: m_ObjectHideFlags: 0 @@ -12366,6 +12375,7 @@ MonoBehaviour: m_EditorClassIdentifier: skillNameText: {fileID: 0} imageProgress: {fileID: 0} + btnCancel: {fileID: 0} inventoryPackButtons: - {fileID: 8631960679953241981} - {fileID: 7087549554151292240} @@ -14070,10 +14080,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 151.67, y: -59.5} - m_SizeDelta: {x: 85, y: 85} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &4452551064742165538 CanvasRenderer: @@ -19517,10 +19527,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 260.84, y: -59.5} - m_SizeDelta: {x: 85, y: 85} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &5155025384962724770 CanvasRenderer: