本章節主要講解使用SteamVR Plugins插件為基礎,來介紹Vive開發的入門,重點講解設備的激活和控制接口。SteamVR Plugins在unity官方資源商店可以免費下載,這里我就不給出鏈接了。
導入SteamVR Plugins后,不要在他的示例上去做開發,那樣你會走彎路。因為這個插件的設備初始化代碼很怪異,甚至可以說無法使用。因此我們需要自己寫設備的初始化代碼以及設備的操作接口。
我們對原插件進行封裝后就可以愉快的使用了,之后怎么開發就和這個設備無關了,我們開發這類的應用無非是獲取相關的接口操作。
新建場景,然后在Camera上添加組件SteamVR_Camera,然后點擊 Expand 按鈕,之后我們就得到了一個基本的VR相機。
然后我們在Camera的下面新建兩個GameObject,並命名為LeftHand和RightHand。同時添加組件SteamVR_TrackedObject。然后在各自的下面添加一個對象名為Mode,並綁定組件SteamVR_RenderModel。
如果對這些步驟有疑問,可以查看百度文庫按照上面的操作完成基本的對象搭建操作:http://wenku.baidu.com/view/eaaec2f058fb770bf68a55b1.html
接下來就是開始擼代碼了,新建腳本SteamVR_InitManager.cs,來獲取手柄的激活和相關的初始化代碼。
using UnityEngine; using System.Collections; using Valve.VR; using System; public class SteamVR_InitManager : MonoBehaviour { public event Action<SteamVR_TrackedObject> OnLeftDeviceActive;//左手柄激活事件 public event Action<SteamVR_TrackedObject> OnRightDeviceActive;//右手柄激活事件 public SteamVR_TrackedObject LeftObject; public SteamVR_TrackedObject RightObject; private bool[] isAllConnect;//0代表右手狀態,1代表左手狀態 private uint leftIndex = 100;//左手柄對應的設備ID private uint rightIndex = 100;//右手柄對應的設備ID private static SteamVR_InitManager instance; public DeviceInput LeftHandInput; public DeviceInput RightHandInput; public static SteamVR_InitManager Instance { get { if (instance == null) { instance = GameObject.FindObjectOfType<SteamVR_InitManager>(); } return instance; } } // Use this for initialization void Awake() { LeftObject = transform.FindChild("LeftHand").GetComponent<SteamVR_TrackedObject>(); RightObject = transform.FindChild("RightHand").GetComponent<SteamVR_TrackedObject>(); LeftObject.gameObject.SetActive(false); RightObject.gameObject.SetActive(false); } void Start() { StartCoroutine(CheckDeviceActive()); } void OnEnable() { OnLeftDeviceActive += LeftDeviceActive; OnRightDeviceActive += RightDeviceActive; } void OnDisable() { OnLeftDeviceActive -= LeftDeviceActive; OnRightDeviceActive -= RightDeviceActive; } /// <summary> /// 檢測手柄設備是否激活 /// </summary> /// <returns></returns> IEnumerator CheckDeviceActive() { yield return new WaitForSeconds(1); while (!isAllConnect[0] || !isAllConnect[1]) { for (uint i = 1; i < OpenVR.k_unMaxTrackedDeviceCount; i++) { if (i == leftIndex || i == rightIndex) continue;//已經初始化的不再進入判斷 if (OpenVR.System != null && OpenVR.System.IsTrackedDeviceConnected(i)) { OnDeviceConnected(new object[] { i, true }); } } yield return new WaitForFixedUpdate(); } yield return 0; } /// <summary> /// 檢測激活的設備是否是手柄 /// </summary> /// <param name="args"></param> private void OnDeviceConnected(object[] args) { if (args != null && args.Length > 1) { uint index = (uint)args[0]; bool isConnect = (bool)args[1]; var system = OpenVR.System; if (isConnect && system != null && system.GetTrackedDeviceClass(index) == ETrackedDeviceClass.Controller) { uint tmpleftIndex = (uint)system.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand); uint tmprightIndex = (uint)system.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.RightHand); if (index == tmprightIndex) { isAllConnect[0] = true; rightIndex = index; OnRightDeviceActive(RightObject); } else if (index == tmpleftIndex) { isAllConnect[1] = true; leftIndex = index; OnLeftDeviceActive(LeftObject); } } } } private void RightDeviceActive(SteamVR_TrackedObject obj) { DeviceActive(obj, rightIndex); RightHandInput = obj.GetComponent<DeviceInput>(); } private void LeftDeviceActive(SteamVR_TrackedObject obj) { DeviceActive(obj, leftIndex); LeftHandInput = obj.GetComponent<DeviceInput>(); } /// <summary> /// 匹配對應的設備號,完成手柄模型的設置 /// </summary> /// <param name="device"></param> /// <param name="index"></param> void DeviceActive(SteamVR_TrackedObject device, uint index) { SteamVR_TrackedObject.EIndex eIndex = (SteamVR_TrackedObject.EIndex)Enum.Parse(typeof(SteamVR_TrackedObject.EIndex), "Device" + index); device.index = eIndex; device.GetComponentInChildren<SteamVR_RenderModel>().index = eIndex; device.gameObject.SetActive(true); } }
然后就是大家比較關心的手柄控制接口代碼DeviceInput.cs,我基本上把所有的手柄控制事件都寫完了.
using UnityEngine; using System.Collections; using System; using Valve.VR; public class DeviceInput : MonoBehaviour { //Swipe directions public enum SwipeDirection { NONE, UP, DOWN, LEFT, RIGHT }; public event Action OnPressTrigger; //按住扳機鍵 public event Action OnPressDownTrigger; // 按下扳機鍵 public event Action OnPressUpTrigger; //抬起扳機鍵 public event Action OnTouchPad; //按住觸摸板 public event Action OnPressDownGripButton; //按下側鍵 public event Action OnPressDownMenuButton; //按下菜單鍵 public event Action<Vector2> OnBeginTouch; //觸摸觸摸板的位置 public event Action<Vector2> OnEndTouch;//抬起觸摸板的位置 public event Action OnTouchPadDown; //按下觸摸板 public event Action OnTouchPadUp;//抬起觸摸板 public event Action<SwipeDirection> OnPadSwipe; [SerializeField] private float m_SwipeWidth = 0.6f; //The width of a swipe private Vector2 m_PadDownPosition; private float m_LastHorizontalValue; private float m_LastVerticalValue; private SteamVR_TrackedObject Hand; private SteamVR_Controller.Device device; private Vector2 m_PadPosition; public void Start() { Hand = GetComponent<SteamVR_TrackedObject>(); } public void Update() { CheckInput(); } private void CheckInput() { // Set the default swipe to be none. SwipeDirection swipe = SwipeDirection.NONE; if (device == null) { device = SteamVR_Controller.Input((int)Hand.index); print("NUll Device"); return; } if (device.GetPress(EVRButtonId.k_EButton_SteamVR_Trigger)) { if (OnPressTrigger != null) OnPressTrigger(); } if (device.GetPressDown(EVRButtonId.k_EButton_SteamVR_Trigger)) { if (OnPressDownTrigger != null) OnPressDownTrigger(); } if (device.GetPressUp(EVRButtonId.k_EButton_SteamVR_Trigger)) { if (OnPressUpTrigger != null) OnPressUpTrigger(); } if (device.GetTouch(EVRButtonId.k_EButton_SteamVR_Touchpad)) { if (OnTouchPad != null) OnTouchPad(); m_PadPosition = device.GetAxis(); } if (device.GetTouchUp(EVRButtonId.k_EButton_SteamVR_Touchpad)) { if (OnTouchPadUp != null) OnTouchPadUp(); if (OnEndTouch != null) OnEndTouch(m_PadPosition); swipe = DetectSwipe(); m_PadDownPosition = Vector2.zero; } if (device.GetTouchDown(EVRButtonId.k_EButton_SteamVR_Touchpad)) { if (OnTouchPadDown != null) OnTouchPadDown(); if (OnBeginTouch != null) OnBeginTouch(m_PadDownPosition = device.GetAxis()); } if (device.GetPressDown(EVRButtonId.k_EButton_Grip)) { if (OnPressDownGripButton != null) { OnPressDownGripButton(); } } if (device.GetPressDown(EVRButtonId.k_EButton_ApplicationMenu)) { if (OnPressDownMenuButton != null) OnPressDownMenuButton(); } if (swipe != SwipeDirection.NONE) { OnPadSwipe(swipe); if (device.GetTouch(EVRButtonId.k_EButton_SteamVR_Touchpad)) { m_PadPosition = device.GetAxis(); } else { m_PadDownPosition = Vector2.zero; } } } private SwipeDirection DetectSwipe() { Vector2 swipeData = (m_PadPosition - m_PadDownPosition).normalized; bool swipeIsVertical = Mathf.Abs(swipeData.y) > m_SwipeWidth; bool swipeIsHorizontal = Mathf.Abs(swipeData.x) > m_SwipeWidth; if (swipeData.y > 0f && swipeIsVertical) return SwipeDirection.UP; if (swipeData.y < 0f && swipeIsVertical) return SwipeDirection.DOWN; if (swipeData.x > 0f && swipeIsHorizontal) return SwipeDirection.RIGHT; if (swipeData.x < 0f && swipeIsHorizontal) return SwipeDirection.LEFT; return SwipeDirection.NONE; } public void OnDisEnable() { OnPressTrigger = null; //按住扳機鍵 OnPressDownTrigger = null; // 按下扳機鍵 OnPressUpTrigger = null; //抬起扳機鍵 OnTouchPad = null; //按住觸摸板 OnPressDownGripButton = null; //按下側鍵 OnPressDownMenuButton = null; //按下菜單鍵 OnBeginTouch = null; //觸摸觸摸板的位置 OnEndTouch = null;//抬起觸摸板的位置 OnTouchPadDown = null; //按下觸摸板 OnTouchPadUp = null;//抬起觸摸板 OnPadSwipe = null; } }
OK,接下來寫一個簡單的測試類來測試相關的代碼:
using UnityEngine; using System.Collections; using System; /// <summary> /// 這是一個測試類,簡單的測試了手柄的激活以及部分手柄的操作事件 /// 兩個手柄分開注冊,這樣擴展性非常好,相同的按鍵可以做不同的處理 /// 大家可以補充測試 /// </summary> public class TestEvent : MonoBehaviour { void OnEnable() { SteamVR_InitManager.Instance.OnLeftDeviceActive += OnLeftDeviceActive;//左手柄激活 SteamVR_InitManager.Instance.OnRightDeviceActive += OnRightDeviceActive;//右手柄激活 } private void OnRightDeviceActive(SteamVR_TrackedObject obj) { print("OnRightDeviceActive"+obj); SteamVR_InitManager.Instance.RightHandInput.OnPressDownTrigger += OnPressDownTrigger; SteamVR_InitManager.Instance.RightHandInput.OnTouchPadDown += OnTouchPadDown; } private void OnPressDownTrigger() { print("OnPressDownTrigger"); } private void OnTouchPadDown() { print("OnTouchPadDown"); } private void OnLeftDeviceActive(SteamVR_TrackedObject obj) { print("OnLeftDeviceActive" + obj); SteamVR_InitManager.Instance.LeftHandInput.OnPressDownTrigger += OnPressDownTrigger; SteamVR_InitManager.Instance.LeftHandInput.OnTouchPadDown += OnTouchPadDown; } void OnDisable() { SteamVR_InitManager.Instance.OnLeftDeviceActive -= OnLeftDeviceActive;//左手柄激活 SteamVR_InitManager.Instance.OnRightDeviceActive -= OnRightDeviceActive;//右手柄激活 } }
下一章我主要介紹手柄和射線事件的相結合代碼,以及拋物線的繪制和移動,歡迎大家關注