Tilt Five™ Unity API  1.4.1
SplitStereoCamera.cs
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020-2023 Tilt Five, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 using System.Collections;
18 using System.Collections.Generic;
19 using UnityEngine;
20 using TiltFive.Logging;
21 
22 #if TILT_FIVE_SRP
23 using UnityEngine.Rendering;
24 #endif
25 
27 
28 namespace TiltFive
29 {
30 
34  [System.Serializable]
35  public class DisplaySettings
36  {
37  private static DisplaySettings instance;
38  private static DisplaySettings Instance
39  {
40  get
41  {
42  if(instance == null)
43  {
44  instance = new DisplaySettings();
45  }
46  return instance;
47  }
48  set => instance = value;
49  }
50 
51  private DisplaySettings()
52  {
54  {
55  Log.Warn("Could not retrieve display settings from the plugin.");
56  }
57  }
58 
60  public static int monoWidth => (stereoWidth / 2);
62  public static int stereoWidth => Instance.defaultDimensions.x;
64  public static int height => Instance.defaultDimensions.y;
66  public static float monoWidthToHeightRatio => (float) monoWidth / height;
68  public static float stereoWidthToHeightRatio => (float) stereoWidth / height;
70  public const int depthBuffer = 24;
71 
72  // Provide a texture format compatible with the glasses.
73  public const RenderTextureFormat nativeTextureFormat = RenderTextureFormat.ARGB32;
74 
75  // Provide a hardcoded default resolution if the plugin is somehow unavailable.
76  private readonly Vector2Int defaultDimensions = new Vector2Int(2432, 768);
77  }
78 
79  [RequireComponent(typeof(Camera))]
80  public partial class SplitStereoCamera : MonoBehaviour
81  {
82  [HideInInspector]
83  internal GlassesHandle glassesHandle;
84 
85  internal SpectatorSettings spectatorSettings = null;
86  private Camera spectatorCamera => spectatorSettings?.spectatorCamera;
87 
88  internal GlassesSettings glassesSettings = null;
90  public Camera cameraTemplate => glassesSettings?.cameraTemplate;
92  public GameObject headPose = null;
93  private bool useSpectatorCamera;
94  internal bool UseSpectatorCamera
95  {
96  get => useSpectatorCamera;
97  set
98  {
99  if (useSpectatorCamera != value)
100  {
101  // If we set a new value here, force the letterboxing/pillarboxing to be redrawn.
103  }
104  useSpectatorCamera = value;
105  }
106  }
107  private bool startedMirroringToOnscreenPreview = false;
108 
109  private IEnumerator presentStereoImagesCoroutine;
110 
112  private const string LEFT_EYE_CAMERA_NAME = "Left Eye Camera";
114  private GameObject leftEye;
116  public Camera leftEyeCamera { get { return eyeCameras[AREyes.EYE_LEFT]; } }
117 
119  private const string RIGHT_EYE_CAMERA_NAME = "Right Eye Camera";
121  private GameObject rightEye;
123  public Camera rightEyeCamera { get { return eyeCameras[AREyes.EYE_RIGHT]; } }
124 
126  public bool showCameras = true;
128  private Dictionary<AREyes, Camera> eyeCameras = new Dictionary<AREyes, Camera>()
129  {
130  { AREyes.EYE_LEFT, null },
131  { AREyes.EYE_RIGHT, null }
132  };
133 
138  public Vector3 posUGBD_UWRLD = Vector3.zero;
139 
144  public Quaternion rotToUGBD_UWRLD = Quaternion.identity;
145 
150  public float scaleToUGBD_UWRLD = 1.0f;
151 
153  private const string SHADER_DISPLAY_BLIT = "Tilt Five/Simple Blend Shader";
155  private Material displayBlitShader;
156 
160 
161 #if TILT_FIVE_SRP
162  private CommandBuffer commandBuffer;
163 #endif
164 
166  [System.Obsolete("fieldOfView is deprecated, please use GlassesSettings' fieldOfView instead.")]
167  public float fieldOfView
168  {
169  get { return spectatorCamera.fieldOfView; }
170  set { rightEyeCamera.fieldOfView = leftEyeCamera.fieldOfView = spectatorCamera.fieldOfView = value; }
171  }
172 
174  [System.Obsolete("nearClipPlane is deprecated, please use GlassesSettings' nearClipPlane instead.")]
175  public float nearClipPlane
176  {
177  get { return spectatorCamera.nearClipPlane; }
178  set { rightEyeCamera.nearClipPlane = leftEyeCamera.nearClipPlane = spectatorCamera.nearClipPlane = value; }
179  }
180 
182  [System.Obsolete("farClipPlane is deprecated, please use GlassesSettings' farClipPlane instead.")]
183  public float farClipPlane
184  {
185  get { return spectatorCamera.farClipPlane; }
186  set { rightEyeCamera.farClipPlane = leftEyeCamera.farClipPlane = spectatorCamera.farClipPlane = value; }
187  }
188 
190  [System.Obsolete("aspectRatio is deprecated, please use DisplaySettings.monoWidthToHeightRatio instead.")]
191  public float aspectRatio
192  {
193  get { return spectatorCamera.aspect; }
194  set { spectatorCamera.aspect = value; }
195  }
196 
200  private void Awake()
201  {
202  enabled = false;
203  useSpectatorCamera = false;
205  }
206 
207  public void Initialize(GameObject headPoseRoot, GlassesSettings glassesSettings, SpectatorSettings spectatorSettings)
208  {
209  if(headPoseRoot == null || spectatorSettings == null)
210  {
211  Log.Error("Arguments cannot be null");
212  return;
213  }
214 
215  headPose = headPoseRoot;
216  this.glassesSettings = glassesSettings;
217  this.spectatorSettings = spectatorSettings;
218 
219 #if TILT_FIVE_SRP
220  commandBuffer = new CommandBuffer() { name = "Onscreen Preview" };
221 #endif
222 
223  // For this mode, we need the headPose Camera to be enabled, as it is the
224  // primary Camera for blitting to the backbuffer.
225  if(spectatorCamera != null)
226  {
227  spectatorCamera.enabled = true;
228  }
229 
230  if(cameraTemplate != null)
231  {
233  }
234  else
235  {
237  }
239 
240  // Load the blitting shader to copy the the left & right render textures
241  // into the backbuffer
242  displayBlitShader = new Material(Shader.Find(SHADER_DISPLAY_BLIT));
243  // Did we find it?
244  if (null == displayBlitShader)
245  {
246  Log.Error("Failed to load Shader '{0}'", SHADER_DISPLAY_BLIT);
247  }
248 
249  SyncFields();
250  SyncTransform();
251  ShowHideCameras();
252 
253  enabled = true;
254  }
255 
256  private void InstantiateEyeCameras(out GameObject leftEye, out GameObject rightEye)
257  {
258  var cloneCameraTemplateChildren = glassesSettings.cloneCameraTemplateChildren;
259 
260  // When we clone the head pose camera using Instantiate, we may not want to clone its children.
261  // If this is the case, detach the children and reparent them under a placeholder/babysitter GameObject
262  GameObject placeholder = cloneCameraTemplateChildren ? null : new GameObject("Placeholder");
263  if (!cloneCameraTemplateChildren)
264  {
265  placeholder.transform.parent = headPose.transform.parent;
266  while (cameraTemplate.transform.childCount > 0)
267  {
268  cameraTemplate.transform.GetChild(0).parent = placeholder.transform;
269  }
270  }
271 
272  // Instantiate left and right eye cameras from the camera template.
273  leftEye = Instantiate(cameraTemplate.gameObject, headPose.transform.position, headPose.transform.rotation, headPose.transform);
275  eyeCameras[AREyes.EYE_LEFT] = leftEye.GetComponent<Camera>();
276 
277  rightEye = Instantiate(cameraTemplate.gameObject, headPose.transform.position, headPose.transform.rotation, headPose.transform);
279  eyeCameras[AREyes.EYE_RIGHT] = rightEye.GetComponent<Camera>();
280 
281  var splitStereoCamerasLeft = leftEye.GetComponents<SplitStereoCamera>();
282  for (int i = 0; i < splitStereoCamerasLeft.Length; i++)
283  {
284  Destroy(splitStereoCamerasLeft[i]);
285  }
286 
287  var splitStereoCamerasRight = rightEye.GetComponents<SplitStereoCamera>();
288  for (int i = 0; i < splitStereoCamerasRight.Length; i++)
289  {
290  Destroy(splitStereoCamerasRight[i]);
291  }
292 
293 
294  if (!cloneCameraTemplateChildren)
295  {
296  // Reclaim the head pose camera's children from the placeholder/babysitter GameObject
297  while (placeholder.transform.childCount > 0)
298  {
299  placeholder.transform.GetChild(0).parent = cameraTemplate.transform;
300  }
301  Destroy(placeholder);
302  }
303  }
304 
305  private void GenerateEyeCameras(out GameObject leftEye, out GameObject rightEye)
306  {
307  leftEye = new GameObject(LEFT_EYE_CAMERA_NAME, typeof(Camera));
308  rightEye = new GameObject(RIGHT_EYE_CAMERA_NAME, typeof(Camera));
309 
310  eyeCameras[AREyes.EYE_LEFT] = leftEye.GetComponent<Camera>();
311  eyeCameras[AREyes.EYE_RIGHT] = rightEye.GetComponent<Camera>();
312 
313  leftEye.transform.parent = headPose.transform;
314  rightEye.transform.parent = headPose.transform;
315 
316  leftEye.transform.SetPositionAndRotation(headPose.transform.position, headPose.transform.rotation);
317  rightEye.transform.SetPositionAndRotation(headPose.transform.position, headPose.transform.rotation);
318  }
319 
320  private void ConfigureEyeCameras()
321  {
322  // Use the head pose camera's preferred texture format, rather than forcing it to render in LDR
324 
325  // Configure the left eye camera's render target
326  RenderTexture leftTex = splitStereoTextures.LeftTexture_GLS;
327  if (leftEyeCamera.allowMSAA && QualitySettings.antiAliasing > 1)
328  {
329  leftTex.antiAliasing = QualitySettings.antiAliasing;
330 
331  // Ensure that the preview textures' antiAliasing settings match.
332  // Otherwise, Unity 2020.3 complains during Graphics.CopyTexture about the mismatch,
333  // resulting in a broken onscreen preview (manifesting as a black screen).
334  splitStereoTextures.MonoPreviewTex.antiAliasing = QualitySettings.antiAliasing;
335  splitStereoTextures.StereoPreviewTex.antiAliasing = QualitySettings.antiAliasing;
336  }
337 
338  leftEyeCamera.targetTexture = leftTex;
339  leftEyeCamera.depth = spectatorCamera.depth - 1;
340 
341  // Configure the right eye camera's render target
342  RenderTexture rightTex = splitStereoTextures.RightTexture_GLS;
343  if (rightEyeCamera.allowMSAA && QualitySettings.antiAliasing > 1)
344  {
345  rightTex.antiAliasing = QualitySettings.antiAliasing;
346  }
347 
348  rightEyeCamera.targetTexture = rightTex;
349  rightEyeCamera.depth = spectatorCamera.depth - 1;
350  }
351 
357  {
358 
359 #if UNITY_EDITOR
360  // We move the eye Cameras in the Editor to emulate head pose and eye movement.
361  // In builds, we only set the camera transforms with Glasses tracking data.
362 
363  if (null == cameraTemplate || !Player.TryGetPlayerIndex(glassesHandle, out PlayerIndex playerIndex))
364  return;
365 
366  if (!Glasses.IsTracked(playerIndex))
367  {
368  GameObject pose = headPose;
369  // left eye copy and adjust
370  leftEye.transform.position = pose.transform.position;
371  leftEye.transform.localPosition = pose.transform.localPosition;
372  leftEye.transform.rotation = pose.transform.rotation;
373  leftEye.transform.localRotation = pose.transform.localRotation;
374  leftEye.transform.localScale = pose.transform.localScale;
375  leftEye.transform.Translate(-leftEye.transform.right.normalized * (cameraTemplate.stereoSeparation * 0.5f));
376 
377  //right eye copy and adjust
378  rightEye.transform.position = pose.transform.position;
379  rightEye.transform.localPosition = pose.transform.localPosition;
380  rightEye.transform.rotation = pose.transform.rotation;
381  rightEye.transform.localRotation = pose.transform.localRotation;
382  rightEye.transform.localScale = headPose.transform.localScale;
383  rightEye.transform.Translate(rightEye.transform.right.normalized * (cameraTemplate.stereoSeparation * 0.5f));
384  }
385 #endif
386  }
387 
388  void OnEnable()
389  {
390  leftEye.SetActive(true);
391  rightEye.SetActive(true);
392  leftEyeCamera.enabled = true;
393  rightEyeCamera.enabled = true;
395  StartCoroutine(presentStereoImagesCoroutine);
396 
397 #if TILT_FIVE_SRP
398  if(Application.isPlaying)
399  {
400  RenderPipelineManager.beginFrameRendering += OnBeginFrameRendering;
401  RenderPipelineManager.endFrameRendering += OnEndFrameRendering;
402  }
403 #endif
404  }
405 
406  private void OnDisable()
407  {
409  {
411  // If OnDisable() is being called from Destroy(), then the children may no longer
412  // exist. Check before acting on them.
413  if (leftEye)
414  {
415  leftEye.SetActive(false);
416  leftEyeCamera.enabled = false;
417  }
418  if (rightEye)
419  {
420  rightEye.SetActive(false);
421  rightEyeCamera.enabled = false;
422  }
423  }
424 
425  if(presentStereoImagesCoroutine != null)
426  {
427  StopCoroutine(presentStereoImagesCoroutine);
428  }
429 #if TILT_FIVE_SRP
430  RenderPipelineManager.beginFrameRendering -= OnBeginFrameRendering;
431  RenderPipelineManager.endFrameRendering -= OnEndFrameRendering;
432 #endif
433  }
434 
435 #if TILT_FIVE_SRP
440  private void OnBeginFrameRendering(ScriptableRenderContext context, Camera[] cameras)
441  {
442  // TODO: Determine whether this is necessary, or even permitted; the docs on RenderTexture.IsCreated() are lacking.
443  // We want to check for invalidated render textures before rendering,
444  // and this event should occur at the beginning of RenderPipeline.Render
445  // before any actual render passes occur, so in principle this should work as a substitute for OnPreRender.
446 
447  // Check whether the left/right render textures' states have been invalidated,
448  // and reset the cached texture handles if so. See the longer explanation below in Update()
450  }
451 #endif
452 
456  void OnPreRender()
457  {
459 
460  if(!UseSpectatorCamera)
461  {
462  return;
463  }
464 
465  spectatorCamera.targetTexture = null;
466 
467  /* If the screen mirror mode changes, junk data will be displayed
468  * in the black bars unless we clear the screen buffer.
469  *
470  * This has to be done before we adjust the headpose camera rect,
471  * since GL.Clear's effect is limited by the active viewport.
472  *
473  * We also must ensure that we call GL.Clear once as soon as we begin mirroring to the screen.
474  * See Gerrit #3013 for additional detail, but in short, there's an implicit mirror mode transition
475  * at the moment we begin mirroring to the onscreen preview that isn't captured by comparing
476  * glassesMirrorMode against previousMirrorMode, and if we don't check for it using the
477  * startedMirroringToOnscreenPreview flag, junk data could fill the letterboxing/pillarboxing.*/
479  {
480  // Before calling GL.Clear(), we need to reset the viewport.
481  // Otherwise, we may not clear the entire screen in some cases.
482  GL.Viewport(spectatorCamera.pixelRect);
483  GL.Clear(true, true, Color.black);
486  }
487 
489  {
490  return;
491  }
492 
493  spectatorCamera.cullingMask = 0; // Cull all layers, render nothing.
494  spectatorCamera.fieldOfView = glassesSettings.fieldOfView;
495  spectatorCamera.nearClipPlane = glassesSettings.nearClipPlane / scaleToUGBD_UWRLD;
496  spectatorCamera.farClipPlane = glassesSettings.farClipPlane / scaleToUGBD_UWRLD;
497 
498  // Lock the aspect ratio and add pillarboxing/letterboxing as needed.
499  float screenRatio = Screen.width / (float)Screen.height;
500  float targetRatio = glassesMirrorMode == GlassesMirrorMode.Stereoscopic
503 
504  if(screenRatio > targetRatio) {
505  // Screen or window is wider than the target: pillarbox.
506  float normalizedWidth = targetRatio / screenRatio;
507  float barThickness = (1f - normalizedWidth) / 2f;
508  spectatorCamera.rect = new Rect(barThickness, 0, normalizedWidth, 1);
509  }
510  else {
511  // Screen or window is narrower than the target: letterbox.
512  float normalizedHeight = screenRatio / targetRatio;
513  float barThickness = (1f - normalizedHeight) / 2f;
514  spectatorCamera.rect = new Rect(0, barThickness, 1, normalizedHeight);
515  }
516  }
517 
518 
519 #if TILT_FIVE_SRP
526  void OnEndFrameRendering(ScriptableRenderContext context, Camera[] cameras)
527  {
528  if (this == null || !enabled || glassesMirrorMode == GlassesMirrorMode.None || !UseSpectatorCamera)
529  {
530  spectatorCamera.rect = spectatorSettings.rect;
531  return;
532  }
533 
534  // OnEndFrameRendering isn't picky about the camera(s) that finished rendering.
535  // This includes the scene view and/or material preview cameras.
536  // We need to make sure we only run the code in this function when we're performing stereoscopic rendering.
537  bool currentlyRenderingEyeCameras = false;
538 
539  for (int i = 0; i < cameras.Length; i++)
540  {
541 #if UNITY_EDITOR
542  if (cameras[i].Equals(UnityEditor.SceneView.lastActiveSceneView.camera))
543  {
544  return;
545  }
546 #endif
547  if (cameras[i].Equals(leftEyeCamera) || cameras[i].Equals(rightEyeCamera) || cameras[i].Equals(spectatorCamera))
548  {
549  currentlyRenderingEyeCameras = true;
550  }
551  }
552  if (!currentlyRenderingEyeCameras)
553  {
554  return;
555  }
556 
557  // Determine the aspect ratio to enable pillarboxing/letterboxing.
558  float screenRatio = Screen.width / (float)Screen.height;
559  float targetRatio = glassesMirrorMode == GlassesMirrorMode.Stereoscopic
560  ? DisplaySettings.stereoWidthToHeightRatio
561  : DisplaySettings.monoWidthToHeightRatio;
562  Vector2 frameScale = Vector2.one;
563 
564  if (screenRatio != targetRatio)
565  {
566  frameScale = screenRatio > targetRatio
567  ? new Vector2(screenRatio / targetRatio, 1f)
568  : new Vector2(1f, targetRatio / screenRatio);
569  }
570 
571  splitStereoTextures.SubmitPreviewTexturesSRP(glassesMirrorMode, spectatorCamera, commandBuffer, frameScale);
572 
573  context.ExecuteCommandBuffer(commandBuffer);
574  context.Submit();
575  commandBuffer.Clear();
576 
577  spectatorSettings.ResetSpectatorCamera();
578  }
579 #endif
580 
587  void OnRenderImage(RenderTexture src, RenderTexture dst)
588  {
589  // If we're not supposed to spectate due to the spectated player being set to None
590  // or to a player that isn't connected, have the first SplitStereoCamera attached to
591  // the SpectatorCamera perform a blit.
592  // TODO: Consider adding a spectator setting to define fallback behavior when the specified player isn't connected.
593  // The current behavior is indistinguishable from the PlayerIndex.None case, and perhaps it'd be desirable
594  // to spectate the next available player instead, if there is one?
595  if (spectatorSettings.spectatedPlayer == PlayerIndex.None || !Player.IsConnected(spectatorSettings.spectatedPlayer))
596  {
597  var splitStereoCameras = spectatorCamera.GetComponents<SplitStereoCamera>();
598  if(splitStereoCameras != null && splitStereoCameras.Length > 0 // These two checks should be redundant
599  && splitStereoCameras[0].Equals(this)) // This is the important one
600  {
601  Graphics.Blit(src, null as RenderTexture);
602  return;
603  }
604  // Any SplitStereoCameras that call OnRenderImage after the first one should return, otherwise they'll clear the screen
605  return;
606  }
607 
608  if(!UseSpectatorCamera)
609  {
610  return;
611  }
612 
614  {
616 
617  var previewTex = glassesMirrorMode == GlassesMirrorMode.Stereoscopic
620 
621  // Blitting is required when overriding OnRenderImage().
622  // Setting the blit destination to null is the same as blitting to the screen backbuffer.
623  // This will effectively render previewTex to the screen.
624  Graphics.Blit(previewTex,
625  null as RenderTexture,
626  Vector2.one,
627  Vector2.zero);
628  }
629  else Graphics.Blit(src, null as RenderTexture);
630 
631  // We're done with our letterboxing/pillarboxing now that we've blitted to the screen.
632  // If the SplitStereoCamera gets disabled next frame, ensure that the original behavior returns.
633  spectatorSettings.ResetSpectatorCamera();
634  }
635 
637  {
638  // WaitForEndOfFrame() will let us wait until the last possible moment to send frames to the glasses.
639  // This allows the results of rendering, postprocessing, and even GUI to be displayed.
640  var cachedWaitForEndOfFrame = new WaitForEndOfFrame();
641 
642  while (enabled)
643  {
644  yield return cachedWaitForEndOfFrame;
645 
647  }
648  }
649 
650  private void PresentStereoImages()
651  {
652  splitStereoTextures.GetNativeTexturePointers(out var leftTexHandle, out var rightTexHandle);
653 
654  var leftTargetTex = splitStereoTextures.LeftTexture_GLS;
655  var rightTargetTex = splitStereoTextures.RightTexture_GLS;
656 
657  bool isSrgb = leftTargetTex.sRGB;
658 
659  Vector3 posOfULVC_UWRLD = leftEyeCamera.transform.position;
660  Quaternion rotToUWRLD_ULVC = leftEyeCamera.transform.rotation;
661  Vector3 posOfURVC_UWRLD = rightEyeCamera.transform.position;
662  Quaternion rotToUWRLD_URVC = rightEyeCamera.transform.rotation;
663 
664  Vector3 posOfULVC_UGBD = rotToUGBD_UWRLD * (scaleToUGBD_UWRLD * (posOfULVC_UWRLD - posUGBD_UWRLD));
665  Quaternion rotToUGBD_ULVC = rotToUGBD_UWRLD * rotToUWRLD_ULVC;
666 
667  Vector3 posOfURVC_UGBD = rotToUGBD_UWRLD * (scaleToUGBD_UWRLD * (posOfURVC_UWRLD - posUGBD_UWRLD));
668  Quaternion rotToUGBD_URVC = rotToUGBD_UWRLD * rotToUWRLD_URVC;
669 
670 
671  Display.PresentStereoImages(glassesHandle,
672  leftTexHandle, rightTexHandle,
673  leftTargetTex.width, rightTargetTex.height,
674  isSrgb,
675  glassesSettings.fieldOfView,
677  rotToUGBD_ULVC,
678  posOfULVC_UGBD,
679  rotToUGBD_URVC,
680  posOfURVC_UGBD);
681  }
682 
686  private void SyncFields()
687  {
688  if (glassesSettings == null)
689  {
690  return;
691  }
692  if (leftEyeCamera != null)
693  {
694  leftEyeCamera.fieldOfView = glassesSettings.fieldOfView;
695  leftEyeCamera.nearClipPlane = glassesSettings.nearClipPlane;
696  leftEyeCamera.farClipPlane = glassesSettings.farClipPlane;
698  }
699  if (rightEyeCamera != null)
700  {
701  rightEyeCamera.fieldOfView = glassesSettings.fieldOfView;
702  rightEyeCamera.nearClipPlane = glassesSettings.nearClipPlane;
703  rightEyeCamera.farClipPlane = glassesSettings.farClipPlane;
705  }
706  }
707 
711  void OnValidate()
712  {
713 
714 #if UNITY_EDITOR
715  if (false == UnityEditor.EditorApplication.isPlaying)
716  return;
717 #endif
718  if (null == spectatorCamera)
719  return;
720 
721  if (null != leftEye && null != rightEye)
722  ShowHideCameras();
723 
724  SyncFields();
725  SyncTransform();
726  }
727 
732  {
733  if (showCameras)
734  {
735  leftEye.hideFlags = HideFlags.None;
736  rightEye.hideFlags = HideFlags.None;
737  }
738  else
739  {
740  leftEye.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
741  rightEye.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
742  }
743  }
744  }
745 }
TiltFive.Glasses.AREyes AREyes
static bool GetDisplayDimensions(ref Vector2Int displayDimensions)
Definition: Display.cs:326
static bool PresentStereoImages(PlayerIndex playerIndex, IntPtr leftTexHandle, IntPtr rightTexHandle, int texWidth_PIX, int texHeight_PIX, bool isSrgb, float fovYDegrees, float widthToHeightRatio, Quaternion rotToUGBD_ULVC, Vector3 posOfULVC_UGBD, Quaternion rotToUGBD_URVC, Vector3 posOfURVC_UGBD)
Definition: Display.cs:150
Display settings constants.
readonly Vector2Int defaultDimensions
static float monoWidthToHeightRatio
The display aspect ratio.
const RenderTextureFormat nativeTextureFormat
static int monoWidth
The display width for a single eye.
static float stereoWidthToHeightRatio
The double-width display aspect ratio.
static DisplaySettings Instance
static int height
The display height.
const int depthBuffer
The depth buffer's precision.
static DisplaySettings instance
static int stereoWidth
The display width for two eyes.
The Glasses API and runtime.
Definition: Glasses.cs:35
static bool IsTracked(PlayerIndex playerIndex=PlayerIndex.One)
Indicate if the specified glasses are tracked.
Definition: Glasses.cs:142
GlassesSettings encapsulates all configuration data used by the Glasses' tracking runtime to compute ...
Camera cameraTemplate
The camera used as a template for creating the eye cameras at runtime.
float farClipPlane
The far clip plane in physical space (meters), to adjust for content scale and gameboard size
float nearClipPlane
The near clip plane in physical space (meters), to adjust for content scale and gameboard size
bool cloneCameraTemplateChildren
Whether or not the camera template's child gameobjects should be cloned during eye camera instantiati...
The Logger.
Definition: Log.cs:42
static void Warn(string m, params object[] list)
WARN logging function call.
Definition: Log.cs:166
static void Error(string m, params object[] list)
ERROR logging function call.
Definition: Log.cs:127
Provides access to player settings and functionality.
Definition: Player.cs:31
static bool IsConnected(PlayerIndex playerIndex)
Determines whether the specified player has an associated pair of glasses connected.
Definition: Player.cs:48
PlayerIndex spectatedPlayer
The player that will have their perspective mirrored on screen.
Rect rect
The viewport rect used by the Spectator Camera.
GlassesMirrorMode glassesMirrorMode
The spectator camera will display content on screen depending on the mirroring mode....
Camera spectatorCamera
The camera used for rendering the onscreen preview
float nearClipPlane
The Cameras' near clip plane property.
bool showCameras
In-editor toggle for displaying the eye cameras in the runtime Hierarchy.
void SyncTransform()
EDITOR-ONLY: Syncs the eye Cameras' transform to the Head Pose when tracking is not available.
float aspectRatio
The Cameras' aspect ratio property.
const string RIGHT_EYE_CAMERA_NAME
The name assigned to the dynamically created camera used for rendering the right eye.
void Initialize(GameObject headPoseRoot, GlassesSettings glassesSettings, SpectatorSettings spectatorSettings)
float farClipPlane
The Cameras' far clip plane property.
void OnPreRender()
Configure rendering parameters for the upcoming frame.
GameObject rightEye
The right eye camera GameObject.
void SyncFields()
Syncs the Cameras' fields to the settings.
Quaternion rotToUGBD_UWRLD
The rotation taking points from the Unity world-space reference frame to the game board reference fra...
void InstantiateEyeCameras(out GameObject leftEye, out GameObject rightEye)
void Awake()
Awake this instance.
Camera leftEyeCamera
The left eye Camera property.
SplitStereoTextures splitStereoTextures
IEnumerator PresentStereoImagesCoroutine()
GlassesMirrorMode previousMirrorMode
GlassesMirrorMode glassesMirrorMode
void ShowHideCameras()
Show/hide to the eye camerasin the hierarchy.
const string LEFT_EYE_CAMERA_NAME
The name assigned to the dynamically created camera used for rendering the left eye.
Camera cameraTemplate
The Camera used as a template when creating the eye cameras.
Vector3 posUGBD_UWRLD
The position of the game board reference frame w.r.t. the Unity world-space reference frame.
Material displayBlitShader
The Material used to store/reference the shader.
GameObject leftEye
The left eye camera GameObject.
Camera rightEyeCamera
The right eye Camera property.
float scaleToUGBD_UWRLD
The uniform scale factor that takes points from the Unity world-space to the game board reference fra...
const string SHADER_DISPLAY_BLIT
The name of the custom shader that blits the rendertextures to the backbuffer.
float fieldOfView
The Cameras' field of view property.
void OnRenderImage(RenderTexture src, RenderTexture dst)
Apply post-processing effects to the final image before it is presented.
void GenerateEyeCameras(out GameObject leftEye, out GameObject rightEye)
GameObject headPose
The head pose GameObject property.
Dictionary< AREyes, Camera > eyeCameras
The Camera objects.
RenderTexture MonoPreviewTex
The rendertexture used to display onscreen previews for the left or right eye camera.
void ValidateNativeTexturePointers()
Determines whether the left/right texture handles are still valid, and resets them if needed
void GetNativeTexturePointers(out IntPtr leftTexHandle, out IntPtr rightTexHandle)
Acquires the native output textures upon startup or invalidaiton.
void SubmitPreviewTextures(GlassesMirrorMode glassesMirrorMode)
Copies frame data from the HDR input textures to the onscreen preview textures.
RenderTexture LeftTexture_GLS
The left eye rendertexture
RenderTexture RightTexture_GLS
The right eye rendertexture
RenderTexture StereoPreviewTex
The rendertexture used to display onscreen previews for the left and right eye cameras in stereo.
void Initialize()
Creates and configures the stereo rendertextures
Definition: Log.cs:21
PlayerIndex
The Player index (e.g. Player One, Player Two, etc)