Unity VR(Pico)开发

最近入手了心仪已久的 VR-Pico Neo 3,价格还不错1900¥拿下,希望 Neo 4晚点出来哈,不然感觉会亏死!基于 Unity 引擎的基础 XR 场景,主要熟悉了一下Pico的SDK引入,手柄交互控制,2D UI交互之类的API。体验了一下其实用起来还蛮简单的,官方文档嘛一言难尽,先看看下面这些Demo呗。

基于PicoVR设备进行VR开发,记录几个Demo Code,用时随时查阅此博客和官方手册。

PicoVR SDK下载地址: https://sdk.picovr.com/developer-platform/sdk

PackageManager 安装插件:

设置Player的中的参数:Android API版本,L2CPP,ARM V8,XR Plugin选择Android,Build And Run选设备:

任意点传送 —— Area

新建地面 Plane,然后给地面标记可以传送:

XR Rig 就是表示玩家自己,XR Rig 就是Plane的Teleprotaion

XR Rig的组件属性设定如下:

Locomotion System组件就是负责整个玩家的移动,Provided只负责将Locomotion System和传送目标点绑定。

关于手柄的一些设置,比如设置射线颜色,触发按钮等等:

锚点传送 —— Anchor

Teleprotaion Anchor 用于锚点传送

如果需要改变传送的位置,先创建空对象,在把Teleprotaion Anchor Transform 设置为创建的空对象即可。

手柄控制视角 —— SnapTurnProvider

XR Rig添加SnapTurnProvider组件,指定控制移动的System即可:

隔空取物组件 —— XR Grab Interactable

地面需要开启碰撞,同时物体最好也设置刚体属性,扔出去的速度调节:Throw Velocity Scale

握住把手/开关门

先建造一个门,然后需要把手柄的射线给取消掉,即 XR Ray Interactor 这个组件需要被移除掉,同时下面两个组件 XR Interactor Line Visual 和 Line Renderer是用来描述射线的,也需要被移除。

给右手手柄添加碰撞器和手柄和交互器,同时为了表示左右手的模型,把手形状的预制体加进去,在 Packages - XR Plugin下面的 Prefab下可以找到:

C#脚本/手柄交互

用左手手柄控制小球运动的Demo Code:

 1using System.Collections;
 2using System.Collections.Generic;
 3using UnityEngine;
 4using UnityEngine.XR;
 5using UnityEngine.XR.Interaction.Toolkit;
 6
 7public class PicoControllerOne : MonoBehaviour
 8{
 9    public XRController leftController;
10    // Start is called before the first frame update
11    void Start()
12    {
13        
14    }
15
16    // Update is called once per frame
17    void Update()
18    {
19        // 获取左手控制器
20        Vector2 result;
21        bool success = leftController.inputDevice.TryGetFeatureValue(CommonUsages.primary2DAxis, out result);
22
23        if (success)
24        {
25            Vector3 position = transform.position;
26            // Time.deltaTime 帧间时间:为了移动更加平滑
27
28            float value = 0.2f;
29            transform.position = new Vector3(position.x + result.x * value * Time.deltaTime, position.y, position.z + result.y * value * Time.deltaTime);
30        }
31        
32        // 握把键按下的值为多少(0 - 1之间的值)
33        leftController.inputDevice.TryGetFeatureValue(CommonUsages.grip, out float floatResult);
34        
35        // 菜单键
36        leftController.inputDevice.TryGetFeatureValue(CommonUsages.menuButton, out bool menuClicked);
37
38        // 用这种方式也是OK的
39        InputHelpers.IsPressed(leftController.inputDevice, InputHelpers.Button.Grip, out menuClicked, 0.8f);
40    }
41}

2D UI绘制与界面

XR -> 创建Canvas

2D UI的点击事件,其实很简单和平时的Unity开发没什么两样,先弄一个空物体挂上脚本,里面写好点击事件回调或者其他回调,然后在Unity里绑定即可:

 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using UnityEngine;
 5using UnityEngine.UI;
 6
 7public class UIController : MonoBehaviour
 8{
 9
10    public Text NumberText;
11    public Slider NumberSlider;
12    public void addNumberClick()
13    {
14        int num = Int32.Parse(NumberText.text);
15        NumberText.text = num + 1 + "";
16    }
17    
18    public void subNumberClick()
19    {
20        int num = Int32.Parse(NumberText.text);
21        NumberText.text = num - 1 + "";
22    }
23
24    public void SliderChange(Single value)
25    {
26        NumberText.text = value + "";
27    }
28    // Start is called before the first frame update
29    void Start()
30    {
31        
32    }
33
34    // Update is called once per frame
35    void Update()
36    {
37        
38    }
39}

射线点击事件回调

XR Grab Interactable 会有抓取的效果,但是 XR Simple Interactable就只有回调,而不是抓取。

射线为照射到小球为灰色,照射到时为蓝色,按下为红色,取消变为蓝色,射线不照射小球恢复灰色的例子:

 1using System.Collections;
 2using System.Collections.Generic;
 3using UnityEngine;
 4using UnityEngine.XR.Interaction.Toolkit;
 5
 6public class SimpleInteractController : MonoBehaviour
 7{
 8
 9    public GameObject gameObject;
10
11    public Material blue, red, grey, green, yellow;
12    // 选中点击按住
13    public void onSelected(XRBaseInteractor interactor)
14    {
15        gameObject.GetComponent<MeshRenderer>().material = red;
16    }
17    // 选中点击松开
18    public void onDeSelected(XRBaseInteractor interactor)
19    {
20        gameObject.GetComponent<MeshRenderer>().material = blue;
21    }
22    
23    // 射线悬停在球上的时候
24    public void onHoverEnter(XRBaseInteractor interactor)
25    {
26        gameObject.GetComponent<MeshRenderer>().material = blue;
27    }
28    
29    // 射线取消悬停在球上的时候
30    public void onHoverExit(XRBaseInteractor interactor)
31    {
32        gameObject.GetComponent<MeshRenderer>().material = grey;
33    }
34    
35    // 选中时按下Trigger进入Active
36    public void onActived(XRBaseInteractor interactor)
37    {
38        gameObject.GetComponent<MeshRenderer>().material = yellow;
39    }
40    // 选中时松开Trigger进入DeActive
41    public void onDeActived(XRBaseInteractor interactor)
42    {
43        gameObject.GetComponent<MeshRenderer>().material = green;
44    }
45    // Start is called before the first frame update
46    void Start()
47    {
48        
49    }
50
51    // Update is called once per frame
52    void Update()
53    {
54        
55    }
56}