RKCanvasMeshRenderer.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. using UnityEngine;
  2. using UnityEngine.Assertions;
  3. using UnityEngine.Profiling;
  4. namespace Rokid.UXR.Interaction
  5. {
  6. using OverlayType = RKOverlay.OverlayType;
  7. using OverlayShape = RKOverlay.OverlayShape;
  8. public enum RKRenderingMode
  9. {
  10. [InspectorName("Alpha-Blended")]
  11. AlphaBlended = RenderingMode.AlphaBlended,
  12. [InspectorName("Alpha-Cutout")]
  13. AlphaCutout = RenderingMode.AlphaCutout,
  14. [InspectorName("Opaque")]
  15. Opaque = RenderingMode.Opaque,
  16. [InspectorName("RK/Overlay")]
  17. Overlay = 100,
  18. [InspectorName("RK/Underlay")]
  19. Underlay,
  20. }
  21. /// <summary>
  22. /// Uses <see cref="RKOverlay"/> to enable Underlay and Overlay
  23. /// rendering of a UI canvas.
  24. /// </summary>
  25. public class RKCanvasMeshRenderer : CanvasMeshRenderer
  26. {
  27. [SerializeField]
  28. protected CanvasMesh _canvasMesh;
  29. [Tooltip("If non-zero it will cause the position of the overlay to be offset by this amount at runtime, while " +
  30. "the renderer will remain where it was at edit time. This can be used to prevent the two representations from overlapping.")]
  31. [SerializeField]
  32. protected Vector3 _runtimeOffset = new Vector3(0, 0, 0);
  33. [Tooltip(
  34. "Uses a more expensive image sampling technique for improved quality at the cost of performance.")]
  35. [SerializeField]
  36. protected bool _enableSuperSampling = true;
  37. [Tooltip(
  38. "Attempts to anti-alias the edges of the underlay by using alpha blending. Can cause borders of " +
  39. "darkness around partially transparent objects.")]
  40. [SerializeField]
  41. private bool _doUnderlayAntiAliasing = false;
  42. private bool _emulateWhileInEditor = true;
  43. protected RKOverlay _overlay;
  44. private RKRenderingMode RenderingMode => (RKRenderingMode)_renderingMode;
  45. public bool ShouldUseOVROverlay
  46. {
  47. get
  48. {
  49. switch (RenderingMode)
  50. {
  51. case RKRenderingMode.Underlay:
  52. case RKRenderingMode.Overlay:
  53. return !UseEditorEmulation();
  54. default:
  55. return false;
  56. }
  57. }
  58. }
  59. protected override string GetShaderName()
  60. {
  61. switch (RenderingMode)
  62. {
  63. case RKRenderingMode.Overlay:
  64. return "Hidden/Imposter_AlphaCutout";
  65. case RKRenderingMode.Underlay:
  66. if (UseEditorEmulation())
  67. {
  68. return "Hidden/Imposter_AlphaCutout";
  69. }
  70. else if (_doUnderlayAntiAliasing)
  71. {
  72. return "Hidden/Imposter_Underlay_AA";
  73. }
  74. else
  75. {
  76. return "Hidden/Imposter_Underlay";
  77. }
  78. default:
  79. return base.GetShaderName();
  80. }
  81. }
  82. protected override float GetAlphaCutoutThreshold()
  83. {
  84. switch (RenderingMode)
  85. {
  86. case RKRenderingMode.Overlay:
  87. return 1f;
  88. case RKRenderingMode.Underlay:
  89. return UseEditorEmulation() ? 0.5f : 1f;
  90. default:
  91. return base.GetAlphaCutoutThreshold();
  92. }
  93. }
  94. protected override void HandleUpdateRenderTexture(Texture texture)
  95. {
  96. base.HandleUpdateRenderTexture(texture);
  97. UpdateOverlay(texture);
  98. }
  99. private bool UseEditorEmulation()
  100. {
  101. return Application.isEditor ? _emulateWhileInEditor : false;
  102. }
  103. private bool GetOverlayParameters(out OverlayShape shape,
  104. out Vector3 position,
  105. out Vector3 scale)
  106. {
  107. if (_canvasMesh is CanvasCylinder canvasCylinder)
  108. {
  109. shape = OverlayShape.Cylinder;
  110. Vector2Int resolution = _canvasRenderTexture.GetBaseResolutionToUse();
  111. position = new Vector3(0, 0, -canvasCylinder.Radius) - _runtimeOffset;
  112. scale = new Vector3(_canvasRenderTexture.PixelsToUnits(resolution.x) /
  113. canvasCylinder.transform.lossyScale.x,
  114. _canvasRenderTexture.PixelsToUnits(resolution.y) /
  115. canvasCylinder.transform.lossyScale.y,
  116. canvasCylinder.Radius);
  117. return true;
  118. }
  119. else if (_canvasMesh is CanvasRect canvasRect)
  120. {
  121. shape = OverlayShape.Quad;
  122. Vector2Int resolution = _canvasRenderTexture.GetBaseResolutionToUse();
  123. position = -_runtimeOffset;
  124. scale = new Vector3(_canvasRenderTexture.PixelsToUnits(resolution.x),
  125. _canvasRenderTexture.PixelsToUnits(resolution.y),
  126. 1);
  127. return true;
  128. }
  129. else // Unsupported
  130. {
  131. shape = OverlayShape.Quad;
  132. position = Vector3.zero;
  133. scale = Vector3.zero;
  134. return false;
  135. }
  136. }
  137. protected override void Start()
  138. {
  139. this.BeginStart(ref _started, () => base.Start());
  140. Assert.IsNotNull(_canvasMesh);
  141. Assert.IsTrue(GetOverlayParameters(out _, out _, out _),
  142. $"Unsupported {nameof(CanvasMesh)} type");
  143. this.EndStart(ref _started);
  144. }
  145. protected void UpdateOverlay(Texture texture)
  146. {
  147. Profiler.BeginSample("InterfaceRenderer.UpdateOverlay");
  148. try
  149. {
  150. if (!ShouldUseOVROverlay)
  151. {
  152. _overlay?.gameObject?.SetActive(false);
  153. return;
  154. }
  155. if (_overlay == null)
  156. {
  157. GameObject overlayObj = CreateChildObject("__Overlay");
  158. _overlay = overlayObj.AddComponent<RKOverlay>();
  159. _overlay.isAlphaPremultiplied = !Application.isMobilePlatform;
  160. }
  161. else
  162. {
  163. _overlay.gameObject.SetActive(true);
  164. }
  165. if (!GetOverlayParameters(out OverlayShape shape,
  166. out Vector3 pos,
  167. out Vector3 scale))
  168. {
  169. _overlay.gameObject.SetActive(false);
  170. return;
  171. }
  172. bool useUnderlayRendering = RenderingMode == RKRenderingMode.Underlay;
  173. _overlay.textures = new Texture[1] { texture };
  174. _overlay.noDepthBufferTesting = useUnderlayRendering;
  175. _overlay.currentOverlayType = useUnderlayRendering ? OverlayType.Underlay : OverlayType.Overlay;
  176. _overlay.currentOverlayShape = shape;
  177. _overlay.useExpensiveSuperSample = _enableSuperSampling;
  178. _overlay.transform.localPosition = pos;
  179. _overlay.transform.localScale = scale;
  180. }
  181. finally
  182. {
  183. Profiler.EndSample();
  184. }
  185. }
  186. protected GameObject CreateChildObject(string name)
  187. {
  188. GameObject obj = new GameObject(name);
  189. obj.transform.SetParent(transform);
  190. obj.transform.localPosition = Vector3.zero;
  191. obj.transform.localRotation = Quaternion.identity;
  192. obj.transform.localScale = Vector3.one;
  193. return obj;
  194. }
  195. public static new class Properties
  196. {
  197. public static readonly string CanvasRenderTexture = nameof(_canvasRenderTexture);
  198. public static readonly string CanvasMesh = nameof(_canvasMesh);
  199. public static readonly string EnableSuperSampling = nameof(_enableSuperSampling);
  200. public static readonly string EmulateWhileInEditor = nameof(_emulateWhileInEditor);
  201. public static readonly string DoUnderlayAntiAliasing = nameof(_doUnderlayAntiAliasing);
  202. public static readonly string RuntimeOffset = nameof(_runtimeOffset);
  203. }
  204. }
  205. }