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()
{
}
}