ARKitInterface.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Runtime.InteropServices;
  5. using UnityEngine;
  6. using UnityEngine.Rendering;
  7. using UnityEngine.XR;
  8. using UnityEngine.XR.iOS;
  9. namespace UnityARInterface
  10. {
  11. public class ARKitInterface : ARInterface
  12. {
  13. private Material m_ClearMaterial;
  14. private UnityARSessionNativeInterface nativeInterface
  15. { get { return UnityARSessionNativeInterface.GetARSessionNativeInterface(); } }
  16. private bool m_TexturesInitialized;
  17. private int m_CurrentFrameIndex;
  18. private int m_CameraWidth;
  19. private int m_CameraHeight;
  20. private byte[] m_TextureYBytes;
  21. private byte[] m_TextureUVBytes;
  22. private byte[] m_TextureYBytes2;
  23. private byte[] m_TextureUVBytes2;
  24. private ARBackgroundRenderer m_BackgroundRenderer;
  25. private Texture2D _videoTextureY;
  26. private Texture2D _videoTextureCbCr;
  27. private GCHandle m_PinnedYArray;
  28. private GCHandle m_PinnedUVArray;
  29. private Vector3[] m_PointCloudData;
  30. private LightEstimate m_LightEstimate;
  31. private Matrix4x4 m_DisplayTransform;
  32. private ARKitWorldTrackingSessionConfiguration m_SessionConfig;
  33. private Dictionary<string, ARAnchor> m_Anchors = new Dictionary<string, ARAnchor>();
  34. private bool m_BackgroundRendering;
  35. private bool m_CanRenderBackground;
  36. private Camera m_Camera;
  37. private float m_CurrentNearZ;
  38. private float m_CurrentFarZ;
  39. public override bool IsSupported
  40. {
  41. get
  42. {
  43. return m_SessionConfig.IsSupported;
  44. }
  45. }
  46. public override bool BackgroundRendering
  47. {
  48. get
  49. {
  50. return m_BackgroundRendering && m_CanRenderBackground;
  51. }
  52. set
  53. {
  54. if (m_BackgroundRenderer == null)
  55. return;
  56. m_BackgroundRendering = value;
  57. m_BackgroundRenderer.mode = m_BackgroundRendering && m_CanRenderBackground ?
  58. ARRenderMode.MaterialAsBackground : ARRenderMode.StandardBackground;
  59. m_Camera.clearFlags = CameraClearFlags.SolidColor;
  60. m_Camera.backgroundColor = Color.black;
  61. }
  62. }
  63. // Use this for initialization
  64. public override IEnumerator StartService(Settings settings)
  65. {
  66. m_SessionConfig = new ARKitWorldTrackingSessionConfiguration(
  67. UnityARAlignment.UnityARAlignmentGravity,
  68. settings.enablePlaneDetection ? UnityARPlaneDetection.Horizontal : UnityARPlaneDetection.None,
  69. settings.enablePointCloud,
  70. settings.enableLightEstimation);
  71. if (!IsSupported)
  72. {
  73. Debug.LogError("The requested ARKit session configuration is not supported");
  74. return null;
  75. }
  76. UnityARSessionRunOption runOptions =
  77. UnityARSessionRunOption.ARSessionRunOptionRemoveExistingAnchors |
  78. UnityARSessionRunOption.ARSessionRunOptionResetTracking;
  79. nativeInterface.RunWithConfigAndOptions(
  80. m_SessionConfig, runOptions);
  81. // Register for plane detection
  82. UnityARSessionNativeInterface.ARAnchorAddedEvent += AddAnchor;
  83. UnityARSessionNativeInterface.ARAnchorUpdatedEvent += UpdateAnchor;
  84. UnityARSessionNativeInterface.ARAnchorRemovedEvent += RemoveAnchor;
  85. UnityARSessionNativeInterface.ARFrameUpdatedEvent += UpdateFrame;
  86. UnityARSessionNativeInterface.ARUserAnchorUpdatedEvent += UpdateUserAnchor;
  87. IsRunning = true;
  88. return null;
  89. }
  90. private Vector3 GetWorldPosition(ARPlaneAnchor arPlaneAnchor)
  91. {
  92. return UnityARMatrixOps.GetPosition(arPlaneAnchor.transform) +
  93. new Vector3(arPlaneAnchor.center.x, arPlaneAnchor.center.y, -arPlaneAnchor.center.z);
  94. }
  95. private BoundedPlane GetBoundedPlane(ARPlaneAnchor arPlaneAnchor)
  96. {
  97. return new BoundedPlane()
  98. {
  99. id = arPlaneAnchor.identifier,
  100. center = GetWorldPosition(arPlaneAnchor),
  101. rotation = UnityARMatrixOps.GetRotation(arPlaneAnchor.transform),
  102. extents = new Vector2(arPlaneAnchor.extent.x, arPlaneAnchor.extent.z)
  103. };
  104. }
  105. void UpdateFrame(UnityARCamera camera)
  106. {
  107. if (!m_TexturesInitialized)
  108. {
  109. m_CameraWidth = camera.videoParams.yWidth;
  110. m_CameraHeight = camera.videoParams.yHeight;
  111. int numYBytes = camera.videoParams.yWidth * camera.videoParams.yHeight;
  112. int numUVBytes = camera.videoParams.yWidth * camera.videoParams.yHeight / 2; //quarter resolution, but two bytes per pixel
  113. m_TextureYBytes = new byte[numYBytes];
  114. m_TextureUVBytes = new byte[numUVBytes];
  115. m_TextureYBytes2 = new byte[numYBytes];
  116. m_TextureUVBytes2 = new byte[numUVBytes];
  117. m_PinnedYArray = GCHandle.Alloc(m_TextureYBytes);
  118. m_PinnedUVArray = GCHandle.Alloc(m_TextureUVBytes);
  119. m_TexturesInitialized = true;
  120. }
  121. m_PointCloudData = camera.pointCloudData;
  122. m_LightEstimate.capabilities = LightEstimateCapabilities.AmbientColorTemperature | LightEstimateCapabilities.AmbientIntensity;
  123. m_LightEstimate.ambientColorTemperature = camera.lightData.arLightEstimate.ambientColorTemperature;
  124. // Convert ARKit intensity to Unity intensity
  125. // ARKit ambient intensity ranges 0-2000
  126. // Unity ambient intensity ranges 0-8 (for over-bright lights)
  127. m_LightEstimate.ambientIntensity = camera.lightData.arLightEstimate.ambientIntensity / 1000f;
  128. //get display transform matrix sent up from sdk
  129. m_DisplayTransform.SetColumn(0, camera.displayTransform.column0);
  130. m_DisplayTransform.SetColumn(1, camera.displayTransform.column1);
  131. m_DisplayTransform.SetColumn(2, camera.displayTransform.column2);
  132. m_DisplayTransform.SetColumn(3, camera.displayTransform.column3);
  133. }
  134. IntPtr PinByteArray(ref GCHandle handle, byte[] array)
  135. {
  136. handle.Free();
  137. handle = GCHandle.Alloc(array, GCHandleType.Pinned);
  138. return handle.AddrOfPinnedObject();
  139. }
  140. byte[] ByteArrayForFrame(int frame, byte[] array0, byte[] array1)
  141. {
  142. return frame == 1 ? array1 : array0;
  143. }
  144. byte[] YByteArrayForFrame(int frame)
  145. {
  146. return ByteArrayForFrame(frame, m_TextureYBytes, m_TextureYBytes2);
  147. }
  148. byte[] UVByteArrayForFrame(int frame)
  149. {
  150. return ByteArrayForFrame(frame, m_TextureUVBytes, m_TextureUVBytes2);
  151. }
  152. private void AddAnchor(ARPlaneAnchor arPlaneAnchor)
  153. {
  154. OnPlaneAdded(GetBoundedPlane(arPlaneAnchor));
  155. }
  156. private void RemoveAnchor(ARPlaneAnchor arPlaneAnchor)
  157. {
  158. OnPlaneRemoved(GetBoundedPlane(arPlaneAnchor));
  159. }
  160. private void UpdateAnchor(ARPlaneAnchor arPlaneAnchor)
  161. {
  162. OnPlaneUpdated(GetBoundedPlane(arPlaneAnchor));
  163. }
  164. private void UpdateUserAnchor(ARUserAnchor anchorData)
  165. {
  166. ARAnchor anchor;
  167. if (m_Anchors.TryGetValue(anchorData.identifier, out anchor))
  168. {
  169. anchor.transform.position = anchorData.transform.GetColumn(3);
  170. anchor.transform.rotation = anchorData.transform.rotation;
  171. }
  172. }
  173. public override void StopService()
  174. {
  175. var anchors = m_Anchors.Values;
  176. foreach (var anchor in anchors)
  177. {
  178. DestroyAnchor(anchor);
  179. }
  180. UnityARSessionNativeInterface.ARAnchorAddedEvent -= AddAnchor;
  181. UnityARSessionNativeInterface.ARAnchorUpdatedEvent -= UpdateAnchor;
  182. UnityARSessionNativeInterface.ARAnchorRemovedEvent -= RemoveAnchor;
  183. UnityARSessionNativeInterface.ARFrameUpdatedEvent -= UpdateFrame;
  184. UnityARSessionNativeInterface.ARUserAnchorUpdatedEvent -= UpdateUserAnchor;
  185. UnityARSessionNativeInterface.GetARSessionNativeInterface().Pause();
  186. nativeInterface.SetCapturePixelData(false, IntPtr.Zero, IntPtr.Zero);
  187. m_PinnedYArray.Free();
  188. m_PinnedUVArray.Free();
  189. m_TexturesInitialized = false;
  190. BackgroundRendering = false;
  191. m_CanRenderBackground = false;
  192. m_BackgroundRenderer.backgroundMaterial = null;
  193. m_BackgroundRenderer.camera = null;
  194. m_BackgroundRenderer = null;
  195. IsRunning = false;
  196. }
  197. public override bool TryGetUnscaledPose(ref Pose pose)
  198. {
  199. Matrix4x4 matrix = nativeInterface.GetCameraPose();
  200. pose.position = UnityARMatrixOps.GetPosition(matrix);
  201. pose.rotation = UnityARMatrixOps.GetRotation(matrix);
  202. return true;
  203. }
  204. public override bool TryGetCameraImage(ref CameraImage cameraImage)
  205. {
  206. ARTextureHandles handles = nativeInterface.GetARVideoTextureHandles();
  207. if (handles.textureY == System.IntPtr.Zero || handles.textureCbCr == System.IntPtr.Zero)
  208. return false;
  209. if (!m_TexturesInitialized)
  210. return false;
  211. m_CurrentFrameIndex = (m_CurrentFrameIndex + 1) % 2;
  212. nativeInterface.SetCapturePixelData(true,
  213. PinByteArray(ref m_PinnedYArray, YByteArrayForFrame(m_CurrentFrameIndex)),
  214. PinByteArray(ref m_PinnedUVArray, UVByteArrayForFrame(m_CurrentFrameIndex)));
  215. cameraImage.y = YByteArrayForFrame(1 - m_CurrentFrameIndex);
  216. cameraImage.uv = UVByteArrayForFrame(1 - m_CurrentFrameIndex);
  217. cameraImage.width = m_CameraWidth;
  218. cameraImage.height = m_CameraHeight;
  219. return true;
  220. }
  221. public override bool TryGetPointCloud(ref PointCloud pointCloud)
  222. {
  223. if (m_PointCloudData == null)
  224. return false;
  225. if (pointCloud.points == null)
  226. pointCloud.points = new List<Vector3>();
  227. pointCloud.points.Clear();
  228. pointCloud.points.AddRange(m_PointCloudData);
  229. return true;
  230. }
  231. public override LightEstimate GetLightEstimate()
  232. {
  233. return m_LightEstimate;
  234. }
  235. public override Matrix4x4 GetDisplayTransform()
  236. {
  237. return m_DisplayTransform;
  238. }
  239. public override void SetupCamera(Camera camera)
  240. {
  241. m_Camera = camera;
  242. m_ClearMaterial = Resources.Load("YUVMaterial", typeof(Material)) as Material;
  243. m_BackgroundRenderer = new ARBackgroundRenderer();
  244. m_BackgroundRenderer.backgroundMaterial = m_ClearMaterial;
  245. m_BackgroundRenderer.camera = camera;
  246. }
  247. public override void UpdateCamera(Camera camera)
  248. {
  249. camera.projectionMatrix = nativeInterface.GetCameraProjection();
  250. if (!m_BackgroundRendering)
  251. return;
  252. ARTextureHandles handles = UnityARSessionNativeInterface.GetARSessionNativeInterface().GetARVideoTextureHandles();
  253. if (handles.textureY == System.IntPtr.Zero || handles.textureCbCr == System.IntPtr.Zero)
  254. {
  255. m_CanRenderBackground = false;
  256. return;
  257. }
  258. m_CanRenderBackground = true;
  259. BackgroundRendering = m_BackgroundRendering;
  260. Resolution currentResolution = Screen.currentResolution;
  261. // Texture Y
  262. if (_videoTextureY == null)
  263. {
  264. _videoTextureY = Texture2D.CreateExternalTexture(currentResolution.width, currentResolution.height,
  265. TextureFormat.R8, false, false, (System.IntPtr)handles.textureY);
  266. _videoTextureY.filterMode = FilterMode.Bilinear;
  267. _videoTextureY.wrapMode = TextureWrapMode.Repeat;
  268. m_ClearMaterial.SetTexture("_textureY", _videoTextureY);
  269. }
  270. // Texture CbCr
  271. if (_videoTextureCbCr == null)
  272. {
  273. _videoTextureCbCr = Texture2D.CreateExternalTexture(currentResolution.width, currentResolution.height,
  274. TextureFormat.RG16, false, false, (System.IntPtr)handles.textureCbCr);
  275. _videoTextureCbCr.filterMode = FilterMode.Bilinear;
  276. _videoTextureCbCr.wrapMode = TextureWrapMode.Repeat;
  277. m_ClearMaterial.SetTexture("_textureCbCr", _videoTextureCbCr);
  278. }
  279. _videoTextureY.UpdateExternalTexture(handles.textureY);
  280. _videoTextureCbCr.UpdateExternalTexture(handles.textureCbCr);
  281. m_ClearMaterial.SetMatrix("_DisplayTransform", m_DisplayTransform);
  282. }
  283. public override void Update()
  284. {
  285. if (m_CurrentNearZ != m_Camera.nearClipPlane || m_CurrentFarZ != m_Camera.farClipPlane)
  286. {
  287. m_CurrentNearZ = m_Camera.nearClipPlane;
  288. m_CurrentFarZ = m_Camera.farClipPlane;
  289. UnityARSessionNativeInterface.GetARSessionNativeInterface().SetCameraClipPlanes(m_CurrentNearZ, m_CurrentFarZ);
  290. }
  291. }
  292. public override void ApplyAnchor(ARAnchor arAnchor)
  293. {
  294. if (!IsRunning)
  295. return;
  296. Matrix4x4 matrix = Matrix4x4.TRS(arAnchor.transform.position, arAnchor.transform.rotation, arAnchor.transform.localScale);
  297. UnityARUserAnchorData anchorData = new UnityARUserAnchorData();
  298. anchorData.transform.column0 = matrix.GetColumn(0);
  299. anchorData.transform.column1 = matrix.GetColumn(1);
  300. anchorData.transform.column2 = matrix.GetColumn(2);
  301. anchorData.transform.column3 = matrix.GetColumn(3);
  302. anchorData = UnityARSessionNativeInterface.GetARSessionNativeInterface().AddUserAnchor(anchorData);
  303. arAnchor.anchorID = anchorData.identifierStr;
  304. m_Anchors[arAnchor.anchorID] = arAnchor;
  305. }
  306. public override void DestroyAnchor(ARAnchor arAnchor)
  307. {
  308. if (!string.IsNullOrEmpty(arAnchor.anchorID))
  309. {
  310. UnityARSessionNativeInterface.GetARSessionNativeInterface().RemoveUserAnchor(arAnchor.anchorID);
  311. if (m_Anchors.ContainsKey(arAnchor.anchorID))
  312. {
  313. m_Anchors.Remove(arAnchor.anchorID);
  314. }
  315. arAnchor.anchorID = null;
  316. }
  317. }
  318. }
  319. }