首页 > 技术文章 > Unity开发VR——插件:HTC.UnityPlugin

kao-la-bao-bei 2020-04-26 17:28 原文

插件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 } }

 

 

推荐阅读