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: