ARCamera.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. using System.Runtime.InteropServices;
  6. #if IMAGINE_URP
  7. using UnityEngine.Rendering;
  8. using UnityEngine.Rendering.Universal;
  9. #endif
  10. namespace Imagine.WebAR
  11. {
  12. [RequireComponent(typeof(Camera))]
  13. public class ARCamera : MonoBehaviour
  14. {
  15. [DllImport("__Internal")] private static extern void SetWebGLARCameraSettings(string settings);
  16. [DllImport("__Internal")] private static extern void WebGLStartCamera();
  17. [DllImport("__Internal")] private static extern bool WebGLIsCameraStarted();
  18. [DllImport("__Internal")] private static extern void WebGLUnpauseCamera();
  19. [DllImport("__Internal")] private static extern void WebGLPauseCamera();
  20. [DllImport("__Internal")] private static extern void WebGLGetCameraTexture(int textureId);
  21. [DllImport("__Internal")] private static extern string WebGLGetVideoDims();
  22. [DllImport("__Internal")] private static extern string WebGLSubscribeVideoTexturePtr(int textureId);
  23. [DllImport("__Internal")] private static extern bool IsWebcamPermissionGranted();
  24. [DllImport("__Internal")] private static extern void WebGLFlipCamera();
  25. [DllImport("__Internal")] private static extern bool WebGLIsCameraFlipped();
  26. public enum VideoPlaneMode {
  27. NONE,
  28. TEXTURE_PTR,
  29. }
  30. [SerializeField] public VideoPlaneMode videoPlaneMode = VideoPlaneMode.TEXTURE_PTR;
  31. [SerializeField] private Material videoPlaneMat;
  32. [SerializeField] private float videoDistance = 100;
  33. [SerializeField] public UnityEvent<Vector2> OnResized;
  34. [HideInInspector] public Camera cam;
  35. private GameObject videoBackground;
  36. private Texture2D videoTexture;
  37. private int videoTextureId;
  38. [Space][SerializeField] private bool unpausePauseOnEnableDisable = false;
  39. [SerializeField] private bool pauseOnDestroy = false;
  40. private bool paused = false;
  41. [SerializeField] private bool pauseOnApplicationLostFocus = false;
  42. [SerializeField][Range(0,1000)]private int resizeDelay = 50;
  43. [SerializeField] public UnityEvent<bool> OnCameraImageFlipped;
  44. [HideInInspector] public bool isFlipped = false;
  45. public enum ARCameraOrientation {PORTRAIT, LANDSCAPE};
  46. [SerializeField] public UnityEvent<ARCameraOrientation> OnCameraOrientationChanged;
  47. [HideInInspector] public ARCameraOrientation orientation;
  48. private void Awake()
  49. {
  50. cam = GetComponent<Camera>();
  51. }
  52. public void InitAR()
  53. {
  54. StartCoroutine(InitARCam());
  55. }
  56. private IEnumerator InitARCam()
  57. {
  58. #if UNITY_WEBGL && !UNITY_EDITOR
  59. isFlipped = WebGLIsCameraFlipped();
  60. #endif
  61. OnCameraImageFlipped?.Invoke(isFlipped);
  62. OnCameraOrientationChanged?.Invoke(Screen.height > Screen.width ? ARCameraOrientation.PORTRAIT : ARCameraOrientation.LANDSCAPE);
  63. #if IMAGINE_URP
  64. //Debug.Log(GraphicsSettings.defaultRenderPipeline.GetType());
  65. if (GraphicsSettings.currentRenderPipeline != null &&
  66. GraphicsSettings.defaultRenderPipeline.GetType().ToString().EndsWith("UniversalRenderPipelineAsset") &&
  67. videoPlaneMode == VideoPlaneMode.NONE
  68. )
  69. {
  70. Debug.Log("URP detected");
  71. cam.clearFlags = CameraClearFlags.Depth;
  72. cam.allowHDR = false;
  73. var camData = GetComponent<UniversalAdditionalCameraData>();
  74. camData.renderPostProcessing = false;
  75. Debug.Log(cam.clearFlags + " " + camData.renderPostProcessing);
  76. }
  77. #endif
  78. SetARCameraSettings();
  79. StartCamera();
  80. yield break;
  81. }
  82. private void OnEnable(){
  83. if(unpausePauseOnEnableDisable)
  84. UnpauseCamera();
  85. }
  86. private void OnDisable(){
  87. if(unpausePauseOnEnableDisable)
  88. PauseCamera();
  89. }
  90. private void OnDestroy(){
  91. if(pauseOnDestroy)
  92. PauseCamera();
  93. }
  94. void SetARCameraSettings(){
  95. var json = "{";
  96. json += "\"UNITY_VIDEOPLANE\":" + (videoPlaneMode != VideoPlaneMode.NONE ? "true" : "false") + ",";
  97. json += "\"RESIZE_DELAY\":" + resizeDelay;
  98. json += "}";
  99. #if UNITY_WEBGL && !UNITY_EDITOR
  100. SetWebGLARCameraSettings(json);
  101. #endif
  102. }
  103. void StartCamera(){
  104. #if UNITY_WEBGL && !UNITY_EDITOR
  105. if(WebGLIsCameraStarted()){
  106. Debug.Log("SetVideoDims");
  107. SetVideoDims();
  108. }
  109. else{
  110. Debug.Log("StartCamera");
  111. WebGLStartCamera();
  112. }
  113. #endif
  114. }
  115. void OnStartWebcamSuccess(){
  116. SetVideoDims();
  117. }
  118. void OnStartWebcamFail(){
  119. Debug.LogError("Webcam failed to start!");
  120. }
  121. void SetCameraFov(float fov)
  122. {
  123. cam.fieldOfView = fov;
  124. Debug.Log("SetCameraFov " + cam.fieldOfView);
  125. }
  126. public void PauseCamera()
  127. {
  128. if(paused)
  129. return;
  130. Debug.Log("Pausing Camera...");
  131. #if UNITY_WEBGL && !UNITY_EDITOR
  132. WebGLPauseCamera();
  133. #endif
  134. paused = true;
  135. }
  136. public void UnpauseCamera()
  137. {
  138. if(!paused)
  139. return;
  140. Debug.Log("Unpausing Camera...");
  141. #if UNITY_WEBGL && !UNITY_EDITOR
  142. WebGLUnpauseCamera();
  143. #endif
  144. paused = false;
  145. }
  146. public void Resize(string dims)
  147. {
  148. // #if UNITY_WEBGL && !UNITY_EDITOR
  149. // //this will tell arCamera in js if unity is also rendering a videoplane
  150. // //and will avoid rendering duplicate planes, and save some fps
  151. // WebGLUseUnityVideoPlane(videoPlaneMode != VideoPlaneMode.NONE);
  152. // #endif
  153. var vals = dims.Split(new string[] { "," }, System.StringSplitOptions.RemoveEmptyEntries);
  154. var width = int.Parse(vals[0]);
  155. var height = int.Parse(vals[1]);
  156. Debug.Log("Got Video Texture Size - " + width + " x " + height);
  157. OnResized?.Invoke(new Vector2(width, height));
  158. if(videoPlaneMode == VideoPlaneMode.NONE)
  159. {
  160. //we resize only when videoplane is active
  161. return;
  162. }
  163. if(videoBackground != null){
  164. Destroy(videoBackground);
  165. }
  166. CreateVideoPlane(width, height);
  167. if(videoTexture != null)
  168. Destroy(videoTexture);
  169. videoTexture = new Texture2D(width, height);
  170. videoPlaneMat.mainTexture = videoTexture;
  171. videoTextureId = (int)videoTexture.GetNativeTexturePtr();
  172. Debug.Log("Unity WebGLSubscribeVideoTexturePtr -> " + videoTextureId);
  173. #if UNITY_WEBGL && !UNITY_EDITOR
  174. WebGLSubscribeVideoTexturePtr(videoTextureId);
  175. #endif
  176. }
  177. void CreateVideoPlane(int width, int height)
  178. {
  179. Debug.Log("Init video plane");
  180. videoBackground = GameObject.CreatePrimitive(PrimitiveType.Quad);
  181. videoBackground.name = "VideoBackground";
  182. videoBackground.transform.parent = transform;
  183. videoPlaneMat.mainTexture = null;
  184. videoBackground.GetComponent<Renderer>().material = videoPlaneMat;
  185. var ar = (float)Screen.width / (float)Screen.height;
  186. var v_ar = (float)width / (float)height;
  187. float heightScale = 1;
  188. if(v_ar > ar){
  189. Debug.Log("Bleed horizontally");
  190. heightScale = 2 * videoDistance * Mathf.Tan(cam.fieldOfView * Mathf.Deg2Rad / 2);
  191. }
  192. else{
  193. Debug.Log("Bleed vertically");
  194. var heightRatio = ar / v_ar;
  195. heightScale = 2 * videoDistance * Mathf.Tan(cam.fieldOfView * Mathf.Deg2Rad / 2) * heightRatio;
  196. }
  197. var widthScale = heightScale * v_ar * (isFlipped ? -1 : 1);
  198. videoBackground.transform.localScale = new Vector3(widthScale, heightScale, 1);
  199. videoBackground.transform.localPosition = new Vector3(0, 0, videoDistance);
  200. videoBackground.transform.localEulerAngles = Vector3.zero;
  201. }
  202. void SetVideoDims(){
  203. Resize( WebGLGetVideoDims());
  204. }
  205. // public void DebugDrawDataUrl(string dataUrl, int width, int height){
  206. // Resize(width + "," + height);
  207. // dataUrl = dataUrl.Replace("data:image/png;base64,", "");
  208. // var oldTex = videoPlaneMat.mainTexture;
  209. // if( oldTex != null){
  210. // Destroy(oldTex);
  211. // }
  212. // Texture2D tex = new Texture2D (width, height);
  213. // tex.LoadImage(System.Convert.FromBase64String(dataUrl));
  214. // tex.Apply ();
  215. // videoPlaneMat.mainTexture = tex;
  216. // }
  217. void OnApplicationFocus(bool hasFocus)
  218. {
  219. if(pauseOnApplicationLostFocus){
  220. #if UNITY_WEBGL && !UNITY_EDITOR
  221. if(WebGLIsCameraStarted()){
  222. if(hasFocus)
  223. UnpauseCamera();
  224. else
  225. PauseCamera();
  226. }
  227. #endif
  228. }
  229. }
  230. void OnApplicationPause(bool pauseStatus)
  231. {
  232. if(pauseOnApplicationLostFocus){
  233. #if UNITY_WEBGL && !UNITY_EDITOR
  234. if(WebGLIsCameraStarted()){
  235. if(!pauseStatus)
  236. UnpauseCamera();
  237. else
  238. PauseCamera();
  239. }
  240. #endif
  241. }
  242. }
  243. public void FlipCamera(){
  244. #if UNITY_WEBGL && !UNITY_EDITOR
  245. WebGLFlipCamera();
  246. #endif
  247. }
  248. void SetFlippedMessage (string message){
  249. Debug.Log("OnFlippedMessage = " + message);
  250. isFlipped = message == "true";
  251. OnCameraImageFlipped?.Invoke(isFlipped);
  252. //flip videoPlane
  253. if(videoBackground != null){
  254. var newScale = videoBackground.transform.localScale;
  255. newScale.x = Mathf.Abs(newScale.x) * (isFlipped ? -1 : 1);
  256. videoBackground.transform.localScale = newScale;
  257. }
  258. }
  259. void SetOrientationMessage (string message){
  260. Debug.Log("OrientationMessage = " + message);
  261. orientation = message == "PORTRAIT" ? ARCameraOrientation.PORTRAIT : ARCameraOrientation.LANDSCAPE;
  262. OnCameraOrientationChanged?.Invoke(orientation);
  263. }
  264. }
  265. }