ARTracking/Assets/Imagine/Common/Scripts/ARCamera.cs

327 lines
11 KiB
C#
Raw Permalink Normal View History

2024-09-10 22:01:36 -07:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System.Runtime.InteropServices;
#if IMAGINE_URP
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
#endif
namespace Imagine.WebAR
{
[RequireComponent(typeof(Camera))]
public class ARCamera : MonoBehaviour
{
[DllImport("__Internal")] private static extern void SetWebGLARCameraSettings(string settings);
[DllImport("__Internal")] private static extern void WebGLStartCamera();
[DllImport("__Internal")] private static extern bool WebGLIsCameraStarted();
[DllImport("__Internal")] private static extern void WebGLUnpauseCamera();
[DllImport("__Internal")] private static extern void WebGLPauseCamera();
[DllImport("__Internal")] private static extern void WebGLGetCameraTexture(int textureId);
[DllImport("__Internal")] private static extern string WebGLGetVideoDims();
[DllImport("__Internal")] private static extern string WebGLSubscribeVideoTexturePtr(int textureId);
[DllImport("__Internal")] private static extern bool IsWebcamPermissionGranted();
[DllImport("__Internal")] private static extern void WebGLFlipCamera();
[DllImport("__Internal")] private static extern bool WebGLIsCameraFlipped();
public enum VideoPlaneMode {
NONE,
TEXTURE_PTR,
}
[SerializeField] public VideoPlaneMode videoPlaneMode = VideoPlaneMode.TEXTURE_PTR;
[SerializeField] private Material videoPlaneMat;
[SerializeField] private float videoDistance = 100;
[SerializeField] public UnityEvent<Vector2> OnResized;
[HideInInspector] public Camera cam;
private GameObject videoBackground;
private Texture2D videoTexture;
private int videoTextureId;
[Space][SerializeField] private bool unpausePauseOnEnableDisable = false;
[SerializeField] private bool pauseOnDestroy = false;
private bool paused = false;
[SerializeField] private bool pauseOnApplicationLostFocus = false;
[SerializeField][Range(0,1000)]private int resizeDelay = 50;
[SerializeField] public UnityEvent<bool> OnCameraImageFlipped;
[HideInInspector] public bool isFlipped = false;
public enum ARCameraOrientation {PORTRAIT, LANDSCAPE};
[SerializeField] public UnityEvent<ARCameraOrientation> OnCameraOrientationChanged;
[HideInInspector] public ARCameraOrientation orientation;
private void Awake()
{
cam = GetComponent<Camera>();
}
private IEnumerator Start()
{
#if UNITY_WEBGL && !UNITY_EDITOR
isFlipped = WebGLIsCameraFlipped();
#endif
OnCameraImageFlipped?.Invoke(isFlipped);
OnCameraOrientationChanged?.Invoke(Screen.height > Screen.width ? ARCameraOrientation.PORTRAIT : ARCameraOrientation.LANDSCAPE);
#if IMAGINE_URP
//Debug.Log(GraphicsSettings.defaultRenderPipeline.GetType());
if (GraphicsSettings.currentRenderPipeline != null &&
GraphicsSettings.defaultRenderPipeline.GetType().ToString().EndsWith("UniversalRenderPipelineAsset") &&
videoPlaneMode == VideoPlaneMode.NONE
)
{
Debug.Log("URP detected");
cam.clearFlags = CameraClearFlags.Depth;
cam.allowHDR = false;
var camData = GetComponent<UniversalAdditionalCameraData>();
camData.renderPostProcessing = false;
Debug.Log(cam.clearFlags + " " + camData.renderPostProcessing);
}
#endif
SetARCameraSettings();
StartCamera();
yield break;
}
private void OnEnable(){
if(unpausePauseOnEnableDisable)
UnpauseCamera();
}
private void OnDisable(){
if(unpausePauseOnEnableDisable)
PauseCamera();
}
private void OnDestroy(){
if(pauseOnDestroy)
PauseCamera();
}
void SetARCameraSettings(){
var json = "{";
json += "\"UNITY_VIDEOPLANE\":" + (videoPlaneMode != VideoPlaneMode.NONE ? "true" : "false") + ",";
json += "\"RESIZE_DELAY\":" + resizeDelay;
json += "}";
#if UNITY_WEBGL && !UNITY_EDITOR
SetWebGLARCameraSettings(json);
#endif
}
void StartCamera(){
#if UNITY_WEBGL && !UNITY_EDITOR
if(WebGLIsCameraStarted()){
Debug.Log("SetVideoDims");
SetVideoDims();
}
else{
Debug.Log("StartCamera");
WebGLStartCamera();
}
#endif
}
void OnStartWebcamSuccess(){
SetVideoDims();
}
void OnStartWebcamFail(){
Debug.LogError("Webcam failed to start!");
}
void SetCameraFov(float fov)
{
cam.fieldOfView = fov;
Debug.Log("SetCameraFov " + cam.fieldOfView);
}
public void PauseCamera()
{
if(paused)
return;
Debug.Log("Pausing Camera...");
#if UNITY_WEBGL && !UNITY_EDITOR
WebGLPauseCamera();
#endif
paused = true;
}
public void UnpauseCamera()
{
if(!paused)
return;
Debug.Log("Unpausing Camera...");
#if UNITY_WEBGL && !UNITY_EDITOR
WebGLUnpauseCamera();
#endif
paused = false;
}
public void Resize(string dims)
{
// #if UNITY_WEBGL && !UNITY_EDITOR
// //this will tell arCamera in js if unity is also rendering a videoplane
// //and will avoid rendering duplicate planes, and save some fps
// WebGLUseUnityVideoPlane(videoPlaneMode != VideoPlaneMode.NONE);
// #endif
var vals = dims.Split(new string[] { "," }, System.StringSplitOptions.RemoveEmptyEntries);
var width = int.Parse(vals[0]);
var height = int.Parse(vals[1]);
Debug.Log("Got Video Texture Size - " + width + " x " + height);
OnResized?.Invoke(new Vector2(width, height));
if(videoPlaneMode == VideoPlaneMode.NONE)
{
//we resize only when videoplane is active
return;
}
if(videoBackground != null){
Destroy(videoBackground);
}
CreateVideoPlane(width, height);
if(videoTexture != null)
Destroy(videoTexture);
videoTexture = new Texture2D(width, height);
videoPlaneMat.mainTexture = videoTexture;
videoTextureId = (int)videoTexture.GetNativeTexturePtr();
Debug.Log("Unity WebGLSubscribeVideoTexturePtr -> " + videoTextureId);
#if UNITY_WEBGL && !UNITY_EDITOR
WebGLSubscribeVideoTexturePtr(videoTextureId);
#endif
}
void CreateVideoPlane(int width, int height)
{
Debug.Log("Init video plane");
videoBackground = GameObject.CreatePrimitive(PrimitiveType.Quad);
videoBackground.name = "VideoBackground";
videoBackground.transform.parent = transform;
videoPlaneMat.mainTexture = null;
videoBackground.GetComponent<Renderer>().material = videoPlaneMat;
var ar = (float)Screen.width / (float)Screen.height;
var v_ar = (float)width / (float)height;
float heightScale = 1;
if(v_ar > ar){
Debug.Log("Bleed horizontally");
heightScale = 2 * videoDistance * Mathf.Tan(cam.fieldOfView * Mathf.Deg2Rad / 2);
}
else{
Debug.Log("Bleed vertically");
var heightRatio = ar / v_ar;
heightScale = 2 * videoDistance * Mathf.Tan(cam.fieldOfView * Mathf.Deg2Rad / 2) * heightRatio;
}
var widthScale = heightScale * v_ar * (isFlipped ? -1 : 1);
videoBackground.transform.localScale = new Vector3(widthScale, heightScale, 1);
videoBackground.transform.localPosition = new Vector3(0, 0, videoDistance);
videoBackground.transform.localEulerAngles = Vector3.zero;
}
void SetVideoDims(){
Resize( WebGLGetVideoDims());
}
// public void DebugDrawDataUrl(string dataUrl, int width, int height){
// Resize(width + "," + height);
// dataUrl = dataUrl.Replace("data:image/png;base64,", "");
// var oldTex = videoPlaneMat.mainTexture;
// if( oldTex != null){
// Destroy(oldTex);
// }
// Texture2D tex = new Texture2D (width, height);
// tex.LoadImage(System.Convert.FromBase64String(dataUrl));
// tex.Apply ();
// videoPlaneMat.mainTexture = tex;
// }
void OnApplicationFocus(bool hasFocus)
{
if(pauseOnApplicationLostFocus){
#if UNITY_WEBGL && !UNITY_EDITOR
if(WebGLIsCameraStarted()){
if(hasFocus)
UnpauseCamera();
else
PauseCamera();
}
#endif
}
}
void OnApplicationPause(bool pauseStatus)
{
if(pauseOnApplicationLostFocus){
#if UNITY_WEBGL && !UNITY_EDITOR
if(WebGLIsCameraStarted()){
if(!pauseStatus)
UnpauseCamera();
else
PauseCamera();
}
#endif
}
}
public void FlipCamera(){
#if UNITY_WEBGL && !UNITY_EDITOR
WebGLFlipCamera();
#endif
}
void SetFlippedMessage (string message){
Debug.Log("OnFlippedMessage = " + message);
isFlipped = message == "true";
OnCameraImageFlipped?.Invoke(isFlipped);
//flip videoPlane
if(videoBackground != null){
var newScale = videoBackground.transform.localScale;
newScale.x = Mathf.Abs(newScale.x) * (isFlipped ? -1 : 1);
videoBackground.transform.localScale = newScale;
}
}
void SetOrientationMessage (string message){
Debug.Log("OrientationMessage = " + message);
orientation = message == "PORTRAIT" ? ARCameraOrientation.PORTRAIT : ARCameraOrientation.LANDSCAPE;
OnCameraOrientationChanged?.Invoke(orientation);
}
}
}