campfire/Assets/SteamVR/Scripts/SteamVR_Camera.cs
2020-04-29 20:40:05 +03:00

294 lines
9.4 KiB
C#

//======= Copyright (c) Valve Corporation, All rights reserved. ===============
//
// Purpose: Adds SteamVR render support to existing camera objects
//
//=============================================================================
using UnityEngine;
using System.Collections;
using System.Reflection;
using Valve.VR;
#if UNITY_2017_2_OR_NEWER
using UnityEngine.XR;
#else
using XRSettings = UnityEngine.VR.VRSettings;
using XRDevice = UnityEngine.VR.VRDevice;
#endif
namespace Valve.VR
{
[RequireComponent(typeof(Camera))]
public class SteamVR_Camera : MonoBehaviour
{
[SerializeField]
private Transform _head;
public Transform head { get { return _head; } }
public Transform offset { get { return _head; } } // legacy
public Transform origin { get { return _head.parent; } }
public new Camera camera { get; private set; }
[SerializeField]
private Transform _ears;
public Transform ears { get { return _ears; } }
public Ray GetRay()
{
return new Ray(_head.position, _head.forward);
}
public bool wireframe = false;
#if UNITY_2017_2_OR_NEWER
static public float sceneResolutionScale
{
get { return XRSettings.eyeTextureResolutionScale; }
set { XRSettings.eyeTextureResolutionScale = value; }
}
#else
static public float sceneResolutionScale
{
get { return XRSettings.renderScale; }
set { if (value == 0) return; XRSettings.renderScale = value; }
}
#endif
#region Enable / Disable
void OnDisable()
{
SteamVR_Render.Remove(this);
}
void OnEnable()
{
// Bail if no hmd is connected
var vr = SteamVR.instance;
if (vr == null)
{
if (head != null)
{
head.GetComponent<SteamVR_TrackedObject>().enabled = false;
}
enabled = false;
return;
}
// Convert camera rig for native OpenVR integration.
var t = transform;
if (head != t)
{
Expand();
t.parent = origin;
while (head.childCount > 0)
head.GetChild(0).parent = t;
// Keep the head around, but parent to the camera now since it moves with the hmd
// but existing content may still have references to this object.
head.parent = t;
head.localPosition = Vector3.zero;
head.localRotation = Quaternion.identity;
head.localScale = Vector3.one;
head.gameObject.SetActive(false);
_head = t;
}
if (ears == null)
{
var e = transform.GetComponentInChildren<SteamVR_Ears>();
if (e != null)
_ears = e.transform;
}
if (ears != null)
ears.GetComponent<SteamVR_Ears>().vrcam = this;
SteamVR_Render.Add(this);
}
#endregion
#region Functionality to ensure SteamVR_Camera component is always the last component on an object
void Awake()
{
camera = GetComponent<Camera>(); // cached to avoid runtime lookup
ForceLast();
}
static Hashtable values;
public void ForceLast()
{
if (values != null)
{
// Restore values on new instance
foreach (DictionaryEntry entry in values)
{
var f = entry.Key as FieldInfo;
f.SetValue(this, entry.Value);
}
values = null;
}
else
{
// Make sure it's the last component
var components = GetComponents<Component>();
// But first make sure there aren't any other SteamVR_Cameras on this object.
for (int i = 0; i < components.Length; i++)
{
var c = components[i] as SteamVR_Camera;
if (c != null && c != this)
{
DestroyImmediate(c);
}
}
components = GetComponents<Component>();
if (this != components[components.Length - 1])
{
// Store off values to be restored on new instance
values = new Hashtable();
var fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var f in fields)
if (f.IsPublic || f.IsDefined(typeof(SerializeField), true))
values[f] = f.GetValue(this);
var go = gameObject;
DestroyImmediate(this);
go.AddComponent<SteamVR_Camera>().ForceLast();
}
}
}
#endregion
#region Expand / Collapse object hierarchy
#if UNITY_EDITOR
public bool isExpanded { get { return head != null && transform.parent == head; } }
#endif
const string eyeSuffix = " (eye)";
const string earsSuffix = " (ears)";
const string headSuffix = " (head)";
const string originSuffix = " (origin)";
public string baseName { get { return name.EndsWith(eyeSuffix) ? name.Substring(0, name.Length - eyeSuffix.Length) : name; } }
// Object hierarchy creation to make it easy to parent other objects appropriately,
// otherwise this gets called on demand at runtime. Remaining initialization is
// performed at startup, once the hmd has been identified.
public void Expand()
{
var _origin = transform.parent;
if (_origin == null)
{
_origin = new GameObject(name + originSuffix).transform;
_origin.localPosition = transform.localPosition;
_origin.localRotation = transform.localRotation;
_origin.localScale = transform.localScale;
}
if (head == null)
{
_head = new GameObject(name + headSuffix, typeof(SteamVR_TrackedObject)).transform;
head.parent = _origin;
head.position = transform.position;
head.rotation = transform.rotation;
head.localScale = Vector3.one;
head.tag = tag;
}
if (transform.parent != head)
{
transform.parent = head;
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
while (transform.childCount > 0)
transform.GetChild(0).parent = head;
#if !UNITY_2017_2_OR_NEWER
var guiLayer = GetComponent<GUILayer>();
if (guiLayer != null)
{
DestroyImmediate(guiLayer);
head.gameObject.AddComponent<GUILayer>();
}
#endif
var audioListener = GetComponent<AudioListener>();
if (audioListener != null)
{
DestroyImmediate(audioListener);
_ears = new GameObject(name + earsSuffix, typeof(SteamVR_Ears)).transform;
ears.parent = _head;
ears.localPosition = Vector3.zero;
ears.localRotation = Quaternion.identity;
ears.localScale = Vector3.one;
}
}
if (!name.EndsWith(eyeSuffix))
name += eyeSuffix;
}
public void Collapse()
{
transform.parent = null;
// Move children and components from head back to camera.
while (head.childCount > 0)
head.GetChild(0).parent = transform;
#if !UNITY_2017_2_OR_NEWER
var guiLayer = head.GetComponent<GUILayer>();
if (guiLayer != null)
{
DestroyImmediate(guiLayer);
gameObject.AddComponent<GUILayer>();
}
#endif
if (ears != null)
{
while (ears.childCount > 0)
ears.GetChild(0).parent = transform;
DestroyImmediate(ears.gameObject);
_ears = null;
gameObject.AddComponent(typeof(AudioListener));
}
if (origin != null)
{
// If we created the origin originally, destroy it now.
if (origin.name.EndsWith(originSuffix))
{
// Reparent any children so we don't accidentally delete them.
var _origin = origin;
while (_origin.childCount > 0)
_origin.GetChild(0).parent = _origin.parent;
DestroyImmediate(_origin.gameObject);
}
else
{
transform.parent = origin;
}
}
DestroyImmediate(head.gameObject);
_head = null;
if (name.EndsWith(eyeSuffix))
name = name.Substring(0, name.Length - eyeSuffix.Length);
}
#endregion
}
}