VR4RoboticArm2/VR4RoboticArm/Library/PackageCache/com.meta.xr.sdk.interaction.ovr/Runtime/Scripts/UnityCanvas/OVRCanvasMeshRenderer.cs
IonutMocanu d7aba243a2 Main
2025-09-08 11:04:02 +03:00

274 lines
10 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using Meta.XR.Util;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Profiling;
using OverlayType = OVROverlay.OverlayType;
using OverlayShape = OVROverlay.OverlayShape;
namespace Oculus.Interaction.UnityCanvas
{
/// <summary>
/// Uses <see cref="OVROverlay"/> to enable Underlay and Overlay
/// rendering of a UI canvas.
/// </summary>
[Feature(Feature.Interaction)]
public class OVRCanvasMeshRenderer : CanvasMeshRenderer
{
[SerializeField]
protected CanvasMesh _canvasMesh;
[Tooltip("If non-zero it will cause the position of the overlay to be offset by this amount at runtime, while " +
"the renderer will remain where it was at edit time. This can be used to prevent the two representations from overlapping.")]
[SerializeField]
protected Vector3 _runtimeOffset = new Vector3(0, 0, 0);
[Tooltip(
"Uses a more expensive image sampling technique for improved quality at the cost of performance.")]
[SerializeField]
protected bool _enableSuperSampling = true;
[Tooltip(
"Attempts to anti-alias the edges of the underlay by using alpha blending. Can cause borders of " +
"darkness around partially transparent objects.")]
[SerializeField]
private bool _doUnderlayAntiAliasing = false;
[Tooltip(
"OVR Layers can provide a buggy or less ideal workflow while in the editor. This option allows you " +
"emulate the layer rendering while in the editor, while still using the OVR Layer rendering in a build.")]
[SerializeField]
private bool _emulateWhileInEditor = true;
protected OVROverlay _overlay;
private OVRRenderingMode RenderingMode => (OVRRenderingMode)_renderingMode;
public bool ShouldUseOVROverlay
{
get
{
switch (RenderingMode)
{
case OVRRenderingMode.Underlay:
case OVRRenderingMode.Overlay:
return !UseEditorEmulation();
default:
return false;
}
}
}
protected override string GetShaderName()
{
switch (RenderingMode)
{
case OVRRenderingMode.Overlay:
return "Hidden/Imposter_AlphaCutout";
case OVRRenderingMode.Underlay:
if (UseEditorEmulation())
{
return "Hidden/Imposter_AlphaCutout";
}
else if (_doUnderlayAntiAliasing)
{
return "Hidden/Imposter_Underlay_AA";
}
else
{
return "Hidden/Imposter_Underlay";
}
default:
return base.GetShaderName();
}
}
protected override float GetAlphaCutoutThreshold()
{
switch (RenderingMode)
{
case OVRRenderingMode.Overlay:
return 1f;
case OVRRenderingMode.Underlay:
return UseEditorEmulation() ? 0.5f : 1f;
default:
return base.GetAlphaCutoutThreshold();
}
}
protected override void HandleUpdateRenderTexture(Texture texture)
{
base.HandleUpdateRenderTexture(texture);
UpdateOverlay(texture);
}
private bool UseEditorEmulation()
{
return Application.isEditor ? _emulateWhileInEditor : false;
}
private bool GetOverlayParameters(out OverlayShape shape,
out Vector3 position,
out Vector3 scale)
{
if (_canvasMesh is CanvasCylinder canvasCylinder)
{
shape = OverlayShape.Cylinder;
Vector2Int resolution = _canvasRenderTexture.GetBaseResolutionToUse();
position = new Vector3(0, 0, -canvasCylinder.Radius) - _runtimeOffset;
scale = new Vector3(_canvasRenderTexture.PixelsToUnits(resolution.x) /
canvasCylinder.transform.lossyScale.x,
_canvasRenderTexture.PixelsToUnits(resolution.y) /
canvasCylinder.transform.lossyScale.y,
canvasCylinder.Radius);
return true;
}
else if (_canvasMesh is CanvasRect canvasRect)
{
shape = OverlayShape.Quad;
Vector2Int resolution = _canvasRenderTexture.GetBaseResolutionToUse();
position = -_runtimeOffset;
scale = new Vector3(_canvasRenderTexture.PixelsToUnits(resolution.x),
_canvasRenderTexture.PixelsToUnits(resolution.y),
1);
return true;
}
else // Unsupported
{
shape = OverlayShape.Quad;
position = Vector3.zero;
scale = Vector3.zero;
return false;
}
}
protected override void Start()
{
this.BeginStart(ref _started, () => base.Start());
this.AssertField(_canvasMesh, nameof(_canvasMesh));
Assert.IsTrue(GetOverlayParameters(out _, out _, out _),
$"Unsupported {nameof(CanvasMesh)} type");
this.EndStart(ref _started);
}
protected void UpdateOverlay(Texture texture)
{
Profiler.BeginSample("InterfaceRenderer.UpdateOverlay");
try
{
if (!ShouldUseOVROverlay)
{
_overlay?.gameObject?.SetActive(false);
return;
}
if (_overlay == null)
{
GameObject overlayObj = CreateChildObject("__Overlay");
_overlay = overlayObj.AddComponent<OVROverlay>();
_overlay.isAlphaPremultiplied = !Application.isMobilePlatform;
}
else
{
_overlay.gameObject.SetActive(true);
}
if (!GetOverlayParameters(out OverlayShape shape,
out Vector3 pos,
out Vector3 scale))
{
_overlay.gameObject.SetActive(false);
return;
}
bool useUnderlayRendering = RenderingMode == OVRRenderingMode.Underlay;
_overlay.textures = new Texture[1] { texture };
_overlay.noDepthBufferTesting = useUnderlayRendering;
_overlay.currentOverlayType = useUnderlayRendering ? OverlayType.Underlay : OverlayType.Overlay;
_overlay.currentOverlayShape = shape;
_overlay.useExpensiveSuperSample = _enableSuperSampling;
_overlay.transform.localPosition = pos;
_overlay.transform.localScale = scale;
}
finally
{
Profiler.EndSample();
}
}
protected GameObject CreateChildObject(string name)
{
GameObject obj = new GameObject(name);
obj.transform.SetParent(transform);
obj.transform.localPosition = Vector3.zero;
obj.transform.localRotation = Quaternion.identity;
obj.transform.localScale = Vector3.one;
return obj;
}
public static new class Properties
{
public static readonly string CanvasRenderTexture = nameof(_canvasRenderTexture);
public static readonly string CanvasMesh = nameof(_canvasMesh);
public static readonly string EnableSuperSampling = nameof(_enableSuperSampling);
public static readonly string EmulateWhileInEditor = nameof(_emulateWhileInEditor);
public static readonly string DoUnderlayAntiAliasing = nameof(_doUnderlayAntiAliasing);
public static readonly string RuntimeOffset = nameof(_runtimeOffset);
}
#region Inject
public void InjectAllOVRCanvasMeshRenderer(CanvasRenderTexture canvasRenderTexture,
MeshRenderer meshRenderer,
CanvasMesh canvasMesh)
{
InjectAllCanvasMeshRenderer(canvasRenderTexture, meshRenderer);
InjectCanvasMesh(canvasMesh);
}
public void InjectCanvasMesh(CanvasMesh canvasMesh)
{
_canvasMesh = canvasMesh;
}
public void InjectOptionalRenderingMode(OVRRenderingMode ovrRenderingMode)
{
_renderingMode = (int)ovrRenderingMode;
}
public void InjectOptionalDoUnderlayAntiAliasing(bool doUnderlayAntiAliasing)
{
_doUnderlayAntiAliasing = doUnderlayAntiAliasing;
}
public void InjectOptionalEnableSuperSampling(bool enableSuperSampling)
{
_enableSuperSampling = enableSuperSampling;
}
#endregion
}
}