holopy3/Assets/SteamVR/Scripts/SteamVR_Render.cs

469 lines
16 KiB
C#
Raw Permalink Normal View History

2020-12-10 14:25:12 +00:00
//======= 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;
}
}
}
}
}