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