Files
VIVE-OpenXR-Unity/com.htc.upm.vive.openxr/Runtime/CompositionLayer/Scripts/CompositionLayerUICanvas.cs
2023-09-14 18:17:47 +08:00

302 lines
9.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// "VIVE SDK
// © 2020 HTC Corporation. All Rights Reserved.
//
// Unless otherwise required by copyright law and practice,
// upon the execution of HTC SDK license agreement,
// HTC grants you access to and use of the VIVE SDK(s).
// You shall fully comply with all of HTCs SDK license agreement terms and
// conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You."
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
namespace VIVE.OpenXR.CompositionLayer
{
[RequireComponent(typeof(Canvas))]
public class CompositionLayerUICanvas : MonoBehaviour
{
private Canvas sourceCanvas;
private RectTransform sourceCanvasRectTransform;
private Graphic[] graphicComponents;
private Camera canvasRenderCamera;
private RenderTexture canvasRenderTexture;
private GameObject canvasCompositionLayerGO;
private CompositionLayer canvasCompositionLayer;
[SerializeField]
public uint maxRenderTextureSize = 1024;
[SerializeField]
public CompositionLayer.LayerType layerType = CompositionLayer.LayerType.Underlay;
[SerializeField]
public CompositionLayer.Visibility layerVisibility = CompositionLayer.Visibility.Both;
[SerializeField]
public Color cameraBGColor = Color.clear;
[SerializeField]
public List<GameObject> backgroundGO = new List<GameObject>();
[SerializeField]
public bool enableAlphaBlendingCorrection = false;
[SerializeField]
public uint compositionDepth = 0;
[SerializeField]
private uint renderPriority = 0;
public uint GetRenderPriority() { return renderPriority; }
public void SetRenderPriority(uint newRenderPriority)
{
renderPriority = newRenderPriority;
canvasCompositionLayer.SetRenderPriority(renderPriority);
}
[SerializeField]
public GameObject trackingOrigin = null;
private CompositionLayer.LayerType previousLayerType;
private CompositionLayer.Visibility previousLayerVisibility;
private uint previousCompositionDepth;
private GameObject previousTrackingOrigin;
private void Start()
{
sourceCanvas = GetComponent<Canvas>();
sourceCanvasRectTransform = sourceCanvas.GetComponent<RectTransform>();
UpdateUIElementBlendMode();
//Calulate Aspect Ratio of the Canvas
float canvasRectWidth = sourceCanvasRectTransform.rect.width;
float canvasRectHeight = sourceCanvasRectTransform.rect.height;
float canvasAspectRatio_X = 1, canvasAspectRatio_Y = 1;
if (canvasRectWidth > canvasRectHeight)
{
canvasAspectRatio_X = canvasRectWidth / canvasRectHeight;
}
else if (canvasRectWidth < canvasRectHeight)
{
canvasAspectRatio_Y = canvasRectHeight / canvasRectWidth;
}
//Create Render Texture
int renderTextureWidth = Mathf.CeilToInt(maxRenderTextureSize * canvasAspectRatio_X);
int renderTextureHeight = Mathf.CeilToInt(maxRenderTextureSize * canvasAspectRatio_Y);
canvasRenderTexture = new RenderTexture(renderTextureWidth, renderTextureHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
canvasRenderTexture.useMipMap = false;
canvasRenderTexture.filterMode = FilterMode.Bilinear;
canvasRenderTexture.autoGenerateMips = false;
canvasRenderTexture.Create();
//Create Canvas Rendering Camera
GameObject canvasRenderCameraGO = new GameObject(name + "_CanvasRenderCamera");
canvasRenderCameraGO.transform.SetParent(transform, false);
canvasRenderCamera = canvasRenderCameraGO.AddComponent<Camera>();
canvasRenderCamera.stereoTargetEye = StereoTargetEyeMask.None;
canvasRenderCamera.transform.position = transform.position - transform.forward; //1m away from canvas
canvasRenderCamera.orthographic = true;
canvasRenderCamera.enabled = false;
canvasRenderCamera.targetTexture = canvasRenderTexture;
canvasRenderCamera.cullingMask = 1 << gameObject.layer;
canvasRenderCamera.clearFlags = CameraClearFlags.SolidColor;
canvasRenderCamera.backgroundColor = cameraBGColor;
float widthWithScale = canvasRectWidth * sourceCanvasRectTransform.localScale.x;
float heightWithScale = canvasRectHeight * sourceCanvasRectTransform.localScale.y;
canvasRenderCamera.orthographicSize = 0.5f * heightWithScale;
canvasRenderCamera.nearClipPlane = 0.99f;
canvasRenderCamera.farClipPlane = 1.01f;
//Create Composition Layer Component
canvasCompositionLayerGO = new GameObject(name + "_CanvasCompositionLayer");
canvasCompositionLayerGO.transform.SetParent(transform, false);
canvasCompositionLayerGO.transform.localPosition = Vector3.zero;
canvasCompositionLayerGO.transform.localRotation = Quaternion.identity;
canvasCompositionLayerGO.transform.localScale = Vector3.one;
canvasCompositionLayer = canvasCompositionLayerGO.AddComponent<CompositionLayer>();
canvasCompositionLayer.isDynamicLayer = true;
canvasCompositionLayer.texture = canvasRenderTexture;
canvasCompositionLayer.layerShape = CompositionLayer.LayerShape.Quad;
canvasCompositionLayer.layerType = previousLayerType = layerType;
canvasCompositionLayer.layerVisibility = previousLayerVisibility = layerVisibility;
canvasCompositionLayer.SetQuadLayerHeight(heightWithScale);
canvasCompositionLayer.SetQuadLayerWidth(widthWithScale);
canvasCompositionLayer.compositionDepth = previousCompositionDepth = compositionDepth;
canvasCompositionLayer.SetRenderPriority(renderPriority);
canvasCompositionLayer.trackingOrigin = previousTrackingOrigin = trackingOrigin;
if (enableAlphaBlendingCorrection && layerType == CompositionLayer.LayerType.Underlay)
{
canvasCompositionLayer.ChangeBlitShadermode(CompositionLayer.BlitShaderMode.LINEAR_TO_SRGB_ALPHA, true);
}
else
{
canvasCompositionLayer.ChangeBlitShadermode(CompositionLayer.BlitShaderMode.LINEAR_TO_SRGB_ALPHA, false);
}
}
private void Update()
{
canvasRenderCamera.Render();
if (layerType != previousLayerType)
{
canvasCompositionLayer.layerType = previousLayerType = layerType;
if (enableAlphaBlendingCorrection && layerType == CompositionLayer.LayerType.Underlay)
{
canvasCompositionLayer.ChangeBlitShadermode(CompositionLayer.BlitShaderMode.LINEAR_TO_SRGB_ALPHA, true);
}
else
{
canvasCompositionLayer.ChangeBlitShadermode(CompositionLayer.BlitShaderMode.LINEAR_TO_SRGB_ALPHA, false);
}
}
if (layerVisibility != previousLayerVisibility)
{
canvasCompositionLayer.layerVisibility = previousLayerVisibility = layerVisibility;
}
if (compositionDepth != previousCompositionDepth)
{
canvasCompositionLayer.compositionDepth = previousCompositionDepth = compositionDepth;
}
if (trackingOrigin != previousTrackingOrigin)
{
canvasCompositionLayer.trackingOrigin = previousTrackingOrigin = trackingOrigin;
}
if (canvasRenderCamera.backgroundColor != cameraBGColor)
{
canvasRenderCamera.backgroundColor = cameraBGColor;
}
}
private void OnDestroy()
{
if (canvasRenderTexture != null && canvasRenderTexture.IsCreated())
{
canvasRenderTexture.Release();
Destroy(canvasRenderTexture);
}
if (canvasCompositionLayerGO)
{
Destroy(canvasCompositionLayerGO);
}
}
private void OnEnable()
{
if (canvasRenderCamera)
{
canvasRenderCamera.enabled = true;
}
if (canvasCompositionLayerGO)
{
canvasCompositionLayerGO.SetActive(true);
}
}
private void OnDisable()
{
if (canvasRenderCamera)
{
canvasRenderCamera.enabled = false;
}
if (canvasCompositionLayerGO)
{
canvasCompositionLayerGO.SetActive(false);
}
}
public void ReplaceUIMaterials()
{
sourceCanvas = GetComponent<Canvas>();
graphicComponents = sourceCanvas.GetComponentsInChildren<Graphic>();
Material underlayCanvasUIMat = new Material(Shader.Find("VIVE/OpenXR/CompositionLayerUICanvas/MultiLayerCanvasUI"));
foreach (Graphic graphicComponent in graphicComponents)
{
if (backgroundGO != null && backgroundGO.Contains(graphicComponent.gameObject))
{
graphicComponent.material = new Material(Shader.Find("VIVE/OpenXR/CompositionLayerUICanvas/MultiLayerCanvasUI")); //Seperate material instance for background
}
else
{
graphicComponent.material = underlayCanvasUIMat;
}
}
}
public void UpdateUIElementBlendMode()
{
sourceCanvas = GetComponent<Canvas>();
graphicComponents = sourceCanvas.GetComponentsInChildren<Graphic>();
foreach (Graphic graphicComponent in graphicComponents)
{
if (backgroundGO != null && backgroundGO.Contains(graphicComponent.gameObject))
{
SetUIShaderBlendMode(graphicComponent.material, UIShaderBlendMode.Background);
}
else
{
SetUIShaderBlendMode(graphicComponent.material, UIShaderBlendMode.Others);
}
}
}
public void SetUIShaderBlendMode(Material canvasUIMaterial, UIShaderBlendMode blendMode = UIShaderBlendMode.Others)
{
switch (blendMode)
{
case UIShaderBlendMode.Background: //Discard camera background color and alpha values
canvasUIMaterial.SetInt("_SrcColBlendMode", (int)BlendMode.One);
canvasUIMaterial.SetInt("_DstColBlendMode", (int)BlendMode.Zero);
canvasUIMaterial.SetInt("_SrcAlpBlendMode", (int)BlendMode.One);
canvasUIMaterial.SetInt("_DstAlpBlendMode", (int)BlendMode.Zero);
break;
case UIShaderBlendMode.Others: //Nornmal transparency blending
default:
canvasUIMaterial.SetInt("_SrcColBlendMode", (int)BlendMode.SrcAlpha);
canvasUIMaterial.SetInt("_DstColBlendMode", (int)BlendMode.OneMinusSrcAlpha);
canvasUIMaterial.SetInt("_SrcAlpBlendMode", (int)BlendMode.One);
canvasUIMaterial.SetInt("_DstAlpBlendMode", (int)BlendMode.OneMinusSrcAlpha);
break;
}
}
public enum UIShaderBlendMode
{
Background,
Others,
}
}
}