using LightGlue.Unity.Game; using LightGlue.Unity.Networking; using LightGlue.Unity.Config; using LightGlue.Unity.Runtime; using LightGlue.Unity.UI; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using Object = UnityEngine.Object; namespace LightGlue.Unity.Custom { public class LightGlueGameManager : MonoBehaviour { [Header("参考图像尺寸(必须与 Python --resize 一致)")] [Tooltip("参考图像宽度(像素)")] public int referenceImageWidth = 320; [Tooltip("参考图像高度(像素)")] public int referenceImageHeight = 240; private void OnEnable() { ReferenceImageResizeService.EnsureInitialized(); ApplyReferenceResize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height); ReferenceImageResizeService.OnResizeChanged += ApplyReferenceResize; } private void OnDisable() { ReferenceImageResizeService.OnResizeChanged -= ApplyReferenceResize; } private void ApplyReferenceResize(int w, int h) { referenceImageWidth = w; referenceImageHeight = h; } [Header("平滑参数来源(唯一来源,无本地参数)")] [Tooltip("留空则使用 LightGlueCursorSettings.Instance;所有平滑参数均由此引用读取,UI 修改后即时生效")] public LightGlueCursorSettings cursorSettings; private Quaternion _currentRotation; private bool _hasCurrentRotation; private Quaternion _smoothStartRot; private Quaternion _smoothTargetRot; private float _smoothProgress; private LightGluePositionUpdate _latestUpdate; private bool _hasLatestUpdate; [Tooltip("X轴偏移(像素,如果autoCalculateOffset=false则使用此值)")] public float offsetX = 0f; [Tooltip("Y轴偏移(像素,如果autoCalculateOffset=false则使用此值)")] public float offsetY = 0f; private RectTransform _markerRect; private Canvas _canvas; private Vector2 _currentScreenPos; private bool _hasCurrentScreenPos; private Vector2 _smoothStartPos; private Vector2 _smoothTargetPos; private float _smoothUIProgress; public static LightGlueGameManager _ins; public static void Create() { if (_ins != null) return; // 这里按你项目资源路径调整 GameObject o = Object.Instantiate(Resources.Load("LightGlueGameManager")); Object.DontDestroyOnLoad(o); _ins = o.GetComponent(); // 挂到你们 ViewMgr 层级(按你实际节点修改) //if (ViewMgr.Instance != null) //{ // var parent = ViewMgr.Instance.transform.Find("1"); // if (parent != null) o.transform.SetParent(parent, false); //} _ins.OnCreated(); } // 初始化运行时 private void OnCreated() { } private void Awake() { if (cursorSettings == null) cursorSettings = LightGlueCursorSettings.Instance; //摄像头设备 LightGlueRuntimeFacade.Ensure(); LightGlueRuntimeFacade.OnPositionUpdate += HandleLatestUpdate; } void Start() { } private void OnDestroy() { LightGlueRuntimeFacade.OnPositionUpdate -= HandleLatestUpdate; } /// /// 单点更新事件 /// public OnPositionUpdateEvent OnPositionUpdate; public delegate void OnPositionUpdateEvent(Vector2 position, Vector2 cameraLocation); public void InvokeOnPositionUpdate(Vector2 position, Vector2 cameraLocation) { try { OnPositionUpdate?.Invoke(position, cameraLocation); } catch (Exception e) { Debug.LogError(e); } } private LightGlueCursorSettings GetCursorSettings() { if (cursorSettings != null) return cursorSettings; return LightGlueCursorSettings.Instance; } private void HandleLatestUpdate(LightGluePositionUpdate update) { _latestUpdate = update; _hasLatestUpdate = true; if (!_latestUpdate.IsValid) return; var settings = GetCursorSettings(); if (settings == null) return; // 构造 LightGlueResult(参考图坐标:左上原点、Y向下) Vector2 p = _latestUpdate.CameraLocation != default ? _latestUpdate.CameraLocation : _latestUpdate.Position; var result = new LightGlueResult( isValid: _latestUpdate.IsValid, numMatches: _latestUpdate.NumMatches, inliersRatio: _latestUpdate.InliersRatio, cameraX: p.x, cameraY: p.y); if (!result.IsValid) return; // -------- 1) Screen 坐标(用于射线/鼠标/业务)-------- Vector2 gameScreenPos = result.GetMappedPosition( referenceWidth: referenceImageWidth, referenceHeight: referenceImageHeight, targetWidth: Screen.width, targetHeight: Screen.height, type: LightGlueResult.MappedCoordinateType.GameScreen); Vector3 screenPoint = new Vector3(gameScreenPos.x, gameScreenPos.y, 0f); // -------- 2) UI anchored 坐标 + 平滑/抖动(用于 UI)-------- Vector2 targetUiPos = result.GetMappedPosition( referenceWidth: referenceImageWidth, referenceHeight: referenceImageHeight, targetWidth: Screen.width, targetHeight: Screen.height, type: LightGlueResult.MappedCoordinateType.UIAnchored, offset: new Vector2(offsetX, offsetY)); bool useUISmooth = settings.markerEnableSmoothFollow; float lerpUISpeed = settings.markerPositionLerpSpeed; float jitterUI = settings.markerJitterThresholdPixels; AnimationCurve curveUI = settings.markerSmoothCurve; if (!useUISmooth || !_hasCurrentScreenPos) { _currentScreenPos = targetUiPos; _hasCurrentScreenPos = true; _smoothStartPos = targetUiPos; _smoothTargetPos = targetUiPos; _smoothUIProgress = 1f; } else { if (jitterUI > 0f && Vector2.Distance(_currentScreenPos, targetUiPos) < jitterUI) targetUiPos = _currentScreenPos; _smoothTargetPos = targetUiPos; if (_smoothUIProgress >= 1f) { _smoothStartPos = _currentScreenPos; _smoothUIProgress = 0f; } _smoothUIProgress += Time.unscaledDeltaTime * lerpUISpeed; _smoothUIProgress = Mathf.Clamp01(_smoothUIProgress); float t = (curveUI != null && curveUI.keys.Length > 0) ? curveUI.Evaluate(_smoothUIProgress) : _smoothUIProgress; t = Mathf.Clamp01(t); _currentScreenPos = Vector2.Lerp(_smoothStartPos, _smoothTargetPos, t); } // -------- 4) 鼠标/射击:统一用 Screen 坐标-------- if (SB_EventSystem.ins) SB_EventSystem.ins.MoveSimulateMouseByInfrared(_currentScreenPos); if (GeneratingTarget.gm != null) GeneratingTarget.gm.shootingEvent.OnPositionUpdate(_currentScreenPos); // UI/业务事件:position=UI(anchored),cameraLocation=Screen(屏幕坐标) InvokeOnPositionUpdate(_currentScreenPos, gameScreenPos); // -------- 3) Camera 朝向-------- if (Camera.main == null || CameraToLook.ins == null) return; Ray ray = Camera.main.ScreenPointToRay(screenPoint); Vector3 rayEndPoint = ray.GetPoint(200f); Quaternion targetRotation = Quaternion.LookRotation(rayEndPoint - Camera.main.transform.position); // 仅挑战场景额外换算(只做一次) if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "GameChallenge") targetRotation = Quaternion.AngleAxis(-180f, Vector3.up) * targetRotation; // 3.1 开镜:只用 GameAssistUI 的平滑(不再叠加 CursorSettings 平滑) if (GameAssistUI.ins && GameAssistUI.ins.scaleAimOn) { float dt = Mathf.Min(Time.unscaledDeltaTime, 0.05f); // 避免低帧率造成旋转跳跃 float smoothingFactor = GameMgr.gameType == 1 ? 12f : 7f; float k = dt * GameAssistUI.ins.currentSensitivity * smoothingFactor; CameraToLook.ins.localRotation = Quaternion.Slerp( CameraToLook.ins.localRotation, targetRotation, k ); } else { // 3.2 非开镜:用 CursorSettings 的平滑+抖动(与 LightGlueCameraAimController 一致) bool useSmooth = settings.cameraAimEnableSmoothRotation; float lerpSpeed = settings.cameraAimRotationLerpSpeed; float jitterDeg = settings.cameraAimRotationJitterThresholdDeg; AnimationCurve curve = settings.cameraAimSmoothCurve; if (!useSmooth || !_hasCurrentRotation) { _currentRotation = targetRotation; _hasCurrentRotation = true; _smoothStartRot = targetRotation; _smoothTargetRot = targetRotation; _smoothProgress = 1f; } else { if (jitterDeg > 0f) { float angle = Quaternion.Angle(_currentRotation, targetRotation); if (angle < jitterDeg) { CameraToLook.ins.localRotation = _currentRotation; if (SB_EventSystem.ins) SB_EventSystem.ins.MoveSimulateMouseByInfrared(screenPoint); if (GeneratingTarget.gm != null) GeneratingTarget.gm.shootingEvent.OnPositionUpdate(screenPoint); return; } } _smoothTargetRot = targetRotation; if (_smoothProgress >= 1f) { _smoothStartRot = _currentRotation; _smoothProgress = 0f; } _smoothProgress += Time.unscaledDeltaTime * lerpSpeed; _smoothProgress = Mathf.Clamp01(_smoothProgress); float t = (curve != null && curve.keys.Length > 0) ? curve.Evaluate(_smoothProgress) : _smoothProgress; t = Mathf.Clamp01(t); _currentRotation = Quaternion.Slerp(_smoothStartRot, _smoothTargetRot, t); } CameraToLook.ins.localRotation = _currentRotation; } } private void HandlePositionUpdate(LightGluePositionUpdate update) { // Debug.Log($"[LightGlueGameManager] Received position update: Valid={update.IsValid}, Matches={update.NumMatches}, InliersRatio={update.InliersRatio}, CameraLocation=({update.CameraLocation.x}, {update.CameraLocation.y}), Position=({update.Position.x}, {update.Position.y})"); _latestUpdate = update; _hasLatestUpdate = true; LightGlueResult result; if (!_hasLatestUpdate) return; if (!_latestUpdate.IsValid) return; // Position/CameraLocation 均为参考图坐标(左上原点、Y向下) Vector2 p = _latestUpdate.CameraLocation != default ? _latestUpdate.CameraLocation : _latestUpdate.Position; result = new LightGlueResult( isValid: _latestUpdate.IsValid, numMatches: _latestUpdate.NumMatches, inliersRatio: _latestUpdate.InliersRatio, cameraX: p.x, cameraY: p.y); if (!result.IsValid) return; Vector2 gameScreenPos = result.GetMappedPosition( referenceWidth: referenceImageWidth, referenceHeight: referenceImageHeight, targetWidth: Screen.width, targetHeight: Screen.height, type: LightGlueResult.MappedCoordinateType.GameScreen); Vector2 gameUIPos = result.GetMappedPosition( referenceWidth: referenceImageWidth, referenceHeight: referenceImageHeight, targetWidth: Screen.width, targetHeight: Screen.height, type: LightGlueResult.MappedCoordinateType.UIAnchored); Vector3 screenPoint = new Vector3(gameScreenPos.x, gameScreenPos.y, 0f); InvokeOnPositionUpdate(gameUIPos, gameScreenPos); //跑九轴时候,不处理这里位置 //if (AimHandler.ins && AimHandler.ins.bRuning9Axis()) return; if (Camera.main == null) return; Ray ray = Camera.main.ScreenPointToRay(screenPoint); Vector3 rayEndPoint = ray.GetPoint(200); Quaternion quat = Quaternion.LookRotation(rayEndPoint - Camera.main.transform.position); // 挑战场景中其相机的父级有旋转,需要换算 if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "GameChallenge") { quat = Quaternion.AngleAxis(-180, Vector3.up) * quat; } if (GameAssistUI.ins && GameAssistUI.ins.scaleAimOn) { if (CameraToLook.ins != null) { // 平滑旋转逻辑 float dt = Mathf.Min(Time.unscaledDeltaTime, 0.05f); // 避免低帧率造成旋转跳跃 float smoothingFactor = GameMgr.gameType == 1 ? 12 : 7f; // 原始未开镜的FOV,可调节,数值越大越“跟手” CameraToLook.ins.localRotation = Quaternion.Slerp( CameraToLook.ins.localRotation, quat, dt * GameAssistUI.ins.currentSensitivity * smoothingFactor ); } } else { if (CameraToLook.ins != null) CameraToLook.ins.localRotation = quat; } if (SB_EventSystem.ins) SB_EventSystem.ins.MoveSimulateMouseByInfrared(screenPoint); //移动目标游戏 if (GeneratingTarget.gm != null) GeneratingTarget.gm.shootingEvent.OnPositionUpdate(screenPoint); } // Update is called once per frame void Update() { } } }