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:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit;

public class PicoControllerOne : MonoBehaviour
{
    public XRController leftController;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        // 获取左手控制器
        Vector2 result;
        bool success = leftController.inputDevice.TryGetFeatureValue(CommonUsages.primary2DAxis, out result);

        if (success)
        {
            Vector3 position = transform.position;
            // Time.deltaTime 帧间时间:为了移动更加平滑

            float value = 0.2f;
            transform.position = new Vector3(position.x + result.x * value * Time.deltaTime, position.y, position.z + result.y * value * Time.deltaTime);
        }
        
        // 握把键按下的值为多少(0 - 1之间的值)
        leftController.inputDevice.TryGetFeatureValue(CommonUsages.grip, out float floatResult);
        
        // 菜单键
        leftController.inputDevice.TryGetFeatureValue(CommonUsages.menuButton, out bool menuClicked);

        // 用这种方式也是OK的
        InputHelpers.IsPressed(leftController.inputDevice, InputHelpers.Button.Grip, out menuClicked, 0.8f);
    }
}

2D UI绘制与界面

XR -> 创建Canvas

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

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIController : MonoBehaviour
{

    public Text NumberText;
    public Slider NumberSlider;
    public void addNumberClick()
    {
        int num = Int32.Parse(NumberText.text);
        NumberText.text = num + 1 + "";
    }
    
    public void subNumberClick()
    {
        int num = Int32.Parse(NumberText.text);
        NumberText.text = num - 1 + "";
    }

    public void SliderChange(Single value)
    {
        NumberText.text = value + "";
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

射线点击事件回调

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

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

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;

public class SimpleInteractController : MonoBehaviour
{

    public GameObject gameObject;

    public Material blue, red, grey, green, yellow;
    // 选中点击按住
    public void onSelected(XRBaseInteractor interactor)
    {
        gameObject.GetComponent<MeshRenderer>().material = red;
    }
    // 选中点击松开
    public void onDeSelected(XRBaseInteractor interactor)
    {
        gameObject.GetComponent<MeshRenderer>().material = blue;
    }
    
    // 射线悬停在球上的时候
    public void onHoverEnter(XRBaseInteractor interactor)
    {
        gameObject.GetComponent<MeshRenderer>().material = blue;
    }
    
    // 射线取消悬停在球上的时候
    public void onHoverExit(XRBaseInteractor interactor)
    {
        gameObject.GetComponent<MeshRenderer>().material = grey;
    }
    
    // 选中时按下Trigger进入Active
    public void onActived(XRBaseInteractor interactor)
    {
        gameObject.GetComponent<MeshRenderer>().material = yellow;
    }
    // 选中时松开Trigger进入DeActive
    public void onDeActived(XRBaseInteractor interactor)
    {
        gameObject.GetComponent<MeshRenderer>().material = green;
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}