using UnityEngine;
using UnityEngine.UI;
using LightGlue.Unity.Game;
using LightGlue.Unity.Networking;
using LightGlue.Unity.Config;
namespace LightGlue.Unity.UI
{
///
/// 相机位置准心渲染器
/// - 将Python算法返回的相机坐标映射到Unity屏幕/Canvas坐标
/// - 在屏幕上渲染准心指示器
///
public class CameraPositionCrosshair : MonoBehaviour
{
[Header("结果来源")]
[Tooltip("必须指定 LightGlueManager,由其统一分发算法结果。禁止直接从 Bridge 获取结果。")]
public LightGlueManager manager;
[Header("参考图像尺寸")]
[Tooltip("参考图像的宽度(像素),用于坐标映射")]
public int referenceImageWidth = 640;
[Tooltip("参考图像的高度(像素),用于坐标映射")]
public int referenceImageHeight = 480;
private void OnEnable()
{
ReferenceImageResizeService.EnsureInitialized();
SetReferenceImageSize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height);
ReferenceImageResizeService.OnResizeChanged += SetReferenceImageSize;
}
private void OnDisable()
{
ReferenceImageResizeService.OnResizeChanged -= SetReferenceImageSize;
}
[Header("准心渲染方式")]
[Tooltip("渲染模式:ScreenSpace(屏幕空间)或 Canvas(Canvas空间)")]
public RenderMode renderMode = RenderMode.Canvas;
[Header("ScreenSpace模式设置")]
[Tooltip("ScreenSpace模式:是否使用Camera(如果为false,使用屏幕坐标)")]
public bool useCamera = false;
[Tooltip("ScreenSpace模式:使用的Camera(如果useCamera=true)")]
public Camera targetCamera;
[Header("Canvas模式设置")]
[Tooltip("Canvas模式:目标Canvas(如果为null,自动查找)")]
public Canvas targetCanvas;
[Header("准心外观")]
[Tooltip("准心颜色")]
public Color crosshairColor = Color.red;
[Tooltip("准心大小(像素)")]
public float crosshairSize = 20f;
[Tooltip("准心线宽度(像素)")]
public float lineWidth = 2f;
[Tooltip("是否显示准心(可以通过代码控制)")]
public bool showCrosshair = true;
[Header("坐标映射设置")]
[Tooltip("是否自动适配Canvas尺寸(如果为true,会根据Canvas尺寸自动计算映射)")]
public bool autoFitCanvas = true;
[Tooltip("手动设置的目标显示区域宽度(像素,如果autoFitCanvas=false)")]
public float targetDisplayWidth = 640f;
[Tooltip("手动设置的目标显示区域高度(像素,如果autoFitCanvas=false)")]
public float targetDisplayHeight = 480f;
[Tooltip("显示区域偏移X(像素,用于调整准心位置)")]
public float offsetX = 0f;
[Tooltip("显示区域偏移Y(像素,用于调整准心位置)")]
public float offsetY = 0f;
[Header("更新设置")]
[Tooltip("更新频率(每秒更新次数,默认30次/秒)")]
[Range(1, 60)]
public int updateRate = 30;
private RectTransform _canvasRect;
private Canvas _canvas;
private GameObject _crosshairObject;
private RectTransform _crosshairRect;
private Image _crosshairImageH; // 水平线
private Image _crosshairImageV; // 垂直线
private float _updateInterval;
private float _lastUpdateTime;
private Vector2 _currentScreenPosition;
private bool _hasValidPosition = false;
// 由 LightGlueManager 统一分发的最新结果缓存
private LightGlueResult _latestResult;
private bool _hasLatestResult;
public enum RenderMode
{
ScreenSpace, // 屏幕空间(使用Screen坐标或Camera.WorldToScreenPoint)
Canvas // Canvas空间(使用RectTransform)
}
private void Start()
{
_updateInterval = 1.0f / updateRate;
_lastUpdateTime = Time.time;
// 结果来源:强制通过全局 LightGlueManager 获取
if (manager == null)
{
manager = LightGlueManager.Instance;
}
if (manager == null)
{
Debug.LogError("[CameraPositionCrosshair] 未找到 LightGlueManager,无法获取算法结果。请在场景中放置 LightGlueSystem 预制并确保 LightGlueManager 存在。");
}
else
{
// 订阅 Manager 的结果事件(由 Manager 统一从 Bridge 拉取一次,再分发给所有订阅者)
manager.OnResultUpdated += OnResultUpdated;
// 如果 Manager 已经有缓存的最新结果,立即用一次,避免等下一帧
if (manager.HasLatestResult)
{
OnResultUpdated(manager.LatestResult);
}
}
// 初始化渲染方式
InitializeRenderMode();
}
private void InitializeRenderMode()
{
if (renderMode == RenderMode.Canvas)
{
// Canvas模式:创建准心UI元素
if (targetCanvas == null)
{
targetCanvas = FindObjectOfType