本章節主要講解使用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;//右手柄激活
}
}
下一章我主要介紹手柄和射線事件的相結合代碼,以及拋物線的繪制和移動,歡迎大家關注
