Unity开发VR——插件:HTC.UnityPlugin
插件HTC.UnityPlugin基于SteamVR插件,可以在 Assets Store 搜索HTC.UnityPlugin,免费下载;
使用该插件需要先导入SteamVR插件,也可以在 Assets Store 搜索 SteamVR,免费下载。
HTC.UnityPlugi的优势:相对于Steamvr来说,方便获取手柄按键、方便与UGUI进行交互
首先
导入SteamVR插件,若SteamVR版本为2.0以上,依次点击如下按钮
之后,导入HTC.UnityPlugin插件
PS:HTC.UnityPlugin自带示例场景位置:HTC.UnityPlugin - ViveInputUtility - Examples - 下级目录0至7文件夹内,每个文件夹含一个示例
HTC.UnityPlugin自带 预 制 体 位置:HTC.UnityPlugin - ViveInputUtility - Prefabs
认识手柄按键
VR视角
删除场景中自带的Main Camera,将预制体ViveRig拖入大场景中
抓取物体
1. 被抓取的物体需带有碰撞器
2. 在被抓取的物体上添加脚本 BasicGrabbable
PS:物体B、C、D、E……是物体A的父物体
物体A挂载脚本BasicGrabbable,子物体不挂载该脚本
移动 B、C、D、E……任何一个物体,物体A下的所以子物体均会同步移动
物体A挂载脚本BasicGrabbable,子物体也挂载该脚本
只有在移动物体A时,物体A下的所以子物体才会同步移动,移动其中一个子物体时,其父物体和其余子物体不会跟着移动
若需要物体在放手之后做物理运动,则需要给物体添加Rigidbody组件
若需要拿起物体之后隐藏手部模型,需要给脚本BasicGrabbable赋值,并选择方法,如下图:
PS:获得射线检测到的物体
玩家移动
1. 在要移动的地面上添加脚本Teleportable,赋值方法如下:
2. 运行程序,按住TouchPad出现钓鱼线;松开按键后移动到钓鱼线落下的位置
PS:将可以移动的区域放在同一个父物体下,给这个父物体添加Teleportable脚本,那么这些区域就都可以移动。
射线移动物体
1. 将预制体 VivePointers 拖入场景中,作为ViveRig的子物体,并把TransFrom Rest;
2. 在被移动的物体上添加脚本 Draggable。
射线点击UGUI
1. 射线出现的方式
(1)按 Menu 键会出现与UI交互的射线,但此时手柄碰撞器消失,不能进行碰撞检测;再次按 Menu 键,与UI交互的射线消失,此时手柄可以进行碰撞检测;
(2)将预制体 VivePointers 拖入场景中,作为ViveRig的子物体,并把TransFrom Rest,射线会一直出现,并且手柄也可以进行射线检测;
2. 创建一个UI,如:Button;
3. 在Canvas面板添加脚本 CanvasRaycastTarget;
4. 删除场景中的游戏物体“EventSystem”(经测试不删也没有问题,但是在运行时程序会自动创建一个 EventSystem ,最好还是删掉)。
替换手柄模型
1. 设置预制体属性:ViveRig - ViveControllers - Right - RenderModel - DeviceTracker - OpenVRRenderModel 的脚本“RenderModelHook”,将 OverrideModel 设置为 IndexHMD(OverrideModel中有多种模型可供选择,可以在运行情况下尝试)
2. 把要替换的模型作为OpenVRRenderModel的子物体(如果第一步不选择IndexHMD,那么要替换的模型会和手柄模型一起出现)
设置钓鱼线
以右手为例:
线:ViveRig - ViveControllers - Right - CurvePointer - GuideLine
落地点:ViveRig - ViveControllers - Right - CurvePointer - Reticle - Puramid - default
可通过上述属性,设置钓鱼线的材质、网格
设置钓鱼线的远近:ViveRig - ViveControllers - Right - CurvePointer - StablizedDeviceTracker - Caster 的脚本“ProjectileGenerator”的属性:Velocity
替换UI交互射线
相对于预制体:VivePointers
射线的位置:VivePointers - Right - Reticle - GuideLine
终点小球的位置:VivePointers - Right - Reticle - Sphere - Mesh
终点小球的材质:VivePointers - Right - Reticle 的脚本 ReticlePoser 的属性 DefaultReticleMat
可通过上述属性,设置钓鱼线的材质、网格
相对于预制体:ViveRig
射线的位置:ViveRig - ViveControllers - Right - Laser Pointer - Reticle - GuideLine
终点小球的位置:ViveRig - ViveControllers - Right - Laser Pointer - Reticle - Sphere - Mesh
可通过上述属性,设置钓鱼线的材质、网格
得到手柄按键
可以复制代码到工程中进行测试,自行领会;注意,脚本名和类名一致:TestHandKey
using System.Collections; using System.Collections.Generic; using UnityEngine; // 引入该命名空间 using HTC.UnityPlugin.Vive; public class TestHandKey : MonoBehaviour { // 给按键添加事件(以 Menu 为例) private void Awake() { #if false // 按住不放:右手的 Menu键 调用方法一 ViveInput.AddPress(HandRole.RightHand, ControllerButton.Menu, One); // 按下:右手的 Menu键 调用方法二 ViveInput.AddPressDown(HandRole.RightHand, ControllerButton.Menu, Two); // 点击:右手的 Menu键 调用方法三(点击:按下之后立刻抬起才会响应,按住不放 一段时间后再放开,则不会调用) ViveInput.AddClick(HandRole.RightHand, ControllerButton.Menu, Three); #endif } // 方法一 private void One() { print("调用了 方法一"); } // 方法二 private void Two() { print("调用了 方法二"); } // 方法三 private void Three() { print("调用了 方法三"); } // 测试按键的按下、按住、抬起 private void Update() {
#if false // 打印 Trigger 的返回值 print("Trigger的返回值为:" + ViveInput.GetTriggerValue(HandRole.RightHand, false)); // 打印 Pad 的坐标值 print("Pad的坐标:" + ViveInput.GetPadAxis(HandRole.RightHand, false)); #endif #if true // Menu if (ViveInput.GetPressDown(HandRole.RightHand, ControllerButton.Menu)) { print("右手 - Menu - 按下"); } else if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.Menu)) { print("右手 - Menu - 按住不放"); } else if (ViveInput.GetPressUp(HandRole.RightHand, ControllerButton.Menu)) { print("右手 - Menu - 抬起"); } // Trigger if (ViveInput.GetPressDown(HandRole.RightHand, ControllerButton.Trigger)) { print("右手 - Trigger - 按下"); } else if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.Trigger)) { print("右手 - Trigger - 按住不放"); } else if (ViveInput.GetPressUp(HandRole.RightHand, ControllerButton.Trigger)) { print("右手 - Trigger - 抬起"); } // pad(是否触摸到pad,通过判断GetPadAxis的返回时是否是(0,0)来判断) if (ViveInput.GetPressDown(HandRole.RightHand, ControllerButton.Pad)) { print("右手 - Pad - 按下"); } else if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.Pad)) { print("右手 - Pad - 按住不放"); } else if (ViveInput.GetPressUp(HandRole.RightHand, ControllerButton.Pad)) { print("右手 - Pad - 抬起"); } // Grip if (ViveInput.GetPressDown(HandRole.RightHand, ControllerButton.Grip)) { print("右手 - Grip - 按下"); } if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.Grip)) { print("右手 - Grip - 按住不放"); } if (ViveInput.GetPressUp(HandRole.RightHand, ControllerButton.Grip)) { print("右手 - Grip - 抬起"); } #endif #if false // Trigger 轻按、重按、按到底 if (ViveInput.GetPressDown(HandRole.RightHand, ControllerButton.HairTrigger)) { print("Trigger - 轻按"); } else if (ViveInput.GetPressDown(HandRole.RightHand, ControllerButton.Trigger)) { print("Trigger - 重按"); } else if (ViveInput.GetPressDown(HandRole.RightHand, ControllerButton.FullTrigger)) { print("Trigger - 按到底"); } #endif #if false // GetPadTouchAxis:触摸 就会返回坐标值 print(ViveInput.GetPadTouchAxis(HandRole.RightHand)); // 从左向右滑,横坐标为正; 从右向左滑,横坐标为负; 从下向上滑,纵坐标为正; 从上向下滑,纵坐标为负 print(ViveInput.GetPadTouchDelta(HandRole.RightHand)); // GetPadTouchVector:以开始触摸点为(0,0),若触摸点为pad的最下方,当手指滑到最上方时坐标值为(0,2) print(ViveInput.GetPadTouchVector(HandRole.RightHand)); // GetPadTouchAxis 为触摸反馈;GetPadPressAxis 为按住反馈 print(ViveInput.GetPadPressAxis(HandRole.RightHand)); print(ViveInput.GetPadPressDelta(HandRole.RightHand)); print(ViveInput.GetPadPressVector(HandRole.RightHand)); #endif } }