NROverlay.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /****************************************************************************
  2. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  3. *
  4. * This file is part of NRSDK.
  5. *
  6. * https://www.nreal.ai/
  7. *
  8. *****************************************************************************/
  9. namespace NRKernal.Experimental
  10. {
  11. using System;
  12. using UnityEngine;
  13. [ExecuteInEditMode]
  14. public class NROverlay : OverlayBase
  15. {
  16. /// <summary>
  17. /// If true, the layer will be created as an external surface. externalSurfaceObject contains the Surface object. It's effective only on Android.
  18. /// </summary>
  19. [Tooltip("If true, the layer will be created as an external surface. externalSurfaceObject contains the Surface object. It's effective only on Android.")]
  20. public bool isExternalSurface = false;
  21. /// <summary>
  22. /// The width which will be used to create the external surface. It's effective only on Android.
  23. /// </summary>
  24. [Tooltip("The width which will be used to create the external surface. It's effective only on Android.")]
  25. public int externalSurfaceWidth = 0;
  26. /// <summary>
  27. /// The height which will be used to create the external surface. It's effective only on Android.
  28. /// </summary>
  29. [Tooltip("The height which will be used to create the external surface. It's effective only on Android.")]
  30. public int externalSurfaceHeight = 0;
  31. /// <summary>
  32. /// If true, the texture's content is copied to the compositor each frame.
  33. /// </summary>
  34. [Tooltip("If true, the texture's content is copied to the compositor each frame.")]
  35. public bool isDynamic = false;
  36. /// <summary>
  37. /// If true, the layer would be used to present protected content. The flag is effective only on Android.
  38. /// </summary>
  39. [Tooltip("If true, the layer would be used to present protected content. The flag is effective only on Android.")]
  40. public bool isProtectedContent = false;
  41. /// <summary>
  42. /// The Texture to show in the layer.
  43. /// </summary>
  44. [Tooltip("The Texture to show in the layer.")]
  45. public Texture texture;
  46. /// <summary>
  47. /// Which display this overlay should render to.
  48. /// </summary>
  49. [Tooltip("Which display this overlay should render to.")]
  50. public LayerSide layerSide = LayerSide.Both;
  51. /// <summary>
  52. /// Whether render this overlay as 0-dof.
  53. /// </summary>
  54. [Tooltip("Whether render this overlay as 0-dof.")]
  55. public bool isScreenSpace = false;
  56. /// <summary>
  57. /// Whether this overlay is 3D rendering layer.
  58. /// </summary>
  59. [Tooltip("Whether this overlay is 3D rendering layer.")]
  60. public bool is3DLayer = false;
  61. /// <summary>
  62. /// Preview the overlay in the editor using a mesh renderer.
  63. /// </summary>
  64. [Tooltip("Preview the overlay in the editor using a mesh renderer.")]
  65. public bool previewInEditor;
  66. private bool userTextureMask = false;
  67. public delegate void ExternalSurfaceObjectCreated();
  68. public delegate void BufferedSurfaceObjectChangeded(RenderTexture rt);
  69. public event ExternalSurfaceObjectCreated externalSurfaceObjectCreated;
  70. /// <summary> Only for RenderTexture imageType.</summary>
  71. public event BufferedSurfaceObjectChangeded onBufferChanged;
  72. public Texture MainTexture
  73. {
  74. get
  75. {
  76. return texture;
  77. }
  78. set
  79. {
  80. if (texture != value)
  81. {
  82. SetDirty(true);
  83. userTextureMask = true;
  84. texture = value;
  85. }
  86. }
  87. }
  88. /// <summary> Determines the on-screen appearance of a layer. </summary>
  89. public enum OverlayShape
  90. {
  91. Quad,
  92. //Cylinder,
  93. //Cubemap,
  94. //OffcenterCubemap,
  95. //Equirect,
  96. }
  97. private NROverlayMeshGenerator m_MeshGenerator;
  98. public OverlayShape overlayShape { get; set; } = OverlayShape.Quad;
  99. private Matrix4x4 m_WorldToLeftDisplayMatrix = Matrix4x4.identity;
  100. private Matrix4x4 m_WorldToRightDisplayMatrix = Matrix4x4.identity;
  101. private Matrix4x4 m_OriginPose;
  102. public Rect[] sourceUVRect = new Rect[2] {
  103. new Rect(0, 0, 1, 1),
  104. new Rect(0, 0, 1, 1)
  105. };
  106. new void Start()
  107. {
  108. base.Start();
  109. ApplyMeshAndMat();
  110. }
  111. private void ApplyMeshAndMat()
  112. {
  113. m_MeshGenerator = gameObject.GetComponentInChildren<NROverlayMeshGenerator>();
  114. if (m_MeshGenerator == null)
  115. {
  116. var go = new GameObject("NROverlayMeshGenerator");
  117. // go.hideFlags = HideFlags.HideInHierarchy;
  118. go.transform.SetParent(this.transform, false);
  119. m_MeshGenerator = go.AddComponent<NROverlayMeshGenerator>();
  120. }
  121. m_MeshGenerator.SetOverlay(this);
  122. }
  123. protected override void Initialize()
  124. {
  125. base.Initialize();
  126. m_BufferSpec = new BufferSpec();
  127. if (isExternalSurface)
  128. {
  129. m_BufferSpec.size = new NativeResolution(externalSurfaceWidth, externalSurfaceHeight);
  130. }
  131. else if (texture != null)
  132. {
  133. m_BufferSpec.size = new NativeResolution(texture.width, texture.height);
  134. }
  135. m_BufferSpec.colorFormat = NRColorFormat.NR_COLOR_FORMAT_RGBA_8888;
  136. m_BufferSpec.depthFormat = NRDepthStencilFormat.NR_DEPTH_STENCIL_FORMAT_DEPTH_24;
  137. m_BufferSpec.samples = 1;
  138. m_BufferSpec.useExternalSurface = isExternalSurface;
  139. int flag = 0;
  140. if (isExternalSurface)
  141. {
  142. if (isProtectedContent)
  143. {
  144. flag |= (int)NRExternalSurfaceFlags.NR_EXTERNAL_SURFACE_FLAG_PROTECTED;
  145. }
  146. if (is3DLayer)
  147. {
  148. flag |= (int)NRExternalSurfaceFlags.NR_EXTERNAL_SURFACE_FLAG_SYNCHRONOUS;
  149. flag |= (int)NRExternalSurfaceFlags.NR_EXTERNAL_SURFACE_FLAG_USE_TIMESTAMPS;
  150. }
  151. }
  152. m_BufferSpec.surfaceFlag = flag;
  153. m_OriginPose = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
  154. }
  155. public override void CreateOverlayTextures()
  156. {
  157. ReleaseOverlayTextures();
  158. IntPtr texturePtr = IntPtr.Zero;
  159. if (isExternalSurface)
  160. {
  161. externalSurfaceObjectCreated?.Invoke();
  162. }
  163. else if (isDynamic)
  164. {
  165. if (texture == null)
  166. {
  167. NRDebugger.Warning("Current texture is empty!!!");
  168. return;
  169. }
  170. for (int i = 0; i < m_BufferSpec.bufferCount; ++i)
  171. {
  172. RenderTexture rt = UnityExtendedUtility.CreateRenderTexture(
  173. texture.width, texture.height, 24, RenderTextureFormat.ARGB32
  174. );
  175. texturePtr = rt.GetNativeTexturePtr();
  176. Textures.Add(texturePtr, rt);
  177. }
  178. }
  179. else if (texture)
  180. {
  181. texturePtr = texture.GetNativeTexturePtr();
  182. Textures.Add(texturePtr, texture);
  183. }
  184. }
  185. public override void ReleaseOverlayTextures()
  186. {
  187. if (Textures.Count == 0)
  188. {
  189. return;
  190. }
  191. if (isDynamic)
  192. {
  193. foreach (var item in Textures)
  194. {
  195. RenderTexture rt = item.Value as RenderTexture;
  196. if (rt != null)
  197. {
  198. rt.Release();
  199. }
  200. else if (item.Value != null)
  201. {
  202. GameObject.Destroy(item.Value);
  203. }
  204. }
  205. }
  206. Textures.Clear();
  207. }
  208. public override void CreateViewport()
  209. {
  210. base.CreateViewport();
  211. if (layerSide != LayerSide.Both)
  212. {
  213. m_ViewPorts = new ViewPort[1];
  214. m_ViewPorts[0].reprojection = isScreenSpace ? NRReprojectionType.NR_REPROJECTION_TYPE_NONE : NRReprojectionType.NR_REPROJECTION_TYPE_FULL;
  215. m_ViewPorts[0].sourceUV = sourceUVRect[0];
  216. m_ViewPorts[0].targetDisplay = layerSide;
  217. m_ViewPorts[0].layerID = m_LayerId;
  218. m_ViewPorts[0].is3DLayer = is3DLayer;
  219. if (is3DLayer)
  220. {
  221. NativeDevice displayDev = layerSide == LayerSide.Left ? NativeDevice.LEFT_DISPLAY : NativeDevice.RIGHT_DISPLAY;
  222. NRFrame.GetEyeFov(displayDev, ref m_ViewPorts[0].fov);
  223. }
  224. else
  225. {
  226. m_ViewPorts[0].transform = CalculateCoords(layerSide);
  227. }
  228. NRSwapChainManager.Instance.CreateBufferViewport(ref m_ViewPorts[0]);
  229. }
  230. else
  231. {
  232. m_ViewPorts = new ViewPort[2];
  233. m_ViewPorts[0].reprojection = isScreenSpace ? NRReprojectionType.NR_REPROJECTION_TYPE_NONE : NRReprojectionType.NR_REPROJECTION_TYPE_FULL;
  234. m_ViewPorts[0].sourceUV = sourceUVRect[0];
  235. m_ViewPorts[0].targetDisplay = LayerSide.Left;
  236. m_ViewPorts[0].layerID = m_LayerId;
  237. m_ViewPorts[0].index = -1;
  238. if (is3DLayer)
  239. {
  240. NRFrame.GetEyeFov(NativeDevice.LEFT_DISPLAY, ref m_ViewPorts[0].fov);
  241. }
  242. else
  243. {
  244. m_ViewPorts[0].transform = CalculateCoords(LayerSide.Left);
  245. }
  246. m_ViewPorts[0].is3DLayer = is3DLayer;
  247. NRSwapChainManager.Instance.CreateBufferViewport(ref m_ViewPorts[0]);
  248. m_ViewPorts[1].reprojection = isScreenSpace ? NRReprojectionType.NR_REPROJECTION_TYPE_NONE : NRReprojectionType.NR_REPROJECTION_TYPE_FULL;
  249. m_ViewPorts[1].sourceUV = sourceUVRect[1];
  250. m_ViewPorts[1].targetDisplay = LayerSide.Right;
  251. m_ViewPorts[1].layerID = m_LayerId;
  252. m_ViewPorts[1].index = -1;
  253. if (is3DLayer)
  254. {
  255. NRFrame.GetEyeFov(NativeDevice.RIGHT_DISPLAY, ref m_ViewPorts[1].fov);
  256. }
  257. else
  258. {
  259. m_ViewPorts[1].transform = CalculateCoords(LayerSide.Right);
  260. }
  261. m_ViewPorts[1].is3DLayer = is3DLayer;
  262. NRSwapChainManager.Instance.CreateBufferViewport(ref m_ViewPorts[1]);
  263. }
  264. if (isScreenSpace)
  265. {
  266. CreateWorldToDisplayMatrix();
  267. }
  268. if (is3DLayer)
  269. {
  270. ClearMask();
  271. }
  272. }
  273. /// <summary>
  274. /// Update transform of viewPort.
  275. /// </summary>
  276. public override void UpdateViewPort()
  277. {
  278. base.UpdateViewPort();
  279. if (m_ViewPorts == null)
  280. {
  281. NRDebugger.Warning("Can not update view port for this layer:{0}", gameObject.name);
  282. return;
  283. }
  284. if (layerSide != LayerSide.Both)
  285. {
  286. if (!is3DLayer)
  287. {
  288. m_ViewPorts[0].transform = CalculateCoords(layerSide);
  289. }
  290. NRSwapChainManager.Instance.UpdateBufferViewport(ref m_ViewPorts[0]);
  291. }
  292. else
  293. {
  294. if (!is3DLayer)
  295. {
  296. m_ViewPorts[0].transform = CalculateCoords(LayerSide.Left);
  297. m_ViewPorts[1].transform = CalculateCoords(LayerSide.Right);
  298. }
  299. NRSwapChainManager.Instance.UpdateBufferViewport(ref m_ViewPorts[0]);
  300. NRSwapChainManager.Instance.UpdateBufferViewport(ref m_ViewPorts[1]);
  301. }
  302. }
  303. public override void DestroyViewPort()
  304. {
  305. base.DestroyViewPort();
  306. if (m_ViewPorts != null)
  307. {
  308. foreach (var viewport in m_ViewPorts)
  309. {
  310. NRSwapChainManager.Instance.DestroyBufferViewPort(viewport.nativeHandler);
  311. }
  312. m_ViewPorts = null;
  313. }
  314. }
  315. public void Apply()
  316. {
  317. SetDirty(true);
  318. }
  319. public override void SwapBuffers(IntPtr bufferHandler)
  320. {
  321. if (isDynamic)
  322. {
  323. Texture targetTexture;
  324. if (!Textures.TryGetValue(bufferHandler, out targetTexture))
  325. {
  326. NRDebugger.Error("Can not find the texture:" + bufferHandler);
  327. return;
  328. }
  329. onBufferChanged?.Invoke((RenderTexture)targetTexture);
  330. }
  331. }
  332. public IntPtr GetSurfaceId()
  333. {
  334. if (!isExternalSurface)
  335. {
  336. return IntPtr.Zero;
  337. }
  338. return NRSwapChainManager.Instance.GetSurfaceHandler(this.LayerId);
  339. }
  340. private void CreateWorldToDisplayMatrix()
  341. {
  342. var centerAnchor = NRSessionManager.Instance.NRHMDPoseTracker.centerAnchor;
  343. Matrix4x4 head_T_centerLocal = Matrix4x4.TRS(
  344. centerAnchor.transform.localPosition,
  345. centerAnchor.transform.localRotation,
  346. centerAnchor.transform.localScale);
  347. var leftCamera = NRSessionManager.Instance.NRHMDPoseTracker.leftCamera;
  348. Matrix4x4 head_T_leftLocal = Matrix4x4.TRS(
  349. leftCamera.transform.localPosition,
  350. leftCamera.transform.localRotation,
  351. leftCamera.transform.localScale);
  352. m_WorldToLeftDisplayMatrix = leftCamera.worldToCameraMatrix * leftCamera.transform.localToWorldMatrix *
  353. Matrix4x4.Inverse(head_T_leftLocal) * head_T_centerLocal;
  354. var rightCamera = NRSessionManager.Instance.NRHMDPoseTracker.rightCamera;
  355. Matrix4x4 head_T_rightLocal = Matrix4x4.TRS(
  356. rightCamera.transform.localPosition,
  357. rightCamera.transform.localRotation,
  358. rightCamera.transform.localScale);
  359. m_WorldToRightDisplayMatrix = rightCamera.worldToCameraMatrix * rightCamera.transform.localToWorldMatrix *
  360. Matrix4x4.Inverse(head_T_rightLocal) * head_T_centerLocal;
  361. }
  362. public void UpdateTransform(Matrix4x4 originMatrix, bool isScreenSpace)
  363. {
  364. this.isScreenSpace = isScreenSpace;
  365. if (this.isScreenSpace)
  366. {
  367. CreateWorldToDisplayMatrix();
  368. }
  369. m_OriginPose = originMatrix;
  370. }
  371. private Matrix4x4 CalculateCoords(LayerSide side)
  372. {
  373. if (isScreenSpace)
  374. {
  375. if (side == LayerSide.Left)
  376. {
  377. return m_WorldToLeftDisplayMatrix * m_OriginPose;
  378. }
  379. else
  380. {
  381. return m_WorldToRightDisplayMatrix * m_OriginPose;
  382. }
  383. }
  384. else
  385. {
  386. Camera imageCamera = null;
  387. if (side == LayerSide.Left)
  388. {
  389. imageCamera = NRSessionManager.Instance.NRHMDPoseTracker.leftCamera;
  390. }
  391. else if (side == LayerSide.Right)
  392. {
  393. imageCamera = NRSessionManager.Instance.NRHMDPoseTracker.rightCamera;
  394. }
  395. if (imageCamera == null)
  396. {
  397. return transform.localToWorldMatrix;
  398. }
  399. return imageCamera.worldToCameraMatrix * transform.localToWorldMatrix;
  400. }
  401. }
  402. public void UpdateExternalSurface(NativeMat4f pose, Int64 timestamp, int index)
  403. {
  404. NRSwapChainManager.Instance.UpdateExternalSurface(m_LayerId, pose, timestamp, index);
  405. }
  406. private void ClearMask()
  407. {
  408. if (m_MeshGenerator != null)
  409. {
  410. GameObject.DestroyImmediate(m_MeshGenerator.gameObject);
  411. m_MeshGenerator = null;
  412. }
  413. }
  414. public override void Destroy()
  415. {
  416. base.Destroy();
  417. if (userTextureMask)
  418. {
  419. texture = null;
  420. userTextureMask = false;
  421. }
  422. }
  423. new void OnDestroy()
  424. {
  425. base.OnDestroy();
  426. ClearMask();
  427. }
  428. }
  429. }