SteamVR
This commit is contained in:
Executable
+435
@@ -0,0 +1,435 @@
|
||||
//========= Copyright 2014, Valve Corporation, All rights reserved. ===========
|
||||
//
|
||||
// Purpose: Handles rendering of all SteamVR_Cameras
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using Valve.VR;
|
||||
|
||||
public class SteamVR_Render : MonoBehaviour
|
||||
{
|
||||
public bool pauseGameWhenDashboardIsVisible = true;
|
||||
public bool lockPhysicsUpdateRateToRenderFrequency = true;
|
||||
|
||||
public SteamVR_ExternalCamera externalCamera;
|
||||
public string externalCameraConfigPath = "externalcamera.cfg";
|
||||
|
||||
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
public LayerMask leftMask, rightMask;
|
||||
|
||||
SteamVR_CameraMask cameraMask;
|
||||
#endif
|
||||
public ETrackingUniverseOrigin trackingSpace = ETrackingUniverseOrigin.TrackingUniverseStanding;
|
||||
|
||||
static public EVREye eye { get; private set; }
|
||||
|
||||
static private SteamVR_Render _instance;
|
||||
static public SteamVR_Render instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = GameObject.FindObjectOfType<SteamVR_Render>();
|
||||
|
||||
if (_instance == null)
|
||||
_instance = new GameObject("[SteamVR]").AddComponent<SteamVR_Render>();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
enabled = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
#if !(UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
compositor.SuspendRendering(value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator RenderLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
if (pauseRendering)
|
||||
continue;
|
||||
|
||||
var compositor = OpenVR.Compositor;
|
||||
if (compositor != null)
|
||||
{
|
||||
if (!compositor.CanRenderScene())
|
||||
continue;
|
||||
|
||||
compositor.SetTrackingSpace(trackingSpace);
|
||||
|
||||
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
SteamVR_Utils.QueueEventOnRenderThread(SteamVR.Unity.k_nRenderEventID_WaitGetPoses);
|
||||
|
||||
// Hack to flush render event that was queued in Update (this ensures WaitGetPoses has returned before we grab the new values).
|
||||
SteamVR.Unity.EventWriteString("[UnityMain] GetNativeTexturePtr - Begin");
|
||||
SteamVR_Camera.GetSceneTexture(cameras[0].GetComponent<Camera>().hdr).GetNativeTexturePtr();
|
||||
SteamVR.Unity.EventWriteString("[UnityMain] GetNativeTexturePtr - End");
|
||||
|
||||
compositor.GetLastPoses(poses, gamePoses);
|
||||
SteamVR_Utils.Event.Send("new_poses", poses);
|
||||
SteamVR_Utils.Event.Send("new_poses_applied");
|
||||
#endif
|
||||
}
|
||||
|
||||
var overlay = SteamVR_Overlay.instance;
|
||||
if (overlay != null)
|
||||
overlay.UpdateOverlay();
|
||||
|
||||
RenderExternalCamera();
|
||||
|
||||
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
var vr = SteamVR.instance;
|
||||
RenderEye(vr, EVREye.Eye_Left);
|
||||
RenderEye(vr, EVREye.Eye_Right);
|
||||
|
||||
// Move cameras back to head position so they can be tracked reliably
|
||||
foreach (var c in cameras)
|
||||
{
|
||||
c.transform.localPosition = Vector3.zero;
|
||||
c.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
if (cameraMask != null)
|
||||
cameraMask.Clear();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
void RenderEye(SteamVR vr, EVREye eye)
|
||||
{
|
||||
int i = (int)eye;
|
||||
SteamVR_Render.eye = eye;
|
||||
|
||||
if (cameraMask != null)
|
||||
cameraMask.Set(vr, eye);
|
||||
|
||||
foreach (var c in cameras)
|
||||
{
|
||||
c.transform.localPosition = vr.eyes[i].pos;
|
||||
c.transform.localRotation = vr.eyes[i].rot;
|
||||
|
||||
// Update position to keep from getting culled
|
||||
cameraMask.transform.position = c.transform.position;
|
||||
|
||||
var camera = c.GetComponent<Camera>();
|
||||
camera.targetTexture = SteamVR_Camera.GetSceneTexture(camera.hdr);
|
||||
int cullingMask = camera.cullingMask;
|
||||
if (eye == EVREye.Eye_Left)
|
||||
{
|
||||
camera.cullingMask &= ~rightMask;
|
||||
camera.cullingMask |= leftMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera.cullingMask &= ~leftMask;
|
||||
camera.cullingMask |= rightMask;
|
||||
}
|
||||
camera.Render();
|
||||
camera.cullingMask = cullingMask;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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(params object[] args)
|
||||
{
|
||||
bool hasFocus = (bool)args[0];
|
||||
if (hasFocus)
|
||||
{
|
||||
if (pauseGameWhenDashboardIsVisible)
|
||||
{
|
||||
Time.timeScale = timeScale;
|
||||
}
|
||||
|
||||
SteamVR_Camera.sceneResolutionScale = sceneResolutionScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pauseGameWhenDashboardIsVisible)
|
||||
{
|
||||
timeScale = Time.timeScale;
|
||||
Time.timeScale = 0.0f;
|
||||
}
|
||||
|
||||
sceneResolutionScale = SteamVR_Camera.sceneResolutionScale;
|
||||
SteamVR_Camera.sceneResolutionScale = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
void OnQuit(params object[] args)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
foreach (System.Reflection.Assembly a in System.AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
var t = a.GetType("UnityEditor.EditorApplication");
|
||||
if (t != null)
|
||||
{
|
||||
t.GetProperty("isPlaying").SetValue(null, false, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
Application.Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
StartCoroutine("RenderLoop");
|
||||
SteamVR_Utils.Event.Listen("input_focus", OnInputFocus);
|
||||
SteamVR_Utils.Event.Listen("Quit", OnQuit);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
SteamVR_Utils.Event.Remove("input_focus", OnInputFocus);
|
||||
SteamVR_Utils.Event.Remove("Quit", OnQuit);
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
var go = new GameObject("cameraMask");
|
||||
go.transform.parent = transform;
|
||||
cameraMask = go.AddComponent<SteamVR_CameraMask>();
|
||||
#endif
|
||||
if (externalCamera == null && System.IO.File.Exists(externalCameraConfigPath))
|
||||
{
|
||||
var prefab = Resources.Load<GameObject>("SteamVR_ExternalCamera");
|
||||
var instance = Instantiate(prefab);
|
||||
instance.gameObject.name = "External Camera";
|
||||
|
||||
externalCamera = instance.transform.GetChild(0).GetComponent<SteamVR_ExternalCamera>();
|
||||
externalCamera.configPath = externalCameraConfigPath;
|
||||
externalCamera.ReadConfig();
|
||||
}
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
// We want to call this as soon after Present as possible.
|
||||
SteamVR_Utils.QueueEventOnRenderThread(SteamVR.Unity.k_nRenderEventID_PostPresentHandoff);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !(UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
private SteamVR_UpdatePoses poseUpdater;
|
||||
#endif
|
||||
|
||||
void Update()
|
||||
{
|
||||
#if !(UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
|
||||
if (poseUpdater == null)
|
||||
{
|
||||
var go = new GameObject("poseUpdater");
|
||||
go.transform.parent = transform;
|
||||
poseUpdater = go.AddComponent<SteamVR_UpdatePoses>();
|
||||
}
|
||||
#else
|
||||
if (cameras.Length == 0)
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// If our FixedUpdate rate doesn't match our render framerate, then catch the handoff here.
|
||||
SteamVR_Utils.QueueEventOnRenderThread(SteamVR.Unity.k_nRenderEventID_PostPresentHandoff);
|
||||
#endif
|
||||
// Force controller update in case no one else called this frame to ensure prevState gets updated.
|
||||
SteamVR_Controller.Update();
|
||||
|
||||
// Dispatch any OpenVR events.
|
||||
var system = OpenVR.System;
|
||||
if (system != null)
|
||||
{
|
||||
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_Utils.Event.Send("input_focus", false);
|
||||
}
|
||||
break;
|
||||
case EVREventType.VREvent_InputFocusReleased: // that app has released input focus
|
||||
if (vrEvent.data.process.pid == 0)
|
||||
{
|
||||
SteamVR_Utils.Event.Send("input_focus", true);
|
||||
}
|
||||
break;
|
||||
case EVREventType.VREvent_ShowRenderModels:
|
||||
SteamVR_Utils.Event.Send("hide_render_models", false);
|
||||
break;
|
||||
case EVREventType.VREvent_HideRenderModels:
|
||||
SteamVR_Utils.Event.Send("hide_render_models", true);
|
||||
break;
|
||||
default:
|
||||
var name = System.Enum.GetName(typeof(EVREventType), vrEvent.eventType);
|
||||
if (name != null)
|
||||
SteamVR_Utils.Event.Send(name.Substring(8) /*strip VREvent_*/, 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 (lockPhysicsUpdateRateToRenderFrequency && Time.timeScale > 0.0f)
|
||||
{
|
||||
var vr = SteamVR.instance;
|
||||
if (vr != null)
|
||||
{
|
||||
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;
|
||||
Time.maximumDeltaTime = Time.fixedDeltaTime * timing.m_nNumFramePresents;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user