You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			469 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			469 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
 | 
						|
//
 | 
						|
// Purpose: Handles rendering of all SteamVR_Cameras
 | 
						|
//
 | 
						|
//=============================================================================
 | 
						|
 | 
						|
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
using Valve.VR;
 | 
						|
 | 
						|
 | 
						|
namespace Valve.VR
 | 
						|
{
 | 
						|
    public class SteamVR_Render : MonoBehaviour
 | 
						|
    {
 | 
						|
        public SteamVR_ExternalCamera externalCamera;
 | 
						|
        public string externalCameraConfigPath = "externalcamera.cfg";
 | 
						|
 | 
						|
        public static EVREye eye { get; private set; }
 | 
						|
 | 
						|
        public static SteamVR_Render instance { get { return SteamVR_Behaviour.instance.steamvr_render; } }
 | 
						|
 | 
						|
        static private bool isQuitting;
 | 
						|
        void OnApplicationQuit()
 | 
						|
        {
 | 
						|
            isQuitting = true;
 | 
						|
            SteamVR.SafeDispose();
 | 
						|
        }
 | 
						|
 | 
						|
        static public void Add(SteamVR_Camera vrcam)
 | 
						|
        {
 | 
						|
            if (!isQuitting)
 | 
						|
                instance.AddInternal(vrcam);
 | 
						|
        }
 | 
						|
 | 
						|
        static public void Remove(SteamVR_Camera vrcam)
 | 
						|
        {
 | 
						|
            if (!isQuitting && instance != null)
 | 
						|
                instance.RemoveInternal(vrcam);
 | 
						|
        }
 | 
						|
 | 
						|
        static public SteamVR_Camera Top()
 | 
						|
        {
 | 
						|
            if (!isQuitting)
 | 
						|
                return instance.TopInternal();
 | 
						|
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
 | 
						|
        private SteamVR_Camera[] cameras = new SteamVR_Camera[0];
 | 
						|
 | 
						|
        void AddInternal(SteamVR_Camera vrcam)
 | 
						|
        {
 | 
						|
            var camera = vrcam.GetComponent<Camera>();
 | 
						|
            var length = cameras.Length;
 | 
						|
            var sorted = new SteamVR_Camera[length + 1];
 | 
						|
            int insert = 0;
 | 
						|
            for (int i = 0; i < length; i++)
 | 
						|
            {
 | 
						|
                var c = cameras[i].GetComponent<Camera>();
 | 
						|
                if (i == insert && c.depth > camera.depth)
 | 
						|
                    sorted[insert++] = vrcam;
 | 
						|
 | 
						|
                sorted[insert++] = cameras[i];
 | 
						|
            }
 | 
						|
            if (insert == length)
 | 
						|
                sorted[insert] = vrcam;
 | 
						|
 | 
						|
            cameras = sorted;
 | 
						|
        }
 | 
						|
 | 
						|
        void RemoveInternal(SteamVR_Camera vrcam)
 | 
						|
        {
 | 
						|
            var length = cameras.Length;
 | 
						|
            int count = 0;
 | 
						|
            for (int i = 0; i < length; i++)
 | 
						|
            {
 | 
						|
                var c = cameras[i];
 | 
						|
                if (c == vrcam)
 | 
						|
                    ++count;
 | 
						|
            }
 | 
						|
            if (count == 0)
 | 
						|
                return;
 | 
						|
 | 
						|
            var sorted = new SteamVR_Camera[length - count];
 | 
						|
            int insert = 0;
 | 
						|
            for (int i = 0; i < length; i++)
 | 
						|
            {
 | 
						|
                var c = cameras[i];
 | 
						|
                if (c != vrcam)
 | 
						|
                    sorted[insert++] = c;
 | 
						|
            }
 | 
						|
 | 
						|
            cameras = sorted;
 | 
						|
        }
 | 
						|
 | 
						|
        SteamVR_Camera TopInternal()
 | 
						|
        {
 | 
						|
            if (cameras.Length > 0)
 | 
						|
                return cameras[cameras.Length - 1];
 | 
						|
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
 | 
						|
        public TrackedDevicePose_t[] poses = new TrackedDevicePose_t[OpenVR.k_unMaxTrackedDeviceCount];
 | 
						|
        public TrackedDevicePose_t[] gamePoses = new TrackedDevicePose_t[0];
 | 
						|
 | 
						|
        static private bool _pauseRendering;
 | 
						|
        static public bool pauseRendering
 | 
						|
        {
 | 
						|
            get { return _pauseRendering; }
 | 
						|
            set
 | 
						|
            {
 | 
						|
                _pauseRendering = value;
 | 
						|
 | 
						|
                var compositor = OpenVR.Compositor;
 | 
						|
                if (compositor != null)
 | 
						|
                    compositor.SuspendRendering(value);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
 | 
						|
 | 
						|
        private IEnumerator RenderLoop()
 | 
						|
        {
 | 
						|
            while (Application.isPlaying)
 | 
						|
            {
 | 
						|
                yield return waitForEndOfFrame;
 | 
						|
 | 
						|
                if (pauseRendering)
 | 
						|
                    continue;
 | 
						|
 | 
						|
                var compositor = OpenVR.Compositor;
 | 
						|
                if (compositor != null)
 | 
						|
                {
 | 
						|
                    if (!compositor.CanRenderScene())
 | 
						|
                        continue;
 | 
						|
 | 
						|
                    compositor.SetTrackingSpace(SteamVR.settings.trackingSpace);
 | 
						|
                }
 | 
						|
 | 
						|
                var overlay = SteamVR_Overlay.instance;
 | 
						|
                if (overlay != null)
 | 
						|
                    overlay.UpdateOverlay();
 | 
						|
 | 
						|
                if (CheckExternalCamera())
 | 
						|
                    RenderExternalCamera();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private bool? doesPathExist = null;
 | 
						|
        private bool CheckExternalCamera()
 | 
						|
        {
 | 
						|
            if (doesPathExist == false)
 | 
						|
                return false;
 | 
						|
            else if (doesPathExist == null)
 | 
						|
                doesPathExist = System.IO.File.Exists(externalCameraConfigPath);
 | 
						|
 | 
						|
            if (externalCamera == null && doesPathExist == true)
 | 
						|
            {
 | 
						|
                GameObject prefab = Resources.Load<GameObject>("SteamVR_ExternalCamera");
 | 
						|
                if (prefab == null)
 | 
						|
                {
 | 
						|
                    doesPathExist = false;
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    if (SteamVR_Settings.instance.legacyMixedRealityCamera)
 | 
						|
                    {
 | 
						|
                        if (SteamVR_ExternalCamera_LegacyManager.hasCamera == false)
 | 
						|
                            return false;
 | 
						|
 | 
						|
                        GameObject instance = Instantiate(prefab);
 | 
						|
                        instance.gameObject.name = "External Camera";
 | 
						|
 | 
						|
                        externalCamera = instance.transform.GetChild(0).GetComponent<SteamVR_ExternalCamera>();
 | 
						|
                        externalCamera.configPath = externalCameraConfigPath;
 | 
						|
                        externalCamera.ReadConfig();
 | 
						|
                        externalCamera.SetupDeviceIndex(SteamVR_ExternalCamera_LegacyManager.cameraIndex);
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        SteamVR_Action_Pose cameraPose = SteamVR_Settings.instance.mixedRealityCameraPose;
 | 
						|
                        SteamVR_Input_Sources cameraSource = SteamVR_Settings.instance.mixedRealityCameraInputSource;
 | 
						|
 | 
						|
                        if (cameraPose != null && SteamVR_Settings.instance.mixedRealityActionSetAutoEnable)
 | 
						|
                        {
 | 
						|
                            if (cameraPose.actionSet != null && cameraPose.actionSet.IsActive(cameraSource) == false)
 | 
						|
                                cameraPose.actionSet.Activate(cameraSource);
 | 
						|
                        }
 | 
						|
 | 
						|
                        if (cameraPose == null)
 | 
						|
                        {
 | 
						|
                            doesPathExist = false;
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
 | 
						|
                        if (cameraPose != null && cameraPose[cameraSource].active && cameraPose[cameraSource].deviceIsConnected)
 | 
						|
                        {
 | 
						|
                            GameObject instance = Instantiate(prefab);
 | 
						|
                            instance.gameObject.name = "External Camera";
 | 
						|
 | 
						|
                            externalCamera = instance.transform.GetChild(0).GetComponent<SteamVR_ExternalCamera>();
 | 
						|
                            externalCamera.configPath = externalCameraConfigPath;
 | 
						|
                            externalCamera.ReadConfig();
 | 
						|
                            externalCamera.SetupPose(cameraPose, cameraSource);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return (externalCamera != null);
 | 
						|
        }
 | 
						|
 | 
						|
        void RenderExternalCamera()
 | 
						|
        {
 | 
						|
            if (externalCamera == null)
 | 
						|
                return;
 | 
						|
 | 
						|
            if (!externalCamera.gameObject.activeInHierarchy)
 | 
						|
                return;
 | 
						|
 | 
						|
            var frameSkip = (int)Mathf.Max(externalCamera.config.frameSkip, 0.0f);
 | 
						|
            if (Time.frameCount % (frameSkip + 1) != 0)
 | 
						|
                return;
 | 
						|
 | 
						|
            // Keep external camera relative to the most relevant vr camera.
 | 
						|
            externalCamera.AttachToCamera(TopInternal());
 | 
						|
 | 
						|
            externalCamera.RenderNear();
 | 
						|
            externalCamera.RenderFar();
 | 
						|
        }
 | 
						|
 | 
						|
        float sceneResolutionScale = 1.0f, timeScale = 1.0f;
 | 
						|
 | 
						|
        private void OnInputFocus(bool hasFocus)
 | 
						|
        {
 | 
						|
            if (SteamVR.active == false)
 | 
						|
                return;
 | 
						|
 | 
						|
            if (hasFocus)
 | 
						|
            {
 | 
						|
                if (SteamVR.settings.pauseGameWhenDashboardVisible)
 | 
						|
                {
 | 
						|
                    Time.timeScale = timeScale;
 | 
						|
                }
 | 
						|
 | 
						|
                SteamVR_Camera.sceneResolutionScale = sceneResolutionScale;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                if (SteamVR.settings.pauseGameWhenDashboardVisible)
 | 
						|
                {
 | 
						|
                    timeScale = Time.timeScale;
 | 
						|
                    Time.timeScale = 0.0f;
 | 
						|
                }
 | 
						|
 | 
						|
                sceneResolutionScale = SteamVR_Camera.sceneResolutionScale;
 | 
						|
                SteamVR_Camera.sceneResolutionScale = 0.5f;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private string GetScreenshotFilename(uint screenshotHandle, EVRScreenshotPropertyFilenames screenshotPropertyFilename)
 | 
						|
        {
 | 
						|
            var error = EVRScreenshotError.None;
 | 
						|
            var capacity = OpenVR.Screenshots.GetScreenshotPropertyFilename(screenshotHandle, screenshotPropertyFilename, null, 0, ref error);
 | 
						|
            if (error != EVRScreenshotError.None && error != EVRScreenshotError.BufferTooSmall)
 | 
						|
                return null;
 | 
						|
            if (capacity > 1)
 | 
						|
            {
 | 
						|
                var result = new System.Text.StringBuilder((int)capacity);
 | 
						|
                OpenVR.Screenshots.GetScreenshotPropertyFilename(screenshotHandle, screenshotPropertyFilename, result, capacity, ref error);
 | 
						|
                if (error != EVRScreenshotError.None)
 | 
						|
                    return null;
 | 
						|
                return result.ToString();
 | 
						|
            }
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
 | 
						|
        private void OnRequestScreenshot(VREvent_t vrEvent)
 | 
						|
        {
 | 
						|
            var screenshotHandle = vrEvent.data.screenshot.handle;
 | 
						|
            var screenshotType = (EVRScreenshotType)vrEvent.data.screenshot.type;
 | 
						|
 | 
						|
            if (screenshotType == EVRScreenshotType.StereoPanorama)
 | 
						|
            {
 | 
						|
                string previewFilename = GetScreenshotFilename(screenshotHandle, EVRScreenshotPropertyFilenames.Preview);
 | 
						|
                string VRFilename = GetScreenshotFilename(screenshotHandle, EVRScreenshotPropertyFilenames.VR);
 | 
						|
 | 
						|
                if (previewFilename == null || VRFilename == null)
 | 
						|
                    return;
 | 
						|
 | 
						|
                // Do the stereo panorama screenshot
 | 
						|
                // Figure out where the view is
 | 
						|
                GameObject screenshotPosition = new GameObject("screenshotPosition");
 | 
						|
                screenshotPosition.transform.position = SteamVR_Render.Top().transform.position;
 | 
						|
                screenshotPosition.transform.rotation = SteamVR_Render.Top().transform.rotation;
 | 
						|
                screenshotPosition.transform.localScale = SteamVR_Render.Top().transform.lossyScale;
 | 
						|
                SteamVR_Utils.TakeStereoScreenshot(screenshotHandle, screenshotPosition, 32, 0.064f, ref previewFilename, ref VRFilename);
 | 
						|
 | 
						|
                // and submit it
 | 
						|
                OpenVR.Screenshots.SubmitScreenshot(screenshotHandle, screenshotType, previewFilename, VRFilename);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private EVRScreenshotType[] screenshotTypes = new EVRScreenshotType[] { EVRScreenshotType.StereoPanorama };
 | 
						|
 | 
						|
        private void OnEnable()
 | 
						|
        {
 | 
						|
            StartCoroutine(RenderLoop());
 | 
						|
            SteamVR_Events.InputFocus.Listen(OnInputFocus);
 | 
						|
            SteamVR_Events.System(EVREventType.VREvent_RequestScreenshot).Listen(OnRequestScreenshot);
 | 
						|
 | 
						|
            if (SteamVR_Settings.instance.legacyMixedRealityCamera)
 | 
						|
                SteamVR_ExternalCamera_LegacyManager.SubscribeToNewPoses();
 | 
						|
 | 
						|
#if UNITY_2017_1_OR_NEWER
 | 
						|
		    Application.onBeforeRender += OnBeforeRender;
 | 
						|
#else
 | 
						|
            Camera.onPreCull += OnCameraPreCull;
 | 
						|
#endif
 | 
						|
 | 
						|
            if (SteamVR.initializedState == SteamVR.InitializedStates.InitializeSuccess)
 | 
						|
                OpenVR.Screenshots.HookScreenshot(screenshotTypes);
 | 
						|
            else
 | 
						|
                SteamVR_Events.Initialized.AddListener(OnSteamVRInitialized);
 | 
						|
        }
 | 
						|
 | 
						|
        private void OnSteamVRInitialized(bool success)
 | 
						|
        {
 | 
						|
            if (success)
 | 
						|
                OpenVR.Screenshots.HookScreenshot(screenshotTypes);
 | 
						|
        }
 | 
						|
 | 
						|
        private void OnDisable()
 | 
						|
        {
 | 
						|
            StopAllCoroutines();
 | 
						|
            SteamVR_Events.InputFocus.Remove(OnInputFocus);
 | 
						|
            SteamVR_Events.System(EVREventType.VREvent_RequestScreenshot).Remove(OnRequestScreenshot);
 | 
						|
 | 
						|
#if UNITY_2017_1_OR_NEWER
 | 
						|
		    Application.onBeforeRender -= OnBeforeRender;
 | 
						|
#else
 | 
						|
            Camera.onPreCull -= OnCameraPreCull;
 | 
						|
#endif
 | 
						|
 | 
						|
            if (SteamVR.initializedState != SteamVR.InitializedStates.InitializeSuccess)
 | 
						|
                SteamVR_Events.Initialized.RemoveListener(OnSteamVRInitialized);
 | 
						|
        }
 | 
						|
 | 
						|
        public void UpdatePoses()
 | 
						|
        {
 | 
						|
            var compositor = OpenVR.Compositor;
 | 
						|
            if (compositor != null)
 | 
						|
            {
 | 
						|
                compositor.GetLastPoses(poses, gamePoses);
 | 
						|
                SteamVR_Events.NewPoses.Send(poses);
 | 
						|
                SteamVR_Events.NewPosesApplied.Send();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
#if UNITY_2017_1_OR_NEWER
 | 
						|
	    void OnBeforeRender()
 | 
						|
        {
 | 
						|
            if (SteamVR.active == false)
 | 
						|
                return;
 | 
						|
 | 
						|
            if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnPreCull))
 | 
						|
            {
 | 
						|
                UpdatePoses();
 | 
						|
            }
 | 
						|
        }
 | 
						|
#else
 | 
						|
        void OnCameraPreCull(Camera cam)
 | 
						|
        {
 | 
						|
            if (SteamVR.active == false)
 | 
						|
                return;
 | 
						|
 | 
						|
#if UNITY_2017_1_OR_NEWER
 | 
						|
		if (cam.cameraType != CameraType.VR)
 | 
						|
			return;
 | 
						|
#else
 | 
						|
            //custom code
 | 
						|
            if (!cam.stereoEnabled) //if not main camera (stereoEnabled isn't perfect, but it is the fast/easiest way to check this in Unity 5.4)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
#endif
 | 
						|
            // Only update poses on the first camera per frame.
 | 
						|
            if (Time.frameCount != lastFrameCount)
 | 
						|
            {
 | 
						|
                lastFrameCount = Time.frameCount;
 | 
						|
 | 
						|
                if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnPreCull))
 | 
						|
                {
 | 
						|
                    UpdatePoses();
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        static int lastFrameCount = -1;
 | 
						|
#endif
 | 
						|
 | 
						|
        void Update()
 | 
						|
        {
 | 
						|
            if (SteamVR.active == false)
 | 
						|
                return;
 | 
						|
 | 
						|
            // Dispatch any OpenVR events.
 | 
						|
            var system = OpenVR.System;
 | 
						|
            if (system == null)
 | 
						|
                return;
 | 
						|
 | 
						|
            UpdatePoses();
 | 
						|
 | 
						|
            var vrEvent = new VREvent_t();
 | 
						|
            var size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(VREvent_t));
 | 
						|
            for (int i = 0; i < 64; i++)
 | 
						|
            {
 | 
						|
                if (!system.PollNextEvent(ref vrEvent, size))
 | 
						|
                    break;
 | 
						|
 | 
						|
                switch ((EVREventType)vrEvent.eventType)
 | 
						|
                {
 | 
						|
                    case EVREventType.VREvent_InputFocusCaptured: // another app has taken focus (likely dashboard)
 | 
						|
                        if (vrEvent.data.process.oldPid == 0)
 | 
						|
                        {
 | 
						|
                            SteamVR_Events.InputFocus.Send(false);
 | 
						|
                        }
 | 
						|
                        break;
 | 
						|
                    case EVREventType.VREvent_InputFocusReleased: // that app has released input focus
 | 
						|
                        if (vrEvent.data.process.pid == 0)
 | 
						|
                        {
 | 
						|
                            SteamVR_Events.InputFocus.Send(true);
 | 
						|
                        }
 | 
						|
                        break;
 | 
						|
                    case EVREventType.VREvent_ShowRenderModels:
 | 
						|
                        SteamVR_Events.HideRenderModels.Send(false);
 | 
						|
                        break;
 | 
						|
                    case EVREventType.VREvent_HideRenderModels:
 | 
						|
                        SteamVR_Events.HideRenderModels.Send(true);
 | 
						|
                        break;
 | 
						|
                    default:
 | 
						|
                        SteamVR_Events.System((EVREventType)vrEvent.eventType).Send(vrEvent);
 | 
						|
                        break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // Ensure various settings to minimize latency.
 | 
						|
            Application.targetFrameRate = -1;
 | 
						|
            Application.runInBackground = true; // don't require companion window focus
 | 
						|
            QualitySettings.maxQueuedFrames = -1;
 | 
						|
            QualitySettings.vSyncCount = 0; // this applies to the companion window
 | 
						|
 | 
						|
            if (SteamVR.settings.lockPhysicsUpdateRateToRenderFrequency && Time.timeScale > 0.0f)
 | 
						|
            {
 | 
						|
                var vr = SteamVR.instance;
 | 
						|
                if (vr != null && Application.isPlaying)
 | 
						|
                {
 | 
						|
                    //var timing = new Compositor_FrameTiming();
 | 
						|
                    //timing.m_nSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(Compositor_FrameTiming));
 | 
						|
                    //vr.compositor.GetFrameTiming(ref timing, 0);
 | 
						|
 | 
						|
                    Time.fixedDeltaTime = Time.timeScale / vr.hmd_DisplayFrequency;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
} |