注意:此入门指南仅适用于 Unity Old Input System!现 SteamVR 支持 New Input System
开发平台:Unity 2019版本以上
头显设备介绍
- HTC Vive 由HTC与Value联合开发的一款VR头显(虚拟现实头戴式显示器)产品。
- 支持 SteamVR 技术
- VR主机:(最低配置)含机箱、显示器、键鼠及备用电缆、插线板
- 显卡:NVIDIA GTX 970/AMD 290 级别或更高(建议参考官网展示信息)
- 内存:4GB 以上
- 处理器:因特i5以上
- USB版本:2.0 及其以上
- 前往 Steam 平台,搜索 Steam VR 下载安装
- 该工具用于检查虚拟设备连接情况,与设置活动环境。
- 前往 Unity Asset Store 下载资源 “SteamVR Plugin”
常见交互方式:一头盔、二手柄、三手柄 思路:
- 找到交互手柄,追踪脚本Index查找,在
Start()
函数中获取追踪脚本
private SteamVR_TrackedObject trackedObj;
void Start()
{
trackedObj = GetComponent();
}
- 在
Update()
函数中通过控制器找到索引
void Update()
{
// 通过控制器获取键位
var device = SteamVR_Controller.Input((int)trackedObj.index);
// 获取手柄具体某一键位
if(device.GetPress(SteamVR_Controller.ButtonMask.Trigger))
{
print("玩家按下扳机键");
}
// 通过openvr_api实现调用
if(device.GetTouchDown(Value.VR.EVRButtonId.k_Button_SteamVR_Touchpad))
{
print("玩家按下触摸板");
}
// 手柄震动反馈
if(device.GetHairTrigger())
{
// 震动灵敏度 0-3999
device.TriggerHapticPulse(1000, EVRButtonId.k_EButton_Grip);
}
}
- 获取不同的按键状态:点击(按下、持续按下、抬起)触摸(开始触摸、持续触摸、结束触摸)
- 手柄键位:扳机键(Trigger)、触摸板(TouchPad)、侧键(2个 Grip)、菜单键(Application)、系统键(System)
其他:脚本无法正常调用或运作情况下,重启VR设备即可解决。
SteamVR 触摸板分区常见触摸板分区效果:计算角度实现不同区域(0~360°)
- 初始点位置,判断位置在哪一轴向(x/y轴)
- 旋转方向(顺时针、逆时针)
private float GetAngle(Vector2 from, Vector2 to)
{
float angle;
// 返回角度,不分正负
angle = Vector2.Angle(from, to);
// 获取两向量夹角
Vector3 cross = Vector3.Cross(from, to);
return cross.z > 0 ? -angle : angle ;
}
- 角度大小 (Unity中支持 0° ~ 180°/-180° ~ 0°)
Vector2 from = new Vector2(0, 0);
Vector2 to = device.GetAxis();
//角度计算
float angle = GetAngle(from, to);
//判断
if(angle > 45 && angle VRTK -> Setup Interactable Object 打开 Setup Object 窗口
VRTK_SDK Object Alias
:配置Body/Head
- 添加
VRYKUICanvas
组件 (1)创建 Canvas,并修改 Render Mode 为 World Space (2)为 Canvas 添加VRTK_UICanvas.cs
组件 (3)添加 Button - 手柄添加
VRTK_pointer
其他
VRTK_Controller Tooltip
:按钮引导显示 VRTK_Controller Events_Unity Events
:Unity事件触发方法 VRTK_Interact Touch
:触摸脚本 VRTK_Interact Use
:射线检测 VRTK_Interact Grab
:拾取脚本
被射线检测物体或交互物体脚本需要继承VRTK_InteractableObject
,被交互对象不可设置为Static
public class Door : VRTK_InteractableObject {
private bool isOpen = false;
public override void StartUsing(VRTK_InteractUse currentUsingObject = null) {
base.StartUsing(currentUsingObject);
transform.rotation = Quaternion.Euler(new Vector3(0, 0, 0));
if(isOpen) transform.Rotate(new Vector3(0, -90, 0));
else transform.Rotate(new Vector3(0, 0, 0));
isOpen = !isOpen;
}
}
VRTK 材质变更
存储材质数据FloorMatData.cs
using UnityEngine;
using Dot.Tweening;
[System.Serializable]
public class FloorMatData {
public Material floorMat;
public Sprite image;
}
切换材质FloorMatList.cs
using UnityEngine;
public class FloorMatList : MonoBehaviour {
public Transform imageBg;
public bool isShowMat = false;
public FloorMatData[] matDataList;
public GameObject buttonMat;
public GameObject floor;
void Start() {}
void Update() {}
private void Init() {
imageBg.localScale = new Vector3(0, 1, 1);
foreach(var item in matDataList) {
GameObject cloneButton = Instantiate(buttonMat);
cloneButton.transform.parent = imageBg;
cloneButton.GetComponent();
rect.localPosition = Vector3.zero;
rect.localRotation = Quaternion.Euler(Vector3.zero);
rect.localSacle = Vector3.zero;
cloneButton.GetComponent().sprite = data.image;
cloneButton.GetComponent().onClick.AddListener(delegate() { OnButtonClick(cloneButton);})
}
}
public void ShowMatList() {
if(isShowMat) {
imageBg.DOScale(new Vector3(0, 1, 1), 0.3f);
}
else {
imageBg.DOScale(Vector3.one, 0.3f);
}
isShowMat = !isShowMat;
}
private void OnButtonClick(GameObject button) {
// 修改图片材质
floor.GetComponent().material = matDataList[button.transform.GetSiblingIndex()].floorMat;
}
}