Notifications
Article
[HDRP]Unity 2019.3 XR Interaction Toolkit 系列教程(二)
Published 23 days ago
212
2
XR Interaction Toolkit 第二讲,这一讲运用官方推荐方法,并做了一些功能上的小幅升级。
大家好,我是VR攻城狮Tobi。在上次的教程里面给大家初略的介绍了一下Unity2019.3版本新的工具包XR Interaction Toolkit后,我特地下载了官方的XR Interaction Toolkit的demo进行第一步深入学习。并在这篇文章里对上一篇博文中手柄部分更改为官方推荐用法。在接着讲下面的内容之前,强调一下,本教程内容完全原创,如需转载,请注明出处和作者~谢谢~
在新的工程里面下载了官方demo后,我首先打开了WorldInteraction的Scenes。如下图:
可能很多人没有设备,我这里先放个简单的演示视频:
再来看看Hierarchy内容:
和教程一里面一样,这里所有的能交互的3D物体都加上了XR GrabInteractable脚本,并且都有相应的刚体和碰撞在物体上。
先看看文章开头说的手柄问题,demo中的手柄和射线是用一个预制做的,上图LeftRayInteractor就是左手预制,但是场景中看不到左手的模型,于是我就把我的射线预制上全部控件(XRController、XRRayInteractor、LineRenderer、XRInteractorLineVisual)剪切到我自己的工程的左手Cube上,并且删除掉了以前射线的预制体。
这样,你不仅只需要一个预制就能实现手柄和射线的功能,而且现在已经可以捡取地上的物体(有XRInteractable组件)了。
但是这个时候我发现一个问题,Unity的Demo是一个普通3D工程,但是我的是一个HDRP工程。看到最下面的XRInteractorLineVisual的组件没有,上面有一个ValidColorGradient和ValidColorGradient参数,这两个是用来在你射线碰到你交互的物体时候变色的参数,也就是当你悬停在可交互物体上时,射线会变成ValidColor的颜色,而没有可交互物体是InvalidColor的颜色。在普通3D工程里面有用,但是用创建的HDRP的材质赋值给LineRenderer的材质赋值,就不会变色了。我看了一下XRInteractorLineVisual的代码,主要是给LineRenderer的colorGradient赋值这句话,虽然值确实变了,但是颜色没变,所以我觉得这个和HDRP的渲染原理有关系,但是不知道以后Unity会不会注意这块。然后我换成了普通的材质球Default-Line,这个时候出现了个更好玩的现象,手柄的射线只有左眼能看到,右眼看不到射线。后来我发现把VRSettings里面的Steoreo Rendering Mode给改为Multi Pass能解决这个问题。但是为了性能,我暂时先放弃了变色这个功能,还是选用HDRP的材质球给LineRenderer,实在不行其实变色的功能可以自己写。
好了,无说明书探索阶段告一段落,手柄讲完了,让我们来看看上面的XRRig预制把。
=====================================================================================================
=====================================================================================================
从这里开始是官方推荐做法。
你可以在Hierarchy的面板上右键鼠标,选择XR->Room-Scale XR Rig 或 XR->Stationary XR Rig。初看这两个东西创建完后没什么区别,然后看了看官方文档。Room-Scale的原始位置是基于地面的,Stationary是基于头显的。上面的XR Rig控件上有个Camera Y Offset,我一开始不知道这玩意干嘛的,因为在Room-Scale的场景中,这个值感觉没什么用。但是当我设置Stationary的时候作用就出来了,它的值直接决定了你的头显的原点高度。效果就是,如果你把Camera Y Offset设置的特别大,那么你在场景中的高度就特别高,但是如果在Room-Scale的场景中,不管你设多少,头显的原点高度都是你场景里面地面的高度。其实Rig的最大不同就是Tracking Origin Mode,Stationary的值是Device,Room-Scale的值是Floor,其他好像都是一样的。刚创建完,XRRig上只有XRRig组件,没有下面的那3个组件(TeleportationProvider、LocomotionSystem和SnapTrunProvider),创建出来的手柄也没有模型,只有射线,但是已经可以和场景里面的物体进行交互了(你已添加XRInteractable的物体),并且和我文章上面说的问题一样,由于LineRenderer的材质是默认的,在运行后,只有左边的画面有手柄射线,右边没有,由于视觉效果真的很怪异,所以我还是把材质换成了HDRP的材质,感觉这应该就是Unity的BUG了,因为我又创建了一个URP的工程,在里面一切正常,而且包括教程一里面提到的快速旋转产生的余晖问题也没有了,所以,呃~好吧,我建议大家现在不要在HDRP的环境下创建VR项目,反正就目前来看,问题还很多。
先不管材质和没有模型的问题,我们接着往下看,现在可以添加运动定位系统了。
在XRRig预制上添加LocomotionSystem、Teleportation、SnapTurnProvider组件。然后新建一个Plane(当做地面),并在上面添加组件TeleportationArea 组件 或 Teleportation Achor组件。完成,现在你就可以在场景里面实现与物体交互和瞬移的功能了。TeleportationArea允许你可以在Area区域上任意点进行瞬移,而TeleportationAnchor只能瞬移到固定点上。
为了便于识别,暂且还是添加2个Cube来代替手柄模型,将原始的Cube大小调整0.1,去掉上面的碰撞体,再新建一个空节点命名为Controller,并将Cube挂到空节点下面。然后将Controller拖拽到Assets目录下某个文件夹(随意哪个,主要是保持制作好的预制体),删除Hierarchy下Controller,再将保存好的预制体拖到LeftHand Controller和RightHand Controller的XRController组件的Model Prefab参数上,这样,在运行的时候,手柄模型就出来了。现在的效果已经和本文开头做的效果一样了,并且多了瞬移的功能。这就是官方推荐做法。
这个时候,有人会发现,不管是瞬移还是选中物体,手柄的射线都是直的。但是大部分游戏里面,瞬移都是抛物线,这样不仅更加美观,而且在前面有障碍物时,也可以瞬移到障碍物的后面去,或者有时候你想瞬移到比较高的障碍物的顶部时,也得靠抛物线,直线是做不到的。那么这个时候就涉及到抛物线切换的问题。
官方示例里面是这么解决的,在XRRig预制上添加一个它自己写的ControllerManager脚本,并且为左右手分别设置2个预制,每个预制对应一种状态,如图:
baseController就是普通的直线模式或者连直线都没有的DirectInteractor模式(这个模式看着就是XRRayInteractor的精简版,或者说阉割版)。TeleportController就是带射线的模式,只不过这是个抛物线的手柄,其实和直线的手柄就XRRayInteractor上面的关于射线类型(Line Type)的参数不一样,其实你会发现XRController的参数SelectUsage也不一样,其实这个无所谓,这个相当于你的确定按钮,我的示例里面统一设置成Trigger(也就是手柄最前面的扳机键)。
再看看ControllerManager。ControllerManager的代码逻辑比较简单,就是通过按键状态来开关手柄预制上的组件的,主要是XRInteractorLineVisual、XRRayInteractor的enable状态和XRController的InputActions的状态。这个脚本有兴趣的可以自己去文章开始里面的链接下载看看,没兴趣的可以自己写,因为真的比较简单,而且里面该打注释的地方都有详细的解释。我这里就借用他的脚本,连同demo中的传送高光的相关预制(Prefabs文件夹中的TeleportReticle)一起打包到了我的工程里面。
按照demo的做法,我在我的XRRig下面分别将左右手柄复制了一份,并且重新命名了预制,然后将我的射线分别改为直线和抛物线状态。有的人这时候会问,上面图中有个ModelPt是什么,这是个空节点,用来标记模型位置的,有时候用户的模型比较不规则,或者模型的中心点的位置问题,用户想自定义模型的位置,这个节点就是干这用的。假如你不用自定义节点位置,就不需要这个空节点。当然射线也可以自定义位置,如果模型和射线自定义的位置不一样,可以定义2个空节点,最后将他们分别拖到XRController组件的ModelTransfrom和XRRayInteracotor组件的AttachTransfrom上就行了。
demo中的示例是通过按键A、按键X或按下摇杆来触发抛物线的,这两个键通常由大拇指来按,如果这两个键按着不动的方式来触发抛物线,那么可能无法通过手柄上的摇杆来修改用户希望的传送后的朝向,因为这个时候你的大拇指在按键上。demo中的示例都固定好了传送后的朝向。Unity的控件默认摇杆的向左向右可以旋转人的视角,这个可以通过将SnapTrunProvider上的Controllers->Size设置为0取消掉。
关于人瞬移后的朝向,TeleportationAnchor和TeleportationArea组件下有个参数MatchOrientatioin。它有2个参数,一个None,一个Camera,当参数为None时,你瞬移后,人的摄像机视角不会旋转,当为Camera时,人的摄像机视角会朝向之前规定的视角,而规定的角度由你TeleportationAnchor或TeleportationArea所绑定的物体的Z轴方向决定,也就是说,现在我场景里面Plane的Z轴朝向哪,瞬移后,我人就朝向哪。它不光会改变相机的水平朝向,连竖直朝向也会跟着改变。比如你的Z轴现在斜45度超下,那么你人的瞬移后,正前方也是四十五度朝下的视角。那我们如何让用户自定义朝向呢?
TeleportationAnchor有个参数TeleportAnchorTransform,它是你的最终朝向,在TeleportationAnchor下,你修改它的值就可以了。
我做了一个简单的箭头Arrow,并挂在了传送门的预制下,效果如图:
我将传送门挂载到TeleportationAnchor的Plane下,并隐藏起来,并且特地没有放到Plane正中央的位置,靠近边缘,并在其四周分别放置了四个不同形状的物体一区别方向。设置脚本TeleportationAnchor的参数用来激活传送门,设置如下:


然后,我在TeleportReticle上挂在一个脚本,用来控制传输门的的旋转。我创建了一个TeleportReticleController类,并挂载到TeleportReticle预制上。然后我将导入工程里面的ControllerManager类改为了一个单例类,并且在脚本里新增了获取手柄摇杆数据的接口。
在TeleportReticleController的Update里面,我添加传送门旋转代码:
这里为了演示,我就简单的锁定只有右手柄摇杆控制旋转。并且,第三行我增加了相机的y值,是为了在你旋转过后,你摇杆的控制方向永远相对于你玩家自己,而不会出现你旋转一个大的角度后,发现旋转箭头和玩家出现较大偏差而出现体验不好的情况。此时玩家头动虽然也会对旋转造成轻微影响,但这里先简单忽略掉,毕竟演示为主。
现在我把触发抛物线设置成Grip键,确认键还是Trigger。所以现在XRRig的设置是这样的:

为了显示瞬移的位置,将先前创建的Plane上的TeleportationArea和TeleporationAnchor上的CustomReticle拖上传送门的预制体。
现在运行程序已经可以在Plane上显示出传送门了并且能正常切换手柄直线和抛物线的状态,但是有个新的问题,直线状态和抛物线状态的手柄都可以与地板交互出现传送门,如果我只想抛物线出现传送门而直线的时候不想让其与地板交互怎么办呢?
手柄组件XRRayInteractor上有个参数RaycastMask。你现在可以新增一个Layer,并命名为Teleportation。并将抛物线手柄的组件的此参数设置为Teleportation,而直线模式手柄的此参数设置为不包括此layer的所有值。
现在来看看效果吧!
好了,这一讲先告一段落,一定要自己亲自动手试一试,这才是最重要的!下一讲会继续讲解交互操作、UI交互、3D交互等等。并对这个工程做进一步升级。希望这篇教程对你有帮助!如果喜欢,请收藏、关注、点赞~谢谢~
Tobi
Programmer
4
Comments
Tobi
22 days ago
金酱Lucky前排沙发🍉
谢谢支持😜
0
金酱Lucky
22 days ago
萌新
前排沙发🍉
0