83 internal GlassesHandle glassesHandle;
96 private bool useSpectatorCamera;
97 internal bool UseSpectatorCamera
99 get => useSpectatorCamera;
102 if (useSpectatorCamera != value)
106 clearsForMirroring = 0;
108 useSpectatorCamera = value;
115 private uint requiredClearsForMirroring = 1;
116 private uint clearsForMirroring = 0;
118 private IEnumerator presentStereoImagesCoroutine;
121 private const string LEFT_EYE_CAMERA_NAME =
"Left Eye Camera";
123 private GameObject leftEye;
128 private const string RIGHT_EYE_CAMERA_NAME =
"Right Eye Camera";
130 private GameObject rightEye;
137 private Dictionary<AREyes, Camera> eyeCameras =
new Dictionary<AREyes, Camera>()
139 { AREyes.EYE_LEFT,
null },
140 { AREyes.EYE_RIGHT,
null }
147 [Obsolete(
"SplitStereoCamera.posUGBD_UWRLD is deprecated.")]
148 public Vector3
posUGBD_UWRLD {
get => posUSTAGE_UWRLD;
set => posUSTAGE_UWRLD = value; }
154 [Obsolete(
"SplitStereoCamera.rotToUGBD_UWRLD is deprecated.")]
155 public Quaternion
rotToUGBD_UWRLD {
get => rotToUSTAGE_UWRLD;
set => rotToUSTAGE_UWRLD = value;}
161 [Obsolete(
"SplitStereoCamera.scaleToUGBD_UWRLD is deprecated.")]
162 public float scaleToUGBD_UWRLD {
get => scaleToUSTAGE_UWRLD;
set => scaleToUSTAGE_UWRLD = value; }
164 private Vector3 posUSTAGE_UWRLD = Vector3.zero;
165 private Quaternion rotToUSTAGE_UWRLD = Quaternion.identity;
166 private float scaleToUSTAGE_UWRLD = 1.0f;
168 internal void UpdateStageSpaceData(Pose gameboardPose_UWRLD,
float scaleToUSTAGE_UWRLD)
170 this.posUSTAGE_UWRLD = gameboardPose_UWRLD.position;
171 this.rotToUSTAGE_UWRLD = gameboardPose_UWRLD.rotation;
172 this.scaleToUSTAGE_UWRLD = scaleToUSTAGE_UWRLD;
176 private const string SHADER_DISPLAY_BLIT =
"Tilt Five/Simple Blend Shader";
178 private Material displayBlitShader;
180 private GlassesMirrorMode glassesMirrorMode => spectatorSettings.
glassesMirrorMode;
181 private GlassesMirrorMode previousMirrorMode = GlassesMirrorMode.None;
185 private CommandBuffer commandBuffer;
189 [System.Obsolete(
"fieldOfView is deprecated, please use GlassesSettings' fieldOfView instead.")]
192 get {
return spectatorCamera.fieldOfView; }
193 set { rightEyeCamera.fieldOfView = leftEyeCamera.fieldOfView = spectatorCamera.fieldOfView = value; }
197 [System.Obsolete(
"nearClipPlane is deprecated, please use GlassesSettings' nearClipPlane instead.")]
200 get {
return spectatorCamera.nearClipPlane; }
201 set { rightEyeCamera.nearClipPlane = leftEyeCamera.nearClipPlane = spectatorCamera.nearClipPlane = value; }
205 [System.Obsolete(
"farClipPlane is deprecated, please use GlassesSettings' farClipPlane instead.")]
208 get {
return spectatorCamera.farClipPlane; }
209 set { rightEyeCamera.farClipPlane = leftEyeCamera.farClipPlane = spectatorCamera.farClipPlane = value; }
213 [System.Obsolete(
"aspectRatio is deprecated, please use Glasses.TryGetDisplayInfo().monoWidthToHeightRatio instead.")]
216 get {
return spectatorCamera.aspect; }
217 set { spectatorCamera.aspect = value; }
226 useSpectatorCamera =
false;
227 clearsForMirroring = 0;
229 if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Vulkan) {
244 requiredClearsForMirroring = 3;
248 public void Initialize(
249 GameObject headPoseRoot,
250 GlassesSettings glassesSettings,
251 SpectatorSettings spectatorSettings,
252 Glasses.DisplayInfo displayInfo)
254 if(headPoseRoot ==
null || spectatorSettings ==
null)
256 Log.Error(
"Arguments cannot be null");
261 this.glassesSettings = glassesSettings;
262 this.spectatorSettings = spectatorSettings;
263 this.displayInfo = displayInfo;
266 commandBuffer =
new CommandBuffer() { name =
"Onscreen Preview" };
271 if(spectatorCamera !=
null)
273 spectatorCamera.enabled =
true;
278 InstantiateEyeCameras(out leftEye, out rightEye);
282 GenerateEyeCameras(out leftEye, out rightEye);
284 ConfigureEyeCameras();
288 displayBlitShader =
new Material(Shader.Find(SHADER_DISPLAY_BLIT));
290 if (
null == displayBlitShader)
292 Log.Error(
"Failed to load Shader '{0}'", SHADER_DISPLAY_BLIT);
302 private void InstantiateEyeCameras(out GameObject leftEye, out GameObject rightEye)
304 var cloneCameraTemplateChildren = glassesSettings.cloneCameraTemplateChildren;
308 GameObject placeholder = cloneCameraTemplateChildren ? null :
new GameObject(
"Placeholder");
309 if (!cloneCameraTemplateChildren)
311 placeholder.transform.parent =
headPose.transform.parent;
314 cameraTemplate.transform.GetChild(0).parent = placeholder.transform;
320 leftEye.name = LEFT_EYE_CAMERA_NAME;
321 eyeCameras[AREyes.EYE_LEFT] = leftEye.GetComponent<Camera>();
324 rightEye.name = RIGHT_EYE_CAMERA_NAME;
325 eyeCameras[AREyes.EYE_RIGHT] = rightEye.GetComponent<Camera>();
327 var splitStereoCamerasLeft = leftEye.GetComponents<SplitStereoCamera>();
328 for (
int i = 0; i < splitStereoCamerasLeft.Length; i++)
330 Destroy(splitStereoCamerasLeft[i]);
333 var splitStereoCamerasRight = rightEye.GetComponents<SplitStereoCamera>();
334 for (
int i = 0; i < splitStereoCamerasRight.Length; i++)
336 Destroy(splitStereoCamerasRight[i]);
340 if (!cloneCameraTemplateChildren)
343 while (placeholder.transform.childCount > 0)
345 placeholder.transform.GetChild(0).parent =
cameraTemplate.transform;
347 Destroy(placeholder);
351 private void GenerateEyeCameras(out GameObject leftEye, out GameObject rightEye)
353 leftEye =
new GameObject(LEFT_EYE_CAMERA_NAME, typeof(Camera));
354 rightEye =
new GameObject(RIGHT_EYE_CAMERA_NAME, typeof(Camera));
356 eyeCameras[AREyes.EYE_LEFT] = leftEye.GetComponent<Camera>();
357 eyeCameras[AREyes.EYE_RIGHT] = rightEye.GetComponent<Camera>();
359 leftEye.transform.parent =
headPose.transform;
360 rightEye.transform.parent =
headPose.transform;
362 leftEye.transform.SetPositionAndRotation(
headPose.transform.position,
headPose.transform.rotation);
363 rightEye.transform.SetPositionAndRotation(
headPose.transform.position,
headPose.transform.rotation);
366 private void ConfigureEyeCameras()
369 splitStereoTextures.Initialize(displayInfo);
372 RenderTexture leftTex = splitStereoTextures.LeftTexture_GLS;
373 if (
leftEyeCamera.allowMSAA && QualitySettings.antiAliasing > 1)
375 leftTex.antiAliasing = QualitySettings.antiAliasing;
380 splitStereoTextures.MonoPreviewTex.antiAliasing = QualitySettings.antiAliasing;
381 splitStereoTextures.StereoPreviewTex.antiAliasing = QualitySettings.antiAliasing;
384 leftEyeCamera.targetTexture = leftTex;
385 leftEyeCamera.depth = spectatorCamera.depth - 1;
388 RenderTexture rightTex = splitStereoTextures.RightTexture_GLS;
391 rightTex.antiAliasing = QualitySettings.antiAliasing;
394 rightEyeCamera.targetTexture = rightTex;
395 rightEyeCamera.depth = spectatorCamera.depth - 1;
412 if (!Glasses.IsTracked(playerIndex))
416 leftEye.transform.position = pose.transform.position;
417 leftEye.transform.localPosition = pose.transform.localPosition;
418 leftEye.transform.rotation = pose.transform.rotation;
419 leftEye.transform.localRotation = pose.transform.localRotation;
420 leftEye.transform.localScale = pose.transform.localScale;
421 leftEye.transform.Translate(-leftEye.transform.right.normalized * (
cameraTemplate.stereoSeparation * 0.5f));
424 rightEye.transform.position = pose.transform.position;
425 rightEye.transform.localPosition = pose.transform.localPosition;
426 rightEye.transform.rotation = pose.transform.rotation;
427 rightEye.transform.localRotation = pose.transform.localRotation;
428 rightEye.transform.localScale =
headPose.transform.localScale;
429 rightEye.transform.Translate(rightEye.transform.right.normalized * (
cameraTemplate.stereoSeparation * 0.5f));
436 leftEye.SetActive(
true);
437 rightEye.SetActive(
true);
438 leftEyeCamera.enabled =
true;
439 rightEyeCamera.enabled =
true;
440 presentStereoImagesCoroutine = PresentStereoImagesCoroutine();
441 StartCoroutine(presentStereoImagesCoroutine);
444 if(Application.isPlaying)
446 RenderPipelineManager.beginFrameRendering += OnBeginFrameRendering;
447 RenderPipelineManager.endFrameRendering += OnEndFrameRendering;
452 private void OnDisable()
454 if (clearsForMirroring > 0)
456 clearsForMirroring = 0;
461 leftEye.SetActive(
false);
462 leftEyeCamera.enabled =
false;
466 rightEye.SetActive(
false);
467 rightEyeCamera.enabled =
false;
471 if(presentStereoImagesCoroutine !=
null)
473 StopCoroutine(presentStereoImagesCoroutine);
476 RenderPipelineManager.beginFrameRendering -= OnBeginFrameRendering;
477 RenderPipelineManager.endFrameRendering -= OnEndFrameRendering;
486 private void OnBeginFrameRendering(ScriptableRenderContext context, Camera[] cameras)
495 splitStereoTextures.ValidateNativeTexturePointers();
504 splitStereoTextures.ValidateNativeTexturePointers();
506 if(!UseSpectatorCamera)
511 spectatorCamera.targetTexture =
null;
518 if (glassesMirrorMode != previousMirrorMode)
520 clearsForMirroring = 0;
521 previousMirrorMode = glassesMirrorMode;
524 if (clearsForMirroring < requiredClearsForMirroring)
528 GL.Viewport(spectatorCamera.pixelRect);
529 GL.Clear(
true,
true, Color.black);
530 clearsForMirroring += 1;
533 if(glassesMirrorMode == GlassesMirrorMode.None)
538 spectatorCamera.cullingMask = 0;
539 spectatorCamera.fieldOfView = glassesSettings.fieldOfView;
540 spectatorCamera.nearClipPlane = glassesSettings.nearClipPlane / scaleToUSTAGE_UWRLD;
541 spectatorCamera.farClipPlane = glassesSettings.farClipPlane / scaleToUSTAGE_UWRLD;
544 float screenRatio = Screen.width / (float)Screen.height;
545 float targetRatio = glassesMirrorMode == GlassesMirrorMode.Stereoscopic
546 ? displayInfo.stereoWidthToHeightRatio
547 : displayInfo.monoWidthToHeightRatio;
549 if(screenRatio > targetRatio) {
551 float normalizedWidth = targetRatio / screenRatio;
552 float barThickness = (1f - normalizedWidth) / 2f;
553 spectatorCamera.rect =
new Rect(barThickness, 0, normalizedWidth, 1);
557 float normalizedHeight = screenRatio / targetRatio;
558 float barThickness = (1f - normalizedHeight) / 2f;
559 spectatorCamera.rect =
new Rect(0, barThickness, 1, normalizedHeight);
571 void OnEndFrameRendering(ScriptableRenderContext context, Camera[] cameras)
573 if (
this ==
null || !enabled || glassesMirrorMode == GlassesMirrorMode.None || !UseSpectatorCamera)
575 spectatorCamera.rect = spectatorSettings.rect;
582 bool currentlyRenderingEyeCameras =
false;
584 for (
int i = 0; i < cameras.Length; i++)
587 if (cameras[i].Equals(UnityEditor.SceneView.lastActiveSceneView.camera))
594 currentlyRenderingEyeCameras =
true;
597 if (!currentlyRenderingEyeCameras)
603 float screenRatio = Screen.width / (float)Screen.height;
604 float targetRatio = glassesMirrorMode == GlassesMirrorMode.Stereoscopic
605 ? displayInfo.stereoWidthToHeightRatio
606 : displayInfo.monoWidthToHeightRatio;
607 Vector2 frameScale = Vector2.one;
609 if (screenRatio != targetRatio)
611 frameScale = screenRatio > targetRatio
612 ?
new Vector2(screenRatio / targetRatio, 1f)
613 : new Vector2(1f, targetRatio / screenRatio);
616 splitStereoTextures.SubmitPreviewTexturesSRP(glassesMirrorMode, spectatorCamera, commandBuffer, frameScale);
618 context.ExecuteCommandBuffer(commandBuffer);
620 commandBuffer.Clear();
622 spectatorSettings.ResetSpectatorCamera();
632 void OnRenderImage(RenderTexture src, RenderTexture dst)
640 if (spectatorSettings.spectatedPlayer ==
PlayerIndex.None || !Player.IsConnected(spectatorSettings.spectatedPlayer))
642 var splitStereoCameras = spectatorCamera.GetComponents<SplitStereoCamera>();
643 if(splitStereoCameras !=
null && splitStereoCameras.Length > 0
644 && splitStereoCameras[0].Equals(
this))
646 Graphics.Blit(src,
null as RenderTexture);
653 if(!UseSpectatorCamera)
658 if (glassesMirrorMode != GlassesMirrorMode.None)
660 splitStereoTextures.SubmitPreviewTextures(glassesMirrorMode);
662 var previewTex = glassesMirrorMode == GlassesMirrorMode.Stereoscopic
663 ? splitStereoTextures.StereoPreviewTex
664 : splitStereoTextures.MonoPreviewTex;
669 Graphics.Blit(previewTex,
670 null as RenderTexture,
674 else Graphics.Blit(src,
null as RenderTexture);
678 spectatorSettings.ResetSpectatorCamera();
681 IEnumerator PresentStereoImagesCoroutine()
685 var cachedWaitForEndOfFrame =
new WaitForEndOfFrame();
689 yield
return cachedWaitForEndOfFrame;
691 PresentStereoImages();
695 private void PresentStereoImages()
697 splitStereoTextures.GetNativeTexturePointers(out var leftTexHandle, out var rightTexHandle);
699 var leftTargetTex = splitStereoTextures.LeftTexture_GLS;
700 var rightTargetTex = splitStereoTextures.RightTexture_GLS;
702 bool isSrgb = leftTargetTex.sRGB;
705 Quaternion rotToUWRLD_ULVC =
leftEyeCamera.transform.rotation;
709 Vector3 posOfULVC_USTAGE = rotToUSTAGE_UWRLD * (scaleToUSTAGE_UWRLD * (posOfULVC_UWRLD - posUSTAGE_UWRLD));
710 Quaternion rotToUSTAGE_ULVC = rotToUSTAGE_UWRLD * rotToUWRLD_ULVC;
712 Vector3 posOfURVC_USTAGE = rotToUSTAGE_UWRLD * (scaleToUSTAGE_UWRLD * (posOfURVC_UWRLD - posUSTAGE_UWRLD));
713 Quaternion rotToUSTAGE_URVC = rotToUSTAGE_UWRLD * rotToUWRLD_URVC;
716 Display.PresentStereoImages(glassesHandle,
717 leftTexHandle, rightTexHandle,
718 leftTargetTex.width, rightTargetTex.height,
720 glassesSettings.fieldOfView,
721 displayInfo.monoWidthToHeightRatio,
731 private void SyncFields()
733 if (glassesSettings ==
null)
739 leftEyeCamera.fieldOfView = glassesSettings.fieldOfView;
740 leftEyeCamera.nearClipPlane = glassesSettings.nearClipPlane;
741 leftEyeCamera.farClipPlane = glassesSettings.farClipPlane;
742 leftEyeCamera.aspect = displayInfo.monoWidthToHeightRatio;
746 rightEyeCamera.fieldOfView = glassesSettings.fieldOfView;
747 rightEyeCamera.nearClipPlane = glassesSettings.nearClipPlane;
748 rightEyeCamera.farClipPlane = glassesSettings.farClipPlane;
749 rightEyeCamera.aspect = displayInfo.monoWidthToHeightRatio;
760 if (
false == UnityEditor.EditorApplication.isPlaying)
763 if (
null == spectatorCamera)
766 if (
null != leftEye &&
null != rightEye)
776 void ShowHideCameras()
780 leftEye.hideFlags = HideFlags.None;
781 rightEye.hideFlags = HideFlags.None;
785 leftEye.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
786 rightEye.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;