Files
vstyler/Assets/SteamVR/Scripts/SteamVR_Render.cs
T
2016-05-27 23:44:15 +02:00

436 lines
11 KiB
C#
Executable File

//========= 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;
}
}
}
}