# VR [toc] # VR 環境設置 1. `Project Setting / XR Plug-in Management` 下載 OpenXR ![](https://i.imgur.com/kmFyQYu.png) ![](https://i.imgur.com/G4unuNG.png) ![](https://i.imgur.com/6XzwuqL.png) 2. 將 `Project Setting / OpenXR` 打開後在 `Interaction Profiles` 加入自己的VR裝置 將 `Render Mode` 改成 `Multi Pass` ![](https://i.imgur.com/1q3TENd.png) 3. 下載 XR Interaction Toolkit ![](https://i.imgur.com/93ZC4Px.png) # VR基礎設備設定 ## VR headset 頭盔轉動 1. 建立一個空物件叫 `VR Rig` ,並未這個空物件加入新元件 `XR Origin` ![](https://i.imgur.com/aDw84Nh.png) 2. 為 `VR Rig` 物件新增一個子物件名為 `Camera Offset` ![](https://i.imgur.com/QBv899U.png) 3. 為 `Camera Offset` 物件新增一個Camera子物件並命名為 `VR Camera` ![](https://i.imgur.com/mSG3zQA.png) ![](https://i.imgur.com/243lapM.png) 4. 在`VR Camera` 底下新增一個新的元件 `Traked Pose Driver` ![](https://i.imgur.com/c1sN48U.png) 5. 將 `VR Rig` 底下的 `XR Origin` 元件分別放入 `Camera Offset` 、 `VR Camera` 進去 ![](https://i.imgur.com/jUnYZLp.png) 6. 將`VR Rig` 的 `XR Origin` 元件的欄位 Tracking Origin Mode 改為 Floor ![](https://i.imgur.com/bPD69U3.png) ## VR 左右手 1. 在 `Camera Offset` 底下建立兩個空的子物件分別命名為 `Left Hand` 、 `Right Hand` 2. 選左右手物件並將兩個物件都加入 `XR Controller (Device-based)` ![](https://i.imgur.com/7hfs5HD.png) 3. 將 `Controller Node` 改成左右手 ![](https://i.imgur.com/0E4nNKa.png) ## 製作暫時的方塊雙手 1. 在 `Hierarchy` 新增一個空的物件叫 `VR Controller`,並在該物件底下新增一個子物件 3D Cube,確保`VR Controller` 、 Cube 的 `Position` 都是`(0,0,0)`。 ![](https://i.imgur.com/g5kJBgE.png) Cube參考大小 ![](https://i.imgur.com/7nEIRfv.png) 2. 將 `VR Controller` 拉到 `Project` 變成 `Prefab` 3. 將Prefab放到左右上 ![](https://i.imgur.com/wPSAj4u.png) - 常見問題: 手臂過遠或不精準 - 解決1: 確保Cube在一個空物件底下(`VR Controller`) - 解決2: 確保`VR Controller` 、 Cube 的 `Position` 都是`(0,0,0)` ## 雙手抓取物件 1. **左右手** 新增元件 `XR Direct Interactor` 跟 `Sphere Collider` ![](https://i.imgur.com/vY3a52w.png) `Sphere Collider` 設為 trigger :heavy_check_mark: ![](https://i.imgur.com/hdZrLXd.png) 2. 將**被抓取**的物體加上 `Collider` 、 `Rigibody` 、`XR Grab Interactable` ![](https://i.imgur.com/Ur6i5S2.png) ## VR Input 找到手把的輸入值跟對應名稱 ![](https://i.imgur.com/ebZN8Mx.png) ![](https://i.imgur.com/ePgSy2c.png) `Window / Analysis / XR Interaction Debugger` 打開後按下 play ,操控手把即可觀察數值以及對應名稱 ![](https://i.imgur.com/kMf0V3l.png) HTC VIVE 不知道為何沒辦法看到abxy按鈕的數值,但是當加入Oculus之後就可以從Oculus裡面觀察到按鈕是有被使用的,且對應的名稱是什麼。 ![](https://i.imgur.com/PlEApCu.png) ### 對應的手把按鈕 [載入兩個 package](https://drive.google.com/drive/folders/166jb0M8mDYT1YaYR9RrtabZbpPuiMpEd?usp=sharing) : `Oculus Hands` 、 `VR Controllers Model-FIXED` ```csharp= using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR; public class Open_Menu : MonoBehaviour { InputDevice targetDevice; InputDeviceCharacteristics desiredCharacteristics = InputDeviceCharacteristics.Right | InputDeviceCharacteristics.Controller; bool get = false; private void Start() { StartCoroutine("wait"); } // Update is called once per frame void Update() { if (get) { targetDevice.TryGetFeatureValue(CommonUsages.primaryButton, out bool _primaryButton); if (_primaryButton) { Debug.Log("案到了"); } } } IEnumerator wait() { yield return new WaitForSeconds(1f); List<InputDevice> devices = new List<InputDevice>(); //「InputDevices」 class to access input devices that are currently connected to the XR system. InputDevices.GetDevicesWithCharacteristics(desiredCharacteristics,devices); //To get a list of all connected devices, use InputDevices.GetDevices if (devices.Count > 0) { targetDevice = devices[0]; } get = true; } } ``` - PrimaryButton (HTC Vive 沒有支援這個按鈕) ```csharp InputDevice.TryGetFeatureValue(CommonUsages.primaryButton, out bool primaryButtonValue); ``` - triggerButton ```csharp= InputDevice.TryGetFeatureValue(CommonUsages.trigger, out float triggerValue); ``` - primary2DAxis 蘑菇頭 ```csharp= targetDevice.TryGetFeatureValue(CommonUsages.primary2DAxis, out Vector2 primary2DAxisValue); ``` ### 放入搖桿建模替代方形手 1. 建立兩個空物件分別叫 `Left Hand Presence` 、`Right Hand Presence`,並將以下程式碼都加入兩個物件底下。 ```csharp= using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR; public class HandPresence : MonoBehaviour { public bool showController = false; //展示手或搖桿其中一個 public InputDeviceCharacteristics controllerCharacteristics; public List<GameObject> controllerPrefabs; //搖桿模型 public GameObject handModelPrefab; //手模型 private InputDevice targetDevice; private GameObject spawnedController; private GameObject spawnedHandModel; void Start() { StartCoroutine(GetDevices(1.0f)); } void Update() { if (showController) { spawnedHandModel.SetActive(false); spawnedController.SetActive(true); } else { spawnedHandModel.SetActive(true); spawnedController.SetActive(false); } } IEnumerator GetDevices(float delayTime) { //Vive啟動的時間會晚一點所以不能放在start()裡面執行 yield return new WaitForSeconds(delayTime); List<InputDevice> devices = new List<InputDevice>(); //controllerCharacteristics設為右手跟遊戲控制器,則為在devices這個List裡面抓取有「右手」跟「遊戲控制器」特徵的InputDevice //controllerCharacteristics設為左手跟遊戲控制器,則為在devices這個List裡面抓取有「左手」跟「遊戲控制器」特徵的InputDevice InputDevices.GetDevicesWithCharacteristics(controllerCharacteristics, devices); foreach (var item in devices) { Debug.Log(item.name + item.characteristics); } if (devices.Count > 0) { targetDevice = devices[0]; GameObject prefab = controllerPrefabs[0]; spawnedController = Instantiate(prefab, transform); //生成左右手 } spawnedHandModel = Instantiate(handModelPrefab, transform); //生成手 } } ``` 2. 在 Inspector 選擇特徵 - 左手搖桿 ![](https://i.imgur.com/IH2BahR.png) - 左手加入搖桿的建模 ![](https://i.imgur.com/9ZCyTYD.png) - 右手搖桿 ![](https://i.imgur.com/jRLP1va.png) - 右手加入搖桿的建模 ![](https://i.imgur.com/CsTClLS.png) 3. 將 Hierarchy 的兩個物件 `Left Hand` 、`Right Hand` 底下的元件`Model Prefab` 放入搖桿的建模 ![](https://i.imgur.com/9AY8DdZ.png) ![](https://i.imgur.com/3oluPZo.png) 成品: ![](https://i.imgur.com/Zu1H5zC.png) # 手部動畫 使用Blend Tree完成 # Teleportation 1. 在`VR Rig`這個物件裡面加入兩個元件`Locomotion System` 、 `Teleportation Provider` 且不用幫這兩個元件的欄位放上物件,直接按play這兩個元件會自動抓取物件 ![](https://i.imgur.com/tA5lTFb.png) 2. 在`Camera Offset`物件新增一子物件`XR / Ray Interactor`,並將名稱改為`Right Teleport Ray` ![](https://i.imgur.com/qdykdEm.png) 3. 確保`Right Teleport Ray`底下的XR Controller元件是(Device-based),並將Controller Node 改為右手 ![](https://i.imgur.com/Uq3rVSY.png) 4. 將想要移動的區域加上元件`Teleportation Area`,並確保一定要有Box Collider ![](https://i.imgur.com/e56CaIY.png) # 與物件的互動 ## 開門 1. 將整個門的物件加上此元件 `XR Grab Interactable` 2. 接著我們要限制玩家只能在手把物件上才能抓到整個門 為門把加入Box Collider ![](https://i.imgur.com/el8iRSX.png) 最後將門把加入整個門的`XR Grab Interactable`元件的Collider裡面,就可以限制只有用門把才可以抓取整個後門了 ![](https://i.imgur.com/0rfFPZv.png) 3. 新增新的Layer,名為`VR Grab Ignore Ray`。 當然我們開門並不想用射線開門,我們想用手的建模開門比起射線會有更多真實感。 ![](https://i.imgur.com/eDTcKyb.png) 4. 打開`Right Teleport Ray`物件並找到`Raycast Mask`欄位,確保`VR Grab Ignore Ray`層沒有被勾選,這樣射線只能用在UI、Ground層 ![](https://i.imgur.com/Wpa5Olz.png) 5. 在門上新增一元件 `Hinge Joint` ,將開門的方式限制只能Y方向旋轉 ![](https://i.imgur.com/69ogFDI.png) 6. 將門的`XR Grab Interactable` 元件裡的Movement Type改成**Velocity Tracking**,這樣會有物理系統的表現。 ![](https://i.imgur.com/5wEhJRe.png) ## VR UI 互動 1. Canvas 的 `Render Mode` 必須是 `World Space`。 2. 為Canvas加入一個元件名子為`Tracked Device Graphic Raycaster`後不需要對元件做任何事。 3. 將EventSystem新增一元件`XR UI Input Module`,並把不需要的刪除 ![](https://i.imgur.com/H0bjit5.png)