diff --git a/Assets/PerfectWorld/Scene/Bootstrap.unity b/Assets/PerfectWorld/Scene/Bootstrap.unity index 450da71ea2..64ded4daf4 100644 --- a/Assets/PerfectWorld/Scene/Bootstrap.unity +++ b/Assets/PerfectWorld/Scene/Bootstrap.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:833a4e6a7e0e815ce2561d06a74cc92483952cd3b3812e09fc3c5b15d0029695 -size 303238 +oid sha256:d67ebb03315697fc106ae8d9795e0d693a19af2a8d69ccb3f3dd652e26c95989 +size 308246 diff --git a/Assets/PerfectWorld/Scene/LoginScene.unity b/Assets/PerfectWorld/Scene/LoginScene.unity index ce0e50f81b..906837005a 100644 --- a/Assets/PerfectWorld/Scene/LoginScene.unity +++ b/Assets/PerfectWorld/Scene/LoginScene.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce4ce7c6a9576c56a5fb0b213f19e1253afc78d679474cb203612a1e50e8093d -size 111451 +oid sha256:1a1058735fae3c5bdd13717ff067673ea1c9ddf07983b2e5a84abe2dd35905c8 +size 106802 diff --git a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs index d8e7d85e57..dbff7fb706 100644 --- a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs +++ b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs @@ -6,7 +6,7 @@ using UnityEngine; namespace BrewMonster.Scripts { - public class PlayerModelPreview : MonoBehaviour + public class PlayerModelPreview : MonoSingleton { [SerializeField] private Transform modelRoot; diff --git a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs index bc05107be6..b83ef8114c 100644 --- a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs +++ b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs @@ -31,12 +31,22 @@ namespace BrewMonster.Scripts.UI.Inventory [SerializeField] private bool inheritPreviewLayer = true; [Header("Camera Output")] - [SerializeField] private Camera previewCamera; [SerializeField] private RawImage previewFrame; [SerializeField] private RenderTexture previewRenderTexture; [SerializeField] private bool autoFocusCamera = true; [SerializeField] private Vector3 cameraFocusOffset = new Vector3(0f, 1.5f, 0f); + [Header("Camera Framing")] + [SerializeField] private float previewCameraDistance = 1.4f; + [SerializeField] private Vector3 previewCameraOffset = new Vector3(0f, 0.5f, 0f); + [SerializeField] private bool overrideFieldOfView = true; + [SerializeField][Range(10f, 60f)] private float previewFieldOfView = 38f; + + private bool _cameraStateCached; + private Vector3 _cachedCameraPosition; + private Quaternion _cachedCameraRotation; + private float _cachedCameraFov; + [Header("Behaviour")] [Tooltip("Disable PlayerVisual/Animancer components on the clone so it stays in a frozen idle pose.")] [SerializeField] private bool freezeAnimation = true; @@ -45,30 +55,40 @@ namespace BrewMonster.Scripts.UI.Inventory private bool _refreshQueued; private int _lastOriginModelChildCount; private Transform _lastOriginModelRoot; + private Camera _previewCamera; + private PlayerModelPreview _playerModelPreview; + private RenderTexture _cachedTargetTexture; private void Awake() { + if (previewRoot == null) { previewRoot = transform; } + TryBindPreviewSystem(); TryBindHostPlayer(); EnsureCameraBindings(); } private void OnEnable() { + TryBindPreviewSystem(); + EnsureCameraBindings(); QueueRefresh(); } private void OnDisable() { + RestoreCameraTargetTexture(); + RestoreSharedCameraState(); DestroyPreviewInstance(); } private void LateUpdate() { + TryBindPreviewSystem(); TryBindHostPlayer(); // Check if origin model structure has changed (equipment models are child objects) @@ -119,6 +139,23 @@ namespace BrewMonster.Scripts.UI.Inventory _refreshQueued = true; } + private void TryBindPreviewSystem() + { + if (_playerModelPreview == null) + { + _playerModelPreview = PlayerModelPreview.Instance; + } + + if (_playerModelPreview == null) + { + return; + } + + if (_previewCamera == null) + { + _previewCamera = _playerModelPreview.GetComponent(); + } + } private void TryBindHostPlayer() { @@ -136,14 +173,40 @@ namespace BrewMonster.Scripts.UI.Inventory private void EnsureCameraBindings() { - if (previewCamera != null && previewRenderTexture != null) + if (_previewCamera == null) { - previewCamera.targetTexture = previewRenderTexture; + TryBindPreviewSystem(); } - if (previewFrame != null && previewCamera != null) + if (_previewCamera == null || previewFrame == null) { - previewFrame.texture = previewCamera.targetTexture; + return; + } + + if (_cachedTargetTexture == null) + { + _cachedTargetTexture = _previewCamera.targetTexture; + } + + if (previewRenderTexture != null) + { + _previewCamera.targetTexture = previewRenderTexture; + } + + if(previewFrame != null) + previewFrame.texture = _previewCamera.targetTexture; + } + + private void RestoreCameraTargetTexture() + { + if (_previewCamera == null) + { + return; + } + + if (_cachedTargetTexture != null) + { + _previewCamera.targetTexture = _cachedTargetTexture; } } @@ -189,6 +252,7 @@ namespace BrewMonster.Scripts.UI.Inventory } EnsureCameraFocus(instanceTransform); + EnsureCameraBindings(); } private Transform ResolveSourceModelRoot() @@ -262,13 +326,36 @@ namespace BrewMonster.Scripts.UI.Inventory private void EnsureCameraFocus(Transform modelRoot) { - if (!autoFocusCamera || previewCamera == null || modelRoot == null) + if (!autoFocusCamera || _previewCamera == null || modelRoot == null) { return; } - var focusPoint = modelRoot.TransformPoint(cameraFocusOffset); - + if (!_cameraStateCached) + { + _cachedCameraPosition = _previewCamera.transform.position; + _cachedCameraRotation = _previewCamera.transform.rotation; + _cachedCameraFov = _previewCamera.fieldOfView; + _cameraStateCached = true; + } + + var focusPoint = modelRoot.TransformPoint(cameraFocusOffset) + previewCameraOffset; + + Vector3 viewDirection = -modelRoot.forward; + viewDirection.y = 0f; + if (viewDirection.sqrMagnitude < 0.0001f) + { + viewDirection = Vector3.back; + } + viewDirection.Normalize(); + + _previewCamera.transform.position = focusPoint + viewDirection * previewCameraDistance; + _previewCamera.transform.LookAt(focusPoint); + + if (overrideFieldOfView) + { + _previewCamera.fieldOfView = previewFieldOfView; + } } private void StripRuntimeScripts(GameObject cloneRoot) @@ -309,6 +396,19 @@ namespace BrewMonster.Scripts.UI.Inventory } } + private void RestoreSharedCameraState() + { + if (!_cameraStateCached || _previewCamera == null) + { + return; + } + + _previewCamera.transform.position = _cachedCameraPosition; + _previewCamera.transform.rotation = _cachedCameraRotation; + _previewCamera.fieldOfView = _cachedCameraFov; + _cameraStateCached = false; + } + private void FreezeAnimators(GameObject cloneRoot) { if (cloneRoot == null) diff --git a/Assets/PerfectWorld/Scripts/UI/Login/CreateCharacterScreen.cs b/Assets/PerfectWorld/Scripts/UI/Login/CreateCharacterScreen.cs index 823542079d..0a65e7d4a3 100644 --- a/Assets/PerfectWorld/Scripts/UI/Login/CreateCharacterScreen.cs +++ b/Assets/PerfectWorld/Scripts/UI/Login/CreateCharacterScreen.cs @@ -30,7 +30,6 @@ namespace BrewMonster.UI [SerializeField] private Button cancelButton; [SerializeField] private Button backButton; [SerializeField] private CDlgMessageBox messageBoxPrefab; - [SerializeField] private PlayerModelPreview playerModelPreview; private CDlgMessageBox _messageBoxInstance; private int _currentProfession = -1; @@ -403,12 +402,12 @@ namespace BrewMonster.UI } } - playerModelPreview.ShowAllPlayerModels(_roleInfos); + PlayerModelPreview.Instance.ShowAllPlayerModels(_roleInfos); } private void LoadShowModel(int prof, int gender) { - playerModelPreview.ShowPlayerModel(prof * (int)Gender.NUM_GENDER + gender); + PlayerModelPreview .Instance.ShowPlayerModel(prof * (int)Gender.NUM_GENDER + gender); } } } diff --git a/Assets/Prefabs/UI/InventoryUI.prefab b/Assets/Prefabs/UI/InventoryUI.prefab index 884dbd82de..aa4e06d0f5 100644 --- a/Assets/Prefabs/UI/InventoryUI.prefab +++ b/Assets/Prefabs/UI/InventoryUI.prefab @@ -1069,138 +1069,6 @@ MonoBehaviour: m_FillOrigin: 2 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!1 &633515748786992396 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 5275130098495308601} - - component: {fileID: 7874153745862569389} - - component: {fileID: 3332719603249310962} - m_Layer: 5 - m_Name: PreviewCamera - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &5275130098495308601 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 633515748786992396} - m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} - m_LocalPosition: {x: 0, y: 0, z: 103} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 6778274724352405780} - m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} - m_AnchorMin: {x: 1, y: 1} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 1} - m_SizeDelta: {x: 100, y: 100} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!20 &7874153745862569389 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 633515748786992396} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 2 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 - m_Iso: 200 - m_ShutterSpeed: 0.005 - m_Aperture: 16 - m_FocusDistance: 10 - m_FocalLength: 50 - m_BladeCount: 5 - m_Curvature: {x: 2, y: 11} - m_BarrelClipping: 0.25 - m_Anamorphism: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 38 - orthographic: 1 - orthographic size: 1 - m_Depth: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 8400000, guid: 42c3c43cd0c3b704cb6cf0dd1051d9ff, type: 2} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!114 &3332719603249310962 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 633515748786992396} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} - m_Name: - m_EditorClassIdentifier: - m_RenderShadows: 1 - m_RequiresDepthTextureOption: 2 - m_RequiresOpaqueTextureOption: 2 - m_CameraType: 0 - m_Cameras: [] - m_RendererIndex: -1 - m_VolumeLayerMask: - serializedVersion: 2 - m_Bits: 1 - m_VolumeTrigger: {fileID: 0} - m_VolumeFrameworkUpdateModeOption: 2 - m_RenderPostProcessing: 0 - m_Antialiasing: 0 - m_AntialiasingQuality: 2 - m_StopNaN: 0 - m_Dithering: 0 - m_ClearDepth: 1 - m_AllowXRRendering: 1 - m_AllowHDROutput: 1 - m_UseScreenCoordOverride: 0 - m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} - m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} - m_RequiresDepthTexture: 0 - m_RequiresColorTexture: 0 - m_Version: 2 - m_TaaSettings: - m_Quality: 3 - m_FrameInfluence: 0.1 - m_JitterScale: 1 - m_MipBias: 0 - m_VarianceClampScale: 0.9 - m_ContrastAdaptiveSharpening: 0 --- !u!1 &644319246446733122 GameObject: m_ObjectHideFlags: 0 @@ -11166,8 +11034,7 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 5275130098495308601} + m_Children: [] m_Father: {fileID: 3289674559629147232} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -11232,11 +11099,14 @@ MonoBehaviour: previewLocalEuler: {x: 0, y: 0, z: 0} previewLocalScale: {x: 1, y: 1, z: 1} inheritPreviewLayer: 1 - previewCamera: {fileID: 7874153745862569389} previewFrame: {fileID: 6707240765686952970} previewRenderTexture: {fileID: 8400000, guid: 42c3c43cd0c3b704cb6cf0dd1051d9ff, type: 2} autoFocusCamera: 1 cameraFocusOffset: {x: 0, y: 0, z: 0} + previewCameraDistance: 1.4 + previewCameraOffset: {x: 0, y: 0.1, z: 0} + overrideFieldOfView: 1 + previewFieldOfView: 25 freezeAnimation: 1 --- !u!1 &5473020210238587200 GameObject: @@ -20239,7 +20109,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 7209086543831860202, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3} propertyPath: m_AnchoredPosition.y - value: -928.02 + value: -836.15 objectReference: {fileID: 0} - target: {fileID: 8894405194986632892, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3} propertyPath: m_AnchorMax.y @@ -20259,7 +20129,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8894405194986632892, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3} propertyPath: m_AnchoredPosition.y - value: -464.01 + value: -418.075 objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] diff --git a/Assets/Scripts/SelecScreenCharacter.cs b/Assets/Scripts/SelecScreenCharacter.cs index 63c187e318..ba2e0d5664 100644 --- a/Assets/Scripts/SelecScreenCharacter.cs +++ b/Assets/Scripts/SelecScreenCharacter.cs @@ -19,7 +19,6 @@ namespace BrewMonster.UI [SerializeField] private Button createCharacterButton; [SerializeField] private Button _btnEnterGame; [SerializeField] private CreateCharacterScreen createCharacterScreen; - [SerializeField] private PlayerModelPreview playerModelPreview; private CharacterItemUI _selectingCharacterItemUI; private Action _onClickItemChar; @@ -36,11 +35,11 @@ namespace BrewMonster.UI if (_roleInfos != null && _roleInfos.Count > 0) { - playerModelPreview?.ShowAllPlayerModels(_roleInfos); + PlayerModelPreview.Instance?.ShowAllPlayerModels(_roleInfos); } else { - playerModelPreview?.ClearModels(); + PlayerModelPreview.Instance?.ClearModels(); } } @@ -123,12 +122,12 @@ namespace BrewMonster.UI } // Load player preview 3D models - playerModelPreview?.ShowAllPlayerModels(roleInfos); + PlayerModelPreview.Instance?.ShowAllPlayerModels(roleInfos); } else { - if (playerModelPreview != null) - playerModelPreview.ShowAllPlayerModels(null); + if (PlayerModelPreview.Instance != null) + PlayerModelPreview.Instance.ShowAllPlayerModels(null); // If roleInfos is null, show createCharacterButton if (createCharacterButton != null) { @@ -153,7 +152,7 @@ namespace BrewMonster.UI _selectingCharacterItemUI.SetFocus(true); _btnEnterGame.gameObject.SetActive(true); - if (playerModelPreview == null || characterItemUI.RoleInfo == null) + if (PlayerModelPreview.Instance == null || characterItemUI.RoleInfo == null) { return; } @@ -168,16 +167,16 @@ namespace BrewMonster.UI private IEnumerator ShowSelectedModelWhenReady(int roleId) { - while (isActiveAndEnabled && playerModelPreview != null) + while (isActiveAndEnabled && PlayerModelPreview.Instance != null) { if (_pendingShowModelRoleId != roleId) { yield break; // Role changed, stop this coroutine } - if (playerModelPreview.playerModelIds != null && playerModelPreview.playerModelIds.Contains(roleId)) + if (PlayerModelPreview.Instance.playerModelIds != null && PlayerModelPreview.Instance.playerModelIds.Contains(roleId)) { - playerModelPreview.ShowPlayerModel(roleId); + PlayerModelPreview.Instance.ShowPlayerModel(roleId); _showModelReadyCoroutine = null; yield break; // Model is ready, show it and stop this coroutine }