前言:VRTK官方插件的DOCUMENT.MD文档是英文,看起来略吃力。其教程是油管视频需要翻墙且全英文。网上的教程基本都是只覆盖到场景搭建和简单交互。远远不够实际开发需要。本人经过一段时间开发之后,把此插件中的精华部分拿出来整理以下。希望能帮到广大VR开发者。本文全干货,无废话,下面开始。
1. 场景搭建
1.1 场景中拖入StreamVR的[CameraRig]预制件(VRTK依赖SteamVR)
1.2 建立一个空物体命名比如[VRTK],添加VRTK_SDKManager
组件,根据需要选择开发平台,此处不需要一个一个选,只需要下拉选择QuickSelectSDK,和最下面的AutoPopulateLinkedObjects就行,最后的ScriptAlais...需要自己指定。
Paste_Image.pngtips: 注意每建立新场景,这个步骤必须从头做一遍,不能把别的场景里的prefab拿进来直接用。
1.3 [VRTK]下面再放置两个空物体(左右手控制器),都添加
VRTK_ControllerEvents
组件,此组件是控制器交互基础组件,必须添加
Paste_Image.png
2. 物体交互
tips: 可交互物体至少要有collider
2.1 激光束和瞬移-官方文档
- 在两个手柄上添加
VRTK_SimplePointer
或者VRTK_BezierPointer
。一个是直线,一个是贝兹曲线。勾选Enable teleport. - 在CameraRig上添加
VRTK_BasicTeleport
。
tips:
- SimplePointer/BezierPointer发送以下事件:
GetComponent<VRTK_SimplePointer>().DestinationMarkerEnter += new DestinationMarkerEventHandler(DoPointerIn);
GetComponent<VRTK_SimplePointer>().DestinationMarkerExit += new DestinationMarkerEventHandler(DoPointerOut);
GetComponent<VRTK_SimplePointer>().DestinationMarkerSet += new DestinationMarkerEventHandler(DoPointerDestinationSet);
并传递以下参数:
public float distance;
public Transform target;
public RaycastHit raycastHit;
public Vector3 destinationPosition;
public bool forceDestinationPosition;
public bool enableTeleport;
public uint controllerIndex;
- SimplePointer上附带的teleporter功能只能在平面上移动,如果想要动Y轴,请使用
VRTK_HeightAdjustTeleport
.- 所有瞬移组件会发送
Teleporting
和Teleported
事件,传递以下参数(和上面pointer参数基本一致):
float distance - The distance between the origin and the collided destination.
Transform target - The Transform of the collided destination object.
RaycastHit raycastHit - The optional RaycastHit generated from when the ray collided.
Vector3 destinationPosition - The world position of the destination marker.
Quaternion? destinationRotation - The world rotation of the destination marker.
bool forceDestinationPosition - If true then the given destination position should not be altered by anything consuming the payload.
bool enableTeleport - Whether the destination set event should trigger teleport.
uint controllerIndex - The optional index of the controller emitting the beam.
- ```VRTK_BodyPhysics```组件加入玩家身体与游戏世界的交互,并且决定其掉落物理特性 [文档](https://github.com/thestonefox/VRTK/blob/master/DOCUMENTATION.md#body-physics-vrtk_bodyphysics)。可根据需要加入
> ![Paste_Image.png](http:https://img.haomeiwen.com/i1431816/c8a62d1f26cf23b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- ```VRTK_DashTeleport``` 是一种类似往前冲的特殊瞬移效果,取代默认的“眼前一黑”效果,个人以为体验比较好
- 如果场景中有一些物体不想设置为瞬移对象,那么需要添加```VRTK_PolicyList```组件,并在Teleport组件中指定。```VRTK_PolicyList```使用物体的```tag,脚本,或者layer```来指定忽略对象
![Paste_Image.png](http:https://img.haomeiwen.com/i1431816/0893d3fc0d41cf77.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![Paste_Image.png](http:https://img.haomeiwen.com/i1431816/f56cd56a7a7fd2a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- ```VRTK_PlayAreaCursor```组件为玩家PlayArea设置了一个体积,并且只允许瞬移到那些能够容纳此体积的物体。这样,墙壁、窄的通道等物体由于其体积小于Playarea,因此不能瞬移。示范场景```012_Controller_PointerWithAreaCollision```。
![Paste_Image.png](http:https://img.haomeiwen.com/i1431816/c8b990497802c6a4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##2.2 碰触
手柄上添加```VRTK_InteractTouch```组件。在物体上添加```VRTK_InteractableObject```组件。可以设置高亮颜色,设置为黑色则不高亮。
> tips:
1. ```VRTK_InteractableObject```组件是可交互物体基础组件。场景中任何可交互物体都必须要有这个组件。
2. 手柄上的```VRTK_InteractTouch```发送```ControllerTouchInteractableObject ```和```ControllerUntouchInteractableObject```事件,传递两个参数:(int:控制器id,gameobject:被接触的物体)
##2.3 抓取
1. 手柄上添加```VRTK_InteractGrab```脚本,此脚本依赖```VRTK_InteractTouch```,所以无需再添加。此脚本还依赖```VRTK_ControllerActions```。
2. 需要抓取的物体上添加```VRTK_InteractableObject```组件,或者直接写一个类继承它。并设置```isGrabable=true```。
>tips:```VRTK_InteractableObject```组件我认为是这个插件最核心的组件,抓取的默认按键是手柄两侧的grip键
1. 被抓取的物体上必须要有Collider,其它组件如rigidbody和```VRTK_FixedJointGrabAttach(默认附着方式)```等会在需要时自动添加。
3. ```Hold Button To Grab```设置为true时,则需要一直按下抓取键,松开物体即掉落。
4. grabOverrideButton和useOverrideButton分别用来制定抓取和use键
5. 如果要在抓取时隐藏手柄,添加```VRTK_InteractControllerAppearance```组件。
7. ```VRTK_InteractableObject```脚本如果勾选了可以抓取,则此脚本在手柄第一次抓取物体时将会自动给物体添加```VRTK_FixedJointGrabAttach```和```rigidbody```组件,这是默认的抓取方式,此方式可以override。
8. 手柄上的```VRTK_InteractGrab```组件发射```ControllerGrabInteractableObject```和```ControllerUngrabInteractableObject```事件。同样传递两个参数:(int:控制器id,gameobject:被接触的物体)
## 2.4 使用
> tips: 使用(use)的默认按键是trigger键
1. 手柄上除了上述组件外,再添加```VRTK_InteractUse```组件
2. 物体上同样必须添加```VRTK_InteractableObject```组件
4. is Useable,Hold Button To Use决定是否可以使用物体。Use Only If Grabbed只有在抓取后可以使用物体。Pointer Activates Use Action使得可以用射线使用物体,前提条件是去掉Hold Button To Use勾选。
2. 使用use功能:按下trigger键(可自定义)调用物体上的use方法,此方法是一个虚方法可以很方便的重写。比如拿起一支枪并开始射击。参见Gun脚本 核心代码:
> ```
public override void StartUsing(GameObject usingObject)
{
base.StartUsing(usingObject);
//自定义实现
}
public override void StopUsing(GameObject usingObject)
{
base.StopUsing(usingObject);
//自定义实现
}
protected void Start()
{
//正常使用Start()方法
}
protected override void Update()
{
//复写Update()方法
base.Update();
}
秘诀:除了复写StartUsing方法(这种方式不太灵活)外,还可以监听手柄上
VRTK_InteractUse
组件的ControllerUseInteractableObject/ControllerUnuseInteractableObject
事件,此事件发送两个参数:控制器index和使用的物体。前述的touch/grab都有类似事件发送,可以很方便的监听
控制器碰触、抓取、使用事件示例:
//监听两个手柄的碰触事件
controllerTouchScripts =GetComponentsInChildren<VRTK_InteractTouch>();
foreach (var item in controllerTouchScripts)
{
item.ControllerTouchInteractableObject += (s, e) => {//事件处理};
item.ControllerUntouchInteractableObject += (s, e) => { //事件处理};
}
//监听两个手柄的抓取事件
controllerGrabScripts = GetComponentsInChildren<VRTK_InteractGrab>();
foreach (var item in controllerGrabScripts)
{
item.ControllerGrabInteractableObject += (s, e) => {//事件处理};
item.ControllerUngrabInteractableObject += (s, e) => { //事件处理};
}
//监听两个手柄的使用事件
controllerUseScripts = GetComponentsInChildren<VRTK_InteractUse>();
foreach (var item in controllerUseScripts)
{
item.ControllerUseInteractableObject += (s, e) => {//事件处理};
item.ControllerUnuseInteractableObject += (s, e) => { //事件处理};
}
3. UI-官方文档
UnityUI交互:
- 手柄上添加
VRTK_UIPointer
组件和VRTK_SimplePointer
组件,3dCanvas上添加VRTK_UICanvas
组件即可
tips:
- 也可在头盔上添加
VRTK_UIPointer
组件和VRTK_SimplePointer
组件,这样有了所谓的“凝视”功能,只不过此时要交互的话需要需要指定一个手柄:
Paste_Image.png - UI事件handle:
GetComponent<VRTK_UIPointer>().UIPointerElementEnter += VRTK_ControllerUIPointerEvents_ListenerExample_UIPointerElementEnter;
GetComponent<VRTK_UIPointer>().UIPointerElementExit += VRTK_ControllerUIPointerEvents_ListenerExample_UIPointerElementExit;
GetComponent<VRTK_UIPointer>().UIPointerElementClick += VRTK_ControllerUIPointerEvents_ListenerExample_UIPointerElementClick;
GetComponent<VRTK_UIPointer>().UIPointerElementDragStart += VRTK_ControllerUIPointerEvents_ListenerExample_UIPointerElementDragStart;
GetComponent<VRTK_UIPointer>().UIPointerElementDragEnd += VRTK_ControllerUIPointerEvents_ListenerExample_UIPointerElementDragEnd;
手柄UI交互
- 手柄tips:在手柄下拖入ControllerTooltips预制件作为子物体即可
Paste_Image.png- 手柄环形菜单:在手柄下拖入RadialMenu预制件作为子物体即可
Paste_Image.pngtips:
-
public bool isShown;
决定是否显示环形菜单,和public bool executeOnUnclick;
配合使用可以在用户触摸touchpad时才显示环形菜单。
为了方便广大程序猿同志,VRTK对一些常见交互物体进行了封装,下面我们来看一下:
- Door (VRTK_Door)
直接生成一扇可以打开的门,简单到只需要指定门物体和把手物体(不指定把手则直接将门本身作为交互物体)
忽略我的这扇门的轴点。。。,应该在建模软件里调整好轴点
网友评论