/* * 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 UnityEngine; using System.Collections; using UnityEngine.UI; //------------------------------------------------------------------------------------- /// /// Shows debug information on a heads-up display. /// public class OVRDebugInfo : MonoBehaviour { #region GameObjects for Debug Information UIs GameObject debugUIManager; GameObject debugUIObject; GameObject riftPresent; GameObject fps; GameObject ipd; GameObject fov; GameObject height; GameObject depth; GameObject resolutionEyeTexture; GameObject latencies; GameObject texts; #endregion #region Debug strings string strRiftPresent = null; // "VR DISABLED" string strFPS = null; // "FPS: 0"; string strIPD = null; // "IPD: 0.000"; string strFOV = null; // "FOV: 0.0f"; string strHeight = null; // "Height: 0.0f"; string strDepth = null; // "Depth: 0.0f"; string strResolutionEyeTexture = null; // "Resolution : {0} x {1}" string strLatencies = null; // "R: {0:F3} TW: {1:F3} PP: {2:F3} RE: {3:F3} TWE: {4:F3}" #endregion /// /// Variables for FPS /// float updateInterval = 0.5f; float accum = 0.0f; int frames = 0; float timeLeft = 0.0f; /// /// Managing for UI initialization /// bool initUIComponent = false; bool isInited = false; /// /// UIs Y offset /// float offsetY = 55.0f; /// /// Managing for rift detection UI /// float riftPresentTimeout = 0.0f; /// /// Turn on / off VR variables /// bool showVRVars = false; #region MonoBehaviour handler /// /// Initialization /// void Awake() { // Create canvas for using new GUI debugUIManager = new GameObject(); debugUIManager.name = "DebugUIManager"; debugUIManager.transform.parent = GameObject.Find("LeftEyeAnchor").transform; RectTransform rectTransform = debugUIManager.AddComponent(); rectTransform.sizeDelta = new Vector2(100f, 100f); rectTransform.localScale = new Vector3(0.001f, 0.001f, 0.001f); rectTransform.localPosition = new Vector3(0.01f, 0.17f, 0.53f); rectTransform.localEulerAngles = Vector3.zero; Canvas canvas = debugUIManager.AddComponent(); canvas.renderMode = RenderMode.WorldSpace; canvas.pixelPerfect = false; } /// /// Updating VR variables and managing UI present /// void Update() { if (initUIComponent && !isInited) { InitUIComponents(); } //todo: enable for Unity Input System #if ENABLE_LEGACY_INPUT_MANAGER if (Input.GetKeyDown(KeyCode.Space) && riftPresentTimeout < 0.0f) { initUIComponent = true; showVRVars ^= true; } #endif UpdateDeviceDetection(); // Presenting VR variables if (showVRVars) { debugUIManager.SetActive(true); UpdateVariable(); UpdateStrings(); } else { debugUIManager.SetActive(false); } } /// /// Initialize isInited value on OnDestroy /// void OnDestroy() { isInited = false; } #endregion #region Private Functions /// /// Initialize UI GameObjects /// void InitUIComponents() { float posY = 0.0f; int fontSize = 20; debugUIObject = new GameObject(); debugUIObject.name = "DebugInfo"; debugUIObject.transform.parent = GameObject.Find("DebugUIManager").transform; debugUIObject.transform.localPosition = new Vector3(0.0f, 100.0f, 0.0f); debugUIObject.transform.localEulerAngles = Vector3.zero; debugUIObject.transform.localScale = new Vector3(1.0f, 1.0f, 1.0f); // Print out for FPS if (!string.IsNullOrEmpty(strFPS)) { fps = VariableObjectManager(fps, "FPS", posY -= offsetY, strFPS, fontSize); } // Print out for IPD if (!string.IsNullOrEmpty(strIPD)) { ipd = VariableObjectManager(ipd, "IPD", posY -= offsetY, strIPD, fontSize); } // Print out for FOV if (!string.IsNullOrEmpty(strFOV)) { fov = VariableObjectManager(fov, "FOV", posY -= offsetY, strFOV, fontSize); } // Print out for Height if (!string.IsNullOrEmpty(strHeight)) { height = VariableObjectManager(height, "Height", posY -= offsetY, strHeight, fontSize); } // Print out for Depth if (!string.IsNullOrEmpty(strDepth)) { depth = VariableObjectManager(depth, "Depth", posY -= offsetY, strDepth, fontSize); } // Print out for Resoulution of Eye Texture if (!string.IsNullOrEmpty(strResolutionEyeTexture)) { resolutionEyeTexture = VariableObjectManager(resolutionEyeTexture, "Resolution", posY -= offsetY, strResolutionEyeTexture, fontSize); } // Print out for Latency if (!string.IsNullOrEmpty(strLatencies)) { latencies = VariableObjectManager(latencies, "Latency", posY -= offsetY, strLatencies, 17); posY = 0.0f; } initUIComponent = false; isInited = true; } /// /// Update VR Variables /// void UpdateVariable() { UpdateIPD(); UpdateEyeHeightOffset(); UpdateEyeDepthOffset(); UpdateFOV(); UpdateResolutionEyeTexture(); UpdateLatencyValues(); UpdateFPS(); } /// /// Update Strings /// void UpdateStrings() { if (debugUIObject == null) return; if (!string.IsNullOrEmpty(strFPS)) fps.GetComponentInChildren().text = strFPS; if (!string.IsNullOrEmpty(strIPD)) ipd.GetComponentInChildren().text = strIPD; if (!string.IsNullOrEmpty(strFOV)) fov.GetComponentInChildren().text = strFOV; if (!string.IsNullOrEmpty(strResolutionEyeTexture)) resolutionEyeTexture.GetComponentInChildren().text = strResolutionEyeTexture; if (!string.IsNullOrEmpty(strLatencies)) { latencies.GetComponentInChildren().text = strLatencies; latencies.GetComponentInChildren().fontSize = 14; } if (!string.IsNullOrEmpty(strHeight)) height.GetComponentInChildren().text = strHeight; if (!string.IsNullOrEmpty(strDepth)) depth.GetComponentInChildren().text = strDepth; } /// /// It's for rift present GUI /// void RiftPresentGUI(GameObject guiMainOBj) { riftPresent = ComponentComposition(riftPresent); riftPresent.transform.SetParent(guiMainOBj.transform); riftPresent.name = "RiftPresent"; RectTransform rectTransform = riftPresent.GetComponent(); rectTransform.localPosition = new Vector3(0.0f, 0.0f, 0.0f); rectTransform.localScale = new Vector3(1.0f, 1.0f, 1.0f); rectTransform.localEulerAngles = Vector3.zero; Text text = riftPresent.GetComponentInChildren(); text.text = strRiftPresent; text.fontSize = 20; } /// /// Updates the device detection. /// void UpdateDeviceDetection() { if (riftPresentTimeout >= 0.0f) { riftPresentTimeout -= Time.deltaTime; } } /// /// Object Manager for Variables /// /// gameobject for each Variable GameObject VariableObjectManager(GameObject gameObject, string name, float posY, string str, int fontSize) { gameObject = ComponentComposition(gameObject); gameObject.name = name; gameObject.transform.SetParent(debugUIObject.transform); RectTransform rectTransform = gameObject.GetComponent(); rectTransform.localPosition = new Vector3(0.0f, posY -= offsetY, 0.0f); Text text = gameObject.GetComponentInChildren(); text.text = str; text.fontSize = fontSize; gameObject.transform.localEulerAngles = Vector3.zero; rectTransform.localScale = new Vector3(1.0f, 1.0f, 1.0f); return gameObject; } /// /// Component composition /// /// Composed gameobject. GameObject ComponentComposition(GameObject GO) { GO = new GameObject(); GO.AddComponent(); GO.AddComponent(); GO.AddComponent(); GO.GetComponent().sizeDelta = new Vector2(350f, 50f); GO.GetComponent().color = new Color(7f / 255f, 45f / 255f, 71f / 255f, 200f / 255f); texts = new GameObject(); texts.AddComponent(); texts.AddComponent(); texts.AddComponent(); texts.GetComponent().sizeDelta = new Vector2(350f, 50f); texts.GetComponent().font = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font; texts.GetComponent().alignment = TextAnchor.MiddleCenter; texts.transform.SetParent(GO.transform); texts.name = "TextBox"; return GO; } #endregion #region Debugging variables handler /// /// Updates the IPD. /// void UpdateIPD() { strIPD = System.String.Format("IPD (mm): {0:F4}", OVRManager.profile.ipd * 1000.0f); } /// /// Updates the eye height offset. /// void UpdateEyeHeightOffset() { float eyeHeight = OVRManager.profile.eyeHeight; strHeight = System.String.Format("Eye Height (m): {0:F3}", eyeHeight); } /// /// Updates the eye depth offset. /// void UpdateEyeDepthOffset() { float eyeDepth = OVRManager.profile.eyeDepth; strDepth = System.String.Format("Eye Depth (m): {0:F3}", eyeDepth); } /// /// Updates the FOV. /// void UpdateFOV() { OVRDisplay.EyeRenderDesc eyeDesc = OVRManager.display.GetEyeRenderDesc(UnityEngine.XR.XRNode.LeftEye); strFOV = System.String.Format("FOV (deg): {0:F3}", eyeDesc.fov.y); } /// /// Updates resolution of eye texture /// void UpdateResolutionEyeTexture() { OVRDisplay.EyeRenderDesc leftEyeDesc = OVRManager.display.GetEyeRenderDesc(UnityEngine.XR.XRNode.LeftEye); OVRDisplay.EyeRenderDesc rightEyeDesc = OVRManager.display.GetEyeRenderDesc(UnityEngine.XR.XRNode.RightEye); float scale = UnityEngine.XR.XRSettings.renderViewportScale; float w = (int)(scale * (float)(leftEyeDesc.resolution.x + rightEyeDesc.resolution.x)); float h = (int)(scale * (float)Mathf.Max(leftEyeDesc.resolution.y, rightEyeDesc.resolution.y)); strResolutionEyeTexture = System.String.Format("Resolution : {0} x {1}", w, h); } /// /// Updates latency values /// void UpdateLatencyValues() { #if !UNITY_ANDROID || UNITY_EDITOR OVRDisplay.LatencyData latency = OVRManager.display.latency; if (latency.render < 0.000001f && latency.timeWarp < 0.000001f && latency.postPresent < 0.000001f) strLatencies = System.String.Format("Latency values are not available."); else strLatencies = System.String.Format("Render: {0:F3} TimeWarp: {1:F3} Post-Present: {2:F3}\nRender Error: {3:F3} TimeWarp Error: {4:F3}", latency.render, latency.timeWarp, latency.postPresent, latency.renderError, latency.timeWarpError); #endif } /// /// Updates the FPS. /// void UpdateFPS() { timeLeft -= Time.unscaledDeltaTime; accum += Time.unscaledDeltaTime; ++frames; // Interval ended - update GUI text and start new interval if (timeLeft <= 0.0) { // display two fractional digits (f2 format) float fps = frames / accum; strFPS = System.String.Format("FPS: {0:F2}", fps); timeLeft += updateInterval; accum = 0.0f; frames = 0; } } #endregion }