| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- using UnityEngine;
- using LightGlue.Unity.Game;
- using LightGlue.Unity.Networking;
- using LightGlue.Unity.Roma;
- using LightGlue.Unity.Runtime;
- using LightGlue.Unity.Config;
- namespace LightGlue.Unity.UI
- {
- /// <summary>
- /// 专用于游戏内的 LightGlue 相机朝向控制器
- /// - 从 HardwareToPythonUdpBridge 读取算法返回的相机坐标(参考图像坐标系)
- /// - 将参考图坐标映射到游戏实际屏幕坐标(Screen.width / Screen.height)
- /// - 使用 ScreenPointToRay 计算射线方向,并更新 CameraToLook.ins.localRotation
- /// - 不依赖 UI Image,不会与 SimpleCameraPositionMarker 的 UI 逻辑耦合或冲突
- /// </summary>
- public class LightGlueCameraAimController : MonoBehaviour
- {
- [Header("事件驱动(推荐插件模式)")]
- [Tooltip("为 true 时,仅使用 LightGlueRuntimeFacade.OnPositionUpdate 作为结果来源,不再依赖 LightGlueManager/RomaManager。")]
- public bool useOnPositionUpdate = true;
- [Header("结果来源")]
- [Tooltip("优先使用 LightGlueManager(旧场景);若为空则回退到 RomaManager(新 Roma 场景)。禁止直接从 Bridge 获取结果。")]
- public LightGlueManager manager;
- [Tooltip("Roma 场景下的结果来源。通常留空,自动使用 RomaManager.Instance。")]
- public RomaManager romaManager;
- [Header("参考图像尺寸(必须与 Python --resize 一致)")]
- [Tooltip("参考图像宽度(像素)")]
- public int referenceImageWidth = 640;
- [Tooltip("参考图像高度(像素)")]
- public int referenceImageHeight = 480;
- [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;
- private LightGlueCursorSettings GetCursorSettings()
- {
- if (cursorSettings != null) return cursorSettings;
- return LightGlueCursorSettings.Instance;
- }
- private void OnEnable()
- {
- ReferenceImageResizeService.EnsureInitialized();
- SetReferenceImageSize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height);
- ReferenceImageResizeService.OnResizeChanged += SetReferenceImageSize;
- if (!useOnPositionUpdate) return;
- LightGlueRuntimeFacade.Ensure();
- LightGlueRuntimeFacade.OnPositionUpdate += HandlePositionUpdate;
- }
- private void OnDisable()
- {
- ReferenceImageResizeService.OnResizeChanged -= SetReferenceImageSize;
- if (!useOnPositionUpdate) return;
- LightGlueRuntimeFacade.OnPositionUpdate -= HandlePositionUpdate;
- }
- private void HandlePositionUpdate(LightGluePositionUpdate update)
- {
- _latestUpdate = update;
- _hasLatestUpdate = true;
- }
- private void Start()
- {
- if (cursorSettings == null)
- cursorSettings = LightGlueCursorSettings.Instance;
- if (GetCursorSettings() == null)
- Debug.LogWarning("[LightGlueCameraAimController] 未找到 LightGlueCursorSettings,相机朝向平滑参数将不可用,请确保 GameManager 已生成设置预制。");
- if (!useOnPositionUpdate)
- {
- if (manager == null) manager = LightGlueManager.Instance;
- if (manager == null && romaManager == null) romaManager = RomaManager.Instance;
- if (manager == null && romaManager == null)
- Debug.LogError("[LightGlueCameraAimController] 未找到 LightGlueManager / RomaManager,无法获取算法结果。请确认场景已生成对应 System 预制。");
- }
- }
- private void Update()
- {
- LightGlueResult result;
- if (useOnPositionUpdate)
- {
- 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);
- }
- else
- {
- if (manager != null)
- {
- if (!manager.HasLatestResult) return;
- result = manager.LatestResult;
- }
- else
- {
- if (romaManager == null) romaManager = RomaManager.Instance;
- if (romaManager == null || !romaManager.HasLatestResult) return;
- result = romaManager.LatestResult;
- }
- }
- LightGlueCursorSettings settings = GetCursorSettings();
- if (settings == null)
- return;
- if (!result.IsValid) return;
- if (Camera.main == null || CameraToLook.ins == null)
- return;
- 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);
- Ray ray = Camera.main.ScreenPointToRay(screenPoint);
- Vector3 rayEndPoint = ray.GetPoint(200f);
- Quaternion targetRotation = Quaternion.LookRotation(rayEndPoint - Camera.main.transform.position);
- targetRotation = Quaternion.AngleAxis(-180f, Vector3.up) * targetRotation;
- 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;
- return;
- }
- }
- _smoothTargetRot = targetRotation;
- if (_smoothProgress >= 1f)
- {
- _smoothStartRot = _currentRotation;
- _smoothProgress = 0f;
- }
- _smoothProgress += Time.deltaTime * 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;
- }
- /// <summary>
- /// 允许在运行时从外部调整参考图像尺寸(例如根据 Python 参数动态设置)
- /// </summary>
- public void SetReferenceImageSize(int width, int height)
- {
- referenceImageWidth = width;
- referenceImageHeight = height;
- }
- }
- }
|