using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SXR;
using UnityEngine.Rendering;
namespace Ximmerse.XR.Rendering
{
///
/// 用于渲染随头UI/3D 物体的组件。
///
public class OverlayCamera : MonoBehaviour
{
///
/// Culling mask of the overlay camera
///
[Tooltip("Culling mask of the overlay camera")]
public LayerMask cullingMask = 1 << 5;
///
/// Depth of the overlay camera
///
[Tooltip("Depth of the overlay camera")]
public int depth = 1;
[Range(0.1f, 1)]
public float renderScale = 1;
const int kBufferCount = 1;
RenderTexture[] renderTexturesL = new RenderTexture[kBufferCount];
RenderTexture[] renderTexturesR = new RenderTexture[kBufferCount];
private int rtIndex = 0;
Transform eyeTrans;
Camera overlayCamL, overlayCamR;
///
/// Background color of overlay camera
///
Color m_overlayBackgroundColor = new Color(0, 0, 0, 0);
public Color overlayBackgroundColor
{
get => m_overlayBackgroundColor;
set
{
m_overlayBackgroundColor = value;
if (overlayCamL)
overlayCamL.backgroundColor = value;
if (overlayCamR)
overlayCamR.backgroundColor = value;
}
}
public void FadeIn(float duration)
{
this.enabled = true;
this.StartCoroutine(fadeIn(duration));
}
public void FadeOut(float duration)
{
this.enabled = true;
this.StartCoroutine(fadeOut(duration));
}
// Start is called before the first frame update
void Start()
{
if (!eyeTrans)
{
eyeTrans = Camera.main.transform;
}
if (!eyeTrans)
{
Debug.LogError("MainCamera is not found , overlay camera failed to start !");
return;
}
bool isAndroid = Application.platform == RuntimePlatform.Android;
Matrix4x4 projectionMatrix = default(Matrix4x4);
float ipd = 0.062f;
if (isAndroid)
{
float l = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Left_FLOAT);
float r = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Right_FLOAT);
float t = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Top_FLOAT);
float b = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Bottom_FLOAT);
float n = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Near_FLOAT);
float f = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_Frustum_Far_FLOAT);
projectionMatrix = GetPerspectiveProjectionMatrix(l, r, b, t, n, f);
ipd = ParamLoader.ParamLoaderGetFloat((int)ParamType.Render_IPD_FLOAT);
}
else
{
projectionMatrix = Matrix4x4.Perspective(Camera.main.fieldOfView, Camera.main.aspect, 0.01f, 1000);
}
//Instantiate overlay cameras:
for (int i = 0; i < kBufferCount; i++)
{
renderTexturesL[i] = new RenderTexture((int)(Screen.width * renderScale), (int)(Screen.height * renderScale), 24, RenderTextureFormat.Default);
if (!renderTexturesL[i].IsCreated())
{
renderTexturesL[i].Create();
}
renderTexturesR[i] = new RenderTexture((int)(Screen.width * renderScale), (int)(Screen.height * renderScale), 24, RenderTextureFormat.Default);
if (!renderTexturesR[i].IsCreated())
{
renderTexturesR[i].Create();
}
}
GameObject overlayCamLGo = new GameObject("Overlay Camera L", new System.Type[] { typeof(Camera) });
GameObject overlayCamRGo = new GameObject("Overlay Camera R", new System.Type[] { typeof(Camera) });
overlayCamL = overlayCamLGo.GetComponent();
overlayCamL.clearFlags = CameraClearFlags.SolidColor;
overlayCamL.depth = this.depth;
overlayCamL.backgroundColor = new Color(0, 0, 0, 0);
overlayCamL.cullingMask = this.cullingMask;
overlayCamL.targetTexture = renderTexturesL[0];
overlayCamL.projectionMatrix = projectionMatrix;
overlayCamR = overlayCamRGo.GetComponent();
overlayCamR.clearFlags = CameraClearFlags.SolidColor;
overlayCamR.depth = this.depth;
overlayCamR.cullingMask = this.cullingMask;
overlayCamR.backgroundColor = new Color(0, 0, 0, 0);
overlayCamR.targetTexture = renderTexturesR[0];
overlayCamR.projectionMatrix = projectionMatrix;
overlayCamLGo.transform.SetParent(eyeTrans.transform, false);
overlayCamRGo.transform.SetParent(eyeTrans.transform, false);
overlayCamLGo.transform.localPosition = new Vector3(-ipd * 0.5f, 0, 0);
overlayCamRGo.transform.localPosition = new Vector3(ipd * 0.5f, 0, 0);
if (isAndroid)
{
XimmerseXR.OverlayRendering = true;
XimmerseXR.SetOverlayRendererTextureID(overlayCamL.targetTexture.GetNativeTexturePtr().ToInt32(), overlayCamR.targetTexture.GetNativeTexturePtr().ToInt32());
//StartCoroutine(swapFrame());
}
}
private void OnDisable()
{
EnableOverlayCameras(false);
}
private void OnEnable()
{
EnableOverlayCameras(true);
}
private void EnableOverlayCameras(bool enabled)
{
if (overlayCamL)
{
overlayCamL.enabled = enabled;
}
if (overlayCamR)
{
overlayCamR.enabled = enabled;
}
if (Application.platform == RuntimePlatform.Android)
XimmerseXR.OverlayRendering = enabled;
}
//private void OnDestroy()
//{
// // StopCoroutine(swapFrame());
//}
//IEnumerator swapFrame()
//{
// WaitForEndOfFrame eof = new WaitForEndOfFrame();
// while (true)
// {
// yield return eof;
// rtIndex = (rtIndex + 1) % kBufferCount;
// overlayCamL.targetTexture = this.renderTexturesL[rtIndex];
// overlayCamR.targetTexture = this.renderTexturesR[rtIndex];
// XimmerseXR.SetOverlayRendererTextureID(overlayCamL.targetTexture.GetNativeTexturePtr().ToInt32(), overlayCamR.targetTexture.GetNativeTexturePtr().ToInt32());
// }
//}
static Matrix4x4 GetPerspectiveProjectionMatrix(float left, float right, float bottom, float top, float near, float far)
{
float x = 2.0F * near / (right - left);
float y = 2.0F * near / (top - bottom);
float a = (right + left) / (right - left);
float b = (top + bottom) / (top - bottom);
float c = -(far + near) / (far - near);
float d = -(2.0F * far * near) / (far - near);
float e = -1.0F;
Matrix4x4 m = new Matrix4x4();
m[0, 0] = x;
m[0, 1] = 0;
m[0, 2] = a;
m[0, 3] = 0;
m[1, 0] = 0;
m[1, 1] = y;
m[1, 2] = b;
m[1, 3] = 0;
m[2, 0] = 0;
m[2, 1] = 0;
m[2, 2] = c;
m[2, 3] = d;
m[3, 0] = 0;
m[3, 1] = 0;
m[3, 2] = e;
m[3, 3] = 0;
return m;
}
///
/// 逐渐变透明
///
///
IEnumerator fadeIn(float time)
{
EnableOverlayCameras(true);
float st = Time.time;
while ((Time.time - st) <= time)
{
float _alpha = 1 - (Time.time - st / 1);
overlayBackgroundColor = new Color(0, 0, 0, _alpha);
// Debug.LogFormat("FadeIn setting overlay alpha: {0}", _alpha);
yield return null;
}
overlayBackgroundColor = new Color(0, 0, 0, 0);
EnableOverlayCameras(false);
}
///
/// 逐渐变黑
///
///
IEnumerator fadeOut(float time)
{
EnableOverlayCameras(true);
float st = Time.time;
while ((Time.time - st) <= time)
{
float _alpha = (Time.time - st) / time;
overlayBackgroundColor = new Color(0, 0, 0, _alpha);
// Debug.LogFormat("FadeOut setting overlay alpha: {0}", _alpha);
yield return null;
}
overlayBackgroundColor = new Color(0, 0, 0, 1);
EnableOverlayCameras(true);
}
}
}