| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- using UnityEngine;
- using UnityEngine.UI;
- using LightGlue.Unity.Game;
- using LightGlue.Unity.Networking;
- using LightGlue.Unity.Roma;
- namespace LightGlue.Unity.UI
- {
- /// <summary>
- /// 简单的相机位置标记器
- /// - 直接将相机坐标映射到屏幕坐标
- /// - 只需要一个Image图标,用RectTransform设置位置
- /// - 不需要考虑图片大小,直接用坐标定位
- /// </summary>
- public class SimpleCameraPositionMarker : MonoBehaviour
- {
- [Header("结果来源")]
- [Tooltip("必须指定 LightGlueManager,由其统一分发算法结果。禁止直接从 Bridge 获取结果。")]
- public LightGlueManager manager;
- [Tooltip("Roma 场景可选:若没有 LightGlueManager,则使用 RomaManager 获取算法结果。")]
- public RomaManager romaManager;
- [Header("UI图标")]
- [Tooltip("要移动的Image图标(在Canvas下的任意Image组件)")]
- public Image markerImage;
- [Header("参考图像尺寸(用于坐标映射)")]
- [Tooltip("参考图像的宽度(像素)")]
- public int referenceImageWidth = 640;
- [Tooltip("参考图像的高度(像素)")]
- public int referenceImageHeight = 480;
- [Header("屏幕显示区域")]
- [Tooltip("目标显示区域的宽度(像素,通常等于Canvas宽度或屏幕宽度)")]
- public float screenWidth = 1920f;
- [Tooltip("目标显示区域的高度(像素,通常等于Canvas高度或屏幕高度)")]
- public float screenHeight = 1080f;
- [Tooltip("是否自动使用Canvas尺寸(如果为true,会自动获取Canvas尺寸)")]
- public bool autoUseCanvasSize = true;
- [Header("坐标偏移(用于微调位置)")]
- [Tooltip("是否自动计算偏移量(如果坐标映射有整体偏移,可以自动修正)")]
- public bool autoCalculateOffset = true;
- [Tooltip("X轴偏移(像素,如果autoCalculateOffset=false则使用此值)")]
- public float offsetX = 0f;
- [Tooltip("Y轴偏移(像素,如果autoCalculateOffset=false则使用此值)")]
- public float offsetY = 0f;
- [Header("平滑参数来源(唯一来源,无本地参数)")]
- [Tooltip("留空则使用 LightGlueCursorSettings.Instance;所有平滑参数均由此引用读取,UI 修改后即时生效")]
- public LightGlueCursorSettings cursorSettings;
- private RectTransform _markerRect;
- private Canvas _canvas;
- private Vector2 _currentScreenPos;
- private bool _hasCurrentScreenPos;
- private Vector2 _smoothStartPos;
- private Vector2 _smoothTargetPos;
- private float _smoothProgress;
- // 由 LightGlueManager 分发的最新结果缓存
- private LightGlueResult _latestResult;
- private bool _hasLatestResult;
- private LightGlueCursorSettings GetCursorSettings()
- {
- if (cursorSettings != null) return cursorSettings;
- return LightGlueCursorSettings.Instance;
- }
- private void Start()
- {
- if (cursorSettings == null)
- cursorSettings = LightGlueCursorSettings.Instance;
- if (GetCursorSettings() == null)
- Debug.LogWarning("[SimpleCameraPositionMarker] 未找到 LightGlueCursorSettings,标记器平滑参数将不可用,请确保 GameManager 已生成设置预制。");
- // 结果来源:强制通过全局 LightGlueManager 获取
- if (manager == null)
- {
- manager = LightGlueManager.Instance;
- }
- if (manager != null)
- {
- manager.OnResultUpdated += OnResultUpdated;
- if (manager.HasLatestResult)
- OnResultUpdated(manager.LatestResult);
- }
- else
- {
- // Roma:统一通过 RomaManager 获取(RomaManager 内部会自动桥接 RomaHardwareToPythonBridge)
- if (romaManager == null)
- romaManager = RomaManager.Instance;
- if (romaManager != null)
- {
- romaManager.OnResultUpdated += OnResultUpdated;
- if (romaManager.HasLatestResult)
- OnResultUpdated(romaManager.LatestResult);
- }
- else
- {
- Debug.LogError("[SimpleCameraPositionMarker] 未找到 LightGlueManager 或 RomaManager,无法获取算法结果。");
- }
- }
- // 获取Image的RectTransform
- if (markerImage != null)
- {
- _markerRect = markerImage.GetComponent<RectTransform>();
- if (_markerRect == null)
- {
- Debug.LogError("[SimpleCameraPositionMarker] Image组件必须附加在带有RectTransform的GameObject上");
- }
- else
- {
- // 确保anchor和pivot设置正确(左下角anchor,中心pivot)
- _markerRect.anchorMin = new Vector2(0, 0);
- _markerRect.anchorMax = new Vector2(0, 0);
- _markerRect.pivot = new Vector2(0.5f, 0.5f); // 中心pivot,这样图标会以中心点定位
- // 输出当前设置用于调试
- Debug.Log($"[SimpleCameraPositionMarker] RectTransform设置: " +
- $"anchor=({_markerRect.anchorMin.x},{_markerRect.anchorMin.y}), " +
- $"pivot=({_markerRect.pivot.x},{_markerRect.pivot.y}), " +
- $"当前位置=({_markerRect.anchoredPosition.x},{_markerRect.anchoredPosition.y})");
- }
- }
- else
- {
- Debug.LogWarning("[SimpleCameraPositionMarker] 请指定要移动的Image图标");
- }
- // 自动获取Canvas尺寸
- if (autoUseCanvasSize)
- {
- if (markerImage != null)
- {
- _canvas = markerImage.canvas;
- if (_canvas != null)
- {
- RectTransform canvasRect = _canvas.GetComponent<RectTransform>();
- if (canvasRect != null)
- {
- screenWidth = canvasRect.rect.width;
- screenHeight = canvasRect.rect.height;
- Debug.Log($"[SimpleCameraPositionMarker] 自动获取Canvas尺寸: {screenWidth}x{screenHeight}");
- }
- }
- }
- // 如果还是没找到Canvas,使用屏幕尺寸
- if (screenWidth <= 0 || screenHeight <= 0)
- {
- screenWidth = Screen.width;
- screenHeight = Screen.height;
- Debug.Log($"[SimpleCameraPositionMarker] 使用屏幕尺寸: {screenWidth}x{screenHeight}");
- }
- }
- // 自动计算偏移量(如果需要)
- if (autoCalculateOffset)
- {
- // 如果anchor设置为左下角(0,0)但实际需要中心点偏移,自动计算
- // 通常这种情况是因为Canvas坐标系原点在中心而不是左下角
- // 偏移量 = -中心点坐标
- offsetX = -screenWidth * 0.5f;
- offsetY = -screenHeight * 0.5f;
- Debug.Log($"[SimpleCameraPositionMarker] 自动计算偏移量: offsetX={offsetX:F1}, offsetY={offsetY:F1} (Canvas中心点偏移)");
- }
- }
- private void Update()
- {
- if (manager == null && romaManager == null)
- return;
- if (!_hasLatestResult || !_latestResult.IsValid)
- return;
- LightGlueCursorSettings settings = GetCursorSettings();
- if (settings == null)
- return;
- var result = _latestResult;
- Vector2 targetScreenPos = result.GetMappedPosition(
- referenceWidth: referenceImageWidth,
- referenceHeight: referenceImageHeight,
- targetWidth: screenWidth,
- targetHeight: screenHeight,
- type: LightGlueResult.MappedCoordinateType.UIAnchored,
- offset: new Vector2(offsetX, offsetY));
- bool useSmooth = settings.markerEnableSmoothFollow;
- float lerpSpeed = settings.markerPositionLerpSpeed;
- float jitter = settings.markerJitterThresholdPixels;
- AnimationCurve curve = settings.markerSmoothCurve;
- if (!useSmooth || !_hasCurrentScreenPos)
- {
- _currentScreenPos = targetScreenPos;
- _hasCurrentScreenPos = true;
- _smoothStartPos = targetScreenPos;
- _smoothTargetPos = targetScreenPos;
- _smoothProgress = 1f;
- }
- else
- {
- if (jitter > 0f && Vector2.Distance(_currentScreenPos, targetScreenPos) < jitter)
- targetScreenPos = _currentScreenPos;
- _smoothTargetPos = targetScreenPos;
- if (_smoothProgress >= 1f)
- {
- _smoothStartPos = _currentScreenPos;
- _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);
- _currentScreenPos = Vector2.Lerp(_smoothStartPos, _smoothTargetPos, t);
- }
- if (_markerRect != null)
- {
- _markerRect.anchoredPosition = _currentScreenPos;
- }
- // 调试输出(每30帧输出一次,避免日志过多)
- //if (Time.frameCount % 30 == 0)
- //{
- // Debug.Log($"[SimpleCameraPositionMarker] 坐标映射: " +
- // $"参考图({result.CameraPosition.x:F1},{result.CameraPosition.y:F1}) -> " +
- // $"屏幕({targetScreenPos.x:F1},{targetScreenPos.y:F1}), " +
- // $"Canvas尺寸={screenWidth}x{screenHeight}, " +
- // $"参考图尺寸={referenceImageWidth}x{referenceImageHeight}");
- //}
- // 显示图标
- if (markerImage != null && !markerImage.gameObject.activeSelf)
- {
- markerImage.gameObject.SetActive(true);
- }
- }
- /// <summary>
- /// 设置参考图像尺寸(供外部调用)
- /// </summary>
- public void SetReferenceImageSize(int width, int height)
- {
- referenceImageWidth = width;
- referenceImageHeight = height;
- }
- /// <summary>
- /// 设置屏幕显示区域尺寸(供外部调用)
- /// </summary>
- public void SetScreenSize(float width, float height)
- {
- screenWidth = width;
- screenHeight = height;
- }
- /// <summary>
- /// 设置坐标偏移(供外部调用)
- /// </summary>
- public void SetOffset(float x, float y)
- {
- offsetX = x;
- offsetY = y;
- }
- /// <summary>
- /// 由 LightGlueManager 触发的结果更新回调,仅做结果缓存,坐标计算在 Update 每帧执行。
- /// </summary>
- private void OnResultUpdated(LightGlueResult result)
- {
- _latestResult = result;
- _hasLatestResult = true;
- }
- private void OnDestroy()
- {
- if (manager != null)
- {
- manager.OnResultUpdated -= OnResultUpdated;
- }
- if (romaManager != null)
- {
- romaManager.OnResultUpdated -= OnResultUpdated;
- }
- }
- }
- }
|