LightGlueGameManager.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. using LightGlue.Unity.Game;
  2. using LightGlue.Unity.Networking;
  3. using LightGlue.Unity.Config;
  4. using LightGlue.Unity.Runtime;
  5. using LightGlue.Unity.UI;
  6. using System;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using UnityEngine;
  10. using UnityEngine.UI;
  11. using Object = UnityEngine.Object;
  12. namespace LightGlue.Unity.Custom
  13. {
  14. public class LightGlueGameManager : MonoBehaviour
  15. {
  16. [Header("参考图像尺寸(必须与 Python --resize 一致)")]
  17. [Tooltip("参考图像宽度(像素)")]
  18. public int referenceImageWidth = 320;
  19. [Tooltip("参考图像高度(像素)")]
  20. public int referenceImageHeight = 240;
  21. private void OnEnable()
  22. {
  23. ReferenceImageResizeService.EnsureInitialized();
  24. ApplyReferenceResize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height);
  25. ReferenceImageResizeService.OnResizeChanged += ApplyReferenceResize;
  26. }
  27. private void OnDisable()
  28. {
  29. ReferenceImageResizeService.OnResizeChanged -= ApplyReferenceResize;
  30. }
  31. private void ApplyReferenceResize(int w, int h)
  32. {
  33. referenceImageWidth = w;
  34. referenceImageHeight = h;
  35. }
  36. [Header("平滑参数来源(唯一来源,无本地参数)")]
  37. [Tooltip("留空则使用 LightGlueCursorSettings.Instance;所有平滑参数均由此引用读取,UI 修改后即时生效")]
  38. public LightGlueCursorSettings cursorSettings;
  39. private Quaternion _currentRotation;
  40. private bool _hasCurrentRotation;
  41. private Quaternion _smoothStartRot;
  42. private Quaternion _smoothTargetRot;
  43. private float _smoothProgress;
  44. private LightGluePositionUpdate _latestUpdate;
  45. private bool _hasLatestUpdate;
  46. [Tooltip("X轴偏移(像素,如果autoCalculateOffset=false则使用此值)")]
  47. public float offsetX = 0f;
  48. [Tooltip("Y轴偏移(像素,如果autoCalculateOffset=false则使用此值)")]
  49. public float offsetY = 0f;
  50. private RectTransform _markerRect;
  51. private Canvas _canvas;
  52. private Vector2 _currentScreenPos;
  53. private bool _hasCurrentScreenPos;
  54. private Vector2 _smoothStartPos;
  55. private Vector2 _smoothTargetPos;
  56. private float _smoothUIProgress;
  57. public static LightGlueGameManager _ins;
  58. public static void Create()
  59. {
  60. if (_ins != null) return;
  61. // 这里按你项目资源路径调整
  62. GameObject o = Object.Instantiate(Resources.Load<GameObject>("LightGlueGameManager"));
  63. Object.DontDestroyOnLoad(o);
  64. _ins = o.GetComponent<LightGlueGameManager>();
  65. // 挂到你们 ViewMgr 层级(按你实际节点修改)
  66. //if (ViewMgr.Instance != null)
  67. //{
  68. // var parent = ViewMgr.Instance.transform.Find("1");
  69. // if (parent != null) o.transform.SetParent(parent, false);
  70. //}
  71. _ins.OnCreated();
  72. }
  73. // 初始化运行时
  74. private void OnCreated()
  75. {
  76. }
  77. private void Awake()
  78. {
  79. if (cursorSettings == null)
  80. cursorSettings = LightGlueCursorSettings.Instance;
  81. //摄像头设备
  82. LightGlueRuntimeFacade.Ensure();
  83. LightGlueRuntimeFacade.OnPositionUpdate += HandleLatestUpdate;
  84. }
  85. void Start()
  86. {
  87. }
  88. private void OnDestroy()
  89. {
  90. LightGlueRuntimeFacade.OnPositionUpdate -= HandleLatestUpdate;
  91. }
  92. /// <summary>
  93. /// 单点更新事件
  94. /// </summary>
  95. public OnPositionUpdateEvent OnPositionUpdate;
  96. public delegate void OnPositionUpdateEvent(Vector2 position, Vector2 cameraLocation);
  97. public void InvokeOnPositionUpdate(Vector2 position, Vector2 cameraLocation)
  98. {
  99. try
  100. {
  101. OnPositionUpdate?.Invoke(position, cameraLocation);
  102. }
  103. catch (Exception e)
  104. {
  105. Debug.LogError(e);
  106. }
  107. }
  108. private LightGlueCursorSettings GetCursorSettings()
  109. {
  110. if (cursorSettings != null) return cursorSettings;
  111. return LightGlueCursorSettings.Instance;
  112. }
  113. private void HandleLatestUpdate(LightGluePositionUpdate update)
  114. {
  115. _latestUpdate = update;
  116. _hasLatestUpdate = true;
  117. if (!_latestUpdate.IsValid) return;
  118. var settings = GetCursorSettings();
  119. if (settings == null) return;
  120. // 构造 LightGlueResult(参考图坐标:左上原点、Y向下)
  121. Vector2 p = _latestUpdate.CameraLocation != default ? _latestUpdate.CameraLocation : _latestUpdate.Position;
  122. var result = new LightGlueResult(
  123. isValid: _latestUpdate.IsValid,
  124. numMatches: _latestUpdate.NumMatches,
  125. inliersRatio: _latestUpdate.InliersRatio,
  126. cameraX: p.x,
  127. cameraY: p.y);
  128. if (!result.IsValid) return;
  129. // -------- 1) Screen 坐标(用于射线/鼠标/业务)--------
  130. Vector2 gameScreenPos = result.GetMappedPosition(
  131. referenceWidth: referenceImageWidth,
  132. referenceHeight: referenceImageHeight,
  133. targetWidth: Screen.width,
  134. targetHeight: Screen.height,
  135. type: LightGlueResult.MappedCoordinateType.GameScreen);
  136. Vector3 screenPoint = new Vector3(gameScreenPos.x, gameScreenPos.y, 0f);
  137. // -------- 2) UI anchored 坐标 + 平滑/抖动(用于 UI)--------
  138. Vector2 targetUiPos = result.GetMappedPosition(
  139. referenceWidth: referenceImageWidth,
  140. referenceHeight: referenceImageHeight,
  141. targetWidth: Screen.width,
  142. targetHeight: Screen.height,
  143. type: LightGlueResult.MappedCoordinateType.UIAnchored,
  144. offset: new Vector2(offsetX, offsetY));
  145. bool useUISmooth = settings.markerEnableSmoothFollow;
  146. float lerpUISpeed = settings.markerPositionLerpSpeed;
  147. float jitterUI = settings.markerJitterThresholdPixels;
  148. AnimationCurve curveUI = settings.markerSmoothCurve;
  149. if (!useUISmooth || !_hasCurrentScreenPos)
  150. {
  151. _currentScreenPos = targetUiPos;
  152. _hasCurrentScreenPos = true;
  153. _smoothStartPos = targetUiPos;
  154. _smoothTargetPos = targetUiPos;
  155. _smoothUIProgress = 1f;
  156. }
  157. else
  158. {
  159. if (jitterUI > 0f && Vector2.Distance(_currentScreenPos, targetUiPos) < jitterUI)
  160. targetUiPos = _currentScreenPos;
  161. _smoothTargetPos = targetUiPos;
  162. if (_smoothUIProgress >= 1f)
  163. {
  164. _smoothStartPos = _currentScreenPos;
  165. _smoothUIProgress = 0f;
  166. }
  167. _smoothUIProgress += Time.unscaledDeltaTime * lerpUISpeed;
  168. _smoothUIProgress = Mathf.Clamp01(_smoothUIProgress);
  169. float t = (curveUI != null && curveUI.keys.Length > 0)
  170. ? curveUI.Evaluate(_smoothUIProgress)
  171. : _smoothUIProgress;
  172. t = Mathf.Clamp01(t);
  173. _currentScreenPos = Vector2.Lerp(_smoothStartPos, _smoothTargetPos, t);
  174. }
  175. // -------- 4) 鼠标/射击:统一用 Screen 坐标--------
  176. if (SB_EventSystem.ins) SB_EventSystem.ins.MoveSimulateMouseByInfrared(_currentScreenPos);
  177. if (GeneratingTarget.gm != null) GeneratingTarget.gm.shootingEvent.OnPositionUpdate(_currentScreenPos);
  178. // UI/业务事件:position=UI(anchored),cameraLocation=Screen(屏幕坐标)
  179. InvokeOnPositionUpdate(_currentScreenPos, gameScreenPos);
  180. // -------- 3) Camera 朝向--------
  181. if (Camera.main == null || CameraToLook.ins == null) return;
  182. Ray ray = Camera.main.ScreenPointToRay(screenPoint);
  183. Vector3 rayEndPoint = ray.GetPoint(200f);
  184. Quaternion targetRotation = Quaternion.LookRotation(rayEndPoint - Camera.main.transform.position);
  185. // 仅挑战场景额外换算(只做一次)
  186. if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "GameChallenge")
  187. targetRotation = Quaternion.AngleAxis(-180f, Vector3.up) * targetRotation;
  188. // 3.1 开镜:只用 GameAssistUI 的平滑(不再叠加 CursorSettings 平滑)
  189. if (GameAssistUI.ins && GameAssistUI.ins.scaleAimOn)
  190. {
  191. float dt = Mathf.Min(Time.unscaledDeltaTime, 0.05f); // 避免低帧率造成旋转跳跃
  192. float smoothingFactor = GameMgr.gameType == 1 ? 12f : 7f;
  193. float k = dt * GameAssistUI.ins.currentSensitivity * smoothingFactor;
  194. CameraToLook.ins.localRotation = Quaternion.Slerp(
  195. CameraToLook.ins.localRotation,
  196. targetRotation,
  197. k
  198. );
  199. }
  200. else
  201. {
  202. // 3.2 非开镜:用 CursorSettings 的平滑+抖动(与 LightGlueCameraAimController 一致)
  203. bool useSmooth = settings.cameraAimEnableSmoothRotation;
  204. float lerpSpeed = settings.cameraAimRotationLerpSpeed;
  205. float jitterDeg = settings.cameraAimRotationJitterThresholdDeg;
  206. AnimationCurve curve = settings.cameraAimSmoothCurve;
  207. if (!useSmooth || !_hasCurrentRotation)
  208. {
  209. _currentRotation = targetRotation;
  210. _hasCurrentRotation = true;
  211. _smoothStartRot = targetRotation;
  212. _smoothTargetRot = targetRotation;
  213. _smoothProgress = 1f;
  214. }
  215. else
  216. {
  217. if (jitterDeg > 0f)
  218. {
  219. float angle = Quaternion.Angle(_currentRotation, targetRotation);
  220. if (angle < jitterDeg)
  221. {
  222. CameraToLook.ins.localRotation = _currentRotation;
  223. if (SB_EventSystem.ins) SB_EventSystem.ins.MoveSimulateMouseByInfrared(screenPoint);
  224. if (GeneratingTarget.gm != null) GeneratingTarget.gm.shootingEvent.OnPositionUpdate(screenPoint);
  225. return;
  226. }
  227. }
  228. _smoothTargetRot = targetRotation;
  229. if (_smoothProgress >= 1f)
  230. {
  231. _smoothStartRot = _currentRotation;
  232. _smoothProgress = 0f;
  233. }
  234. _smoothProgress += Time.unscaledDeltaTime * lerpSpeed;
  235. _smoothProgress = Mathf.Clamp01(_smoothProgress);
  236. float t = (curve != null && curve.keys.Length > 0) ? curve.Evaluate(_smoothProgress) : _smoothProgress;
  237. t = Mathf.Clamp01(t);
  238. _currentRotation = Quaternion.Slerp(_smoothStartRot, _smoothTargetRot, t);
  239. }
  240. CameraToLook.ins.localRotation = _currentRotation;
  241. }
  242. }
  243. private void HandlePositionUpdate(LightGluePositionUpdate update)
  244. {
  245. // 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})");
  246. _latestUpdate = update;
  247. _hasLatestUpdate = true;
  248. LightGlueResult result;
  249. if (!_hasLatestUpdate) return;
  250. if (!_latestUpdate.IsValid) return;
  251. // Position/CameraLocation 均为参考图坐标(左上原点、Y向下)
  252. Vector2 p = _latestUpdate.CameraLocation != default ? _latestUpdate.CameraLocation : _latestUpdate.Position;
  253. result = new LightGlueResult(
  254. isValid: _latestUpdate.IsValid,
  255. numMatches: _latestUpdate.NumMatches,
  256. inliersRatio: _latestUpdate.InliersRatio,
  257. cameraX: p.x,
  258. cameraY: p.y);
  259. if (!result.IsValid) return;
  260. Vector2 gameScreenPos = result.GetMappedPosition(
  261. referenceWidth: referenceImageWidth,
  262. referenceHeight: referenceImageHeight,
  263. targetWidth: Screen.width,
  264. targetHeight: Screen.height,
  265. type: LightGlueResult.MappedCoordinateType.GameScreen);
  266. Vector2 gameUIPos = result.GetMappedPosition(
  267. referenceWidth: referenceImageWidth,
  268. referenceHeight: referenceImageHeight,
  269. targetWidth: Screen.width,
  270. targetHeight: Screen.height,
  271. type: LightGlueResult.MappedCoordinateType.UIAnchored);
  272. Vector3 screenPoint = new Vector3(gameScreenPos.x, gameScreenPos.y, 0f);
  273. InvokeOnPositionUpdate(gameUIPos, gameScreenPos);
  274. //跑九轴时候,不处理这里位置
  275. //if (AimHandler.ins && AimHandler.ins.bRuning9Axis()) return;
  276. if (Camera.main == null)
  277. return;
  278. Ray ray = Camera.main.ScreenPointToRay(screenPoint);
  279. Vector3 rayEndPoint = ray.GetPoint(200);
  280. Quaternion quat = Quaternion.LookRotation(rayEndPoint - Camera.main.transform.position);
  281. // 挑战场景中其相机的父级有旋转,需要换算
  282. if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "GameChallenge")
  283. {
  284. quat = Quaternion.AngleAxis(-180, Vector3.up) * quat;
  285. }
  286. if (GameAssistUI.ins && GameAssistUI.ins.scaleAimOn)
  287. {
  288. if (CameraToLook.ins != null)
  289. {
  290. // 平滑旋转逻辑
  291. float dt = Mathf.Min(Time.unscaledDeltaTime, 0.05f); // 避免低帧率造成旋转跳跃
  292. float smoothingFactor = GameMgr.gameType == 1 ? 12 : 7f; // 原始未开镜的FOV,可调节,数值越大越“跟手”
  293. CameraToLook.ins.localRotation = Quaternion.Slerp(
  294. CameraToLook.ins.localRotation,
  295. quat,
  296. dt * GameAssistUI.ins.currentSensitivity * smoothingFactor
  297. );
  298. }
  299. }
  300. else
  301. {
  302. if (CameraToLook.ins != null) CameraToLook.ins.localRotation = quat;
  303. }
  304. if (SB_EventSystem.ins) SB_EventSystem.ins.MoveSimulateMouseByInfrared(screenPoint);
  305. //移动目标游戏
  306. if (GeneratingTarget.gm != null) GeneratingTarget.gm.shootingEvent.OnPositionUpdate(screenPoint);
  307. }
  308. // Update is called once per frame
  309. void Update()
  310. {
  311. }
  312. }
  313. }