文章目录
往期回顾:
Unity VR开发教程 OpenXR+XR Interaction Toolkit 2.1.1 (一) 安装和配置
Unity VR开发教程 OpenXR+XR Interaction Toolkit 2.1.1 (二) 手部动画
Unity VR开发教程 OpenXR+XR Interaction Toolkit 2.1.1 (三) 转向和移动
Unity VR开发教程 OpenXR+XR Interaction Toolkit 2.1.1 (四) 传送
在 VR 的交互中,与 UI 进行交互是很常见的功能。本篇教程,我将介绍如何在 VR 世界中用射线进行 UI 的交互。
📕教程说明
使用的 Unity 版本: 2020.3.36
使用的 VR 头显: Oculus Quest 2
前期的配置:环境配置参考教程一,手部模型参考教程二。本篇教程的场景基于上一篇教程搭建的场景进行延申。
项目源码(持续更新):https://github.com/YY-nb/Unity_XRInteractionToolkit_Tutorial2022/tree/master
最终实现的效果:手部射线(一开始是看不见的)对准 UI 时,会显示一条指向 UI 的射线。按下手柄的 Trigger 键,能与可交互的 UI(如 Button,Toggle,Slider 等)进行互动。
📕制作 World Space 模式的 UI
首先在场景中创建一个 Canvas 游戏物体。基于 VR 应用的沉浸感,其中的 UI 应该是 3D 世界中的一部分,因此我们在制作 UI 的时候要把 Canvas 组件的 Render Mode 改为 World Space
然后调整一下 Canvas 的大小和位置,就可以在 Canvas 上添加 UI 了。这里我就加上一个 Button,一个 Toggle 和 一个 Slider:
📕添加 Tracked Device Graphic Raycaster 脚本
在 Canvas 上添加 Tracked Device Graphic Raycaster 脚本。添加了这个脚本后,UI 就能被射线响应。
📕添加 XR UI Input Module 脚本
在 EventSystem 游戏物体上添加 XR UI Input Module 脚本,并且把原先的 Standalone Input Module 脚本移除。XR UI Input Module 配合 Event System 组件,可以让 Input Action 中的动作配置作用于 VR 中的 UI,让 UI 能够被交互,比如让按钮能被射线点击。
📕添加 UI 射线相关脚本
因为在我们的需求中,是用射线与 UI 进行交互,所以我们需要添加和射线相关的脚本。这时候我们可以联想一下我写的上一篇传送教程(Unity VR开发教程 OpenXR+XR Interaction Toolkit 2.1.1 (四) 传送)。因为传送也有用到射线,所以我们完全可以用类似的思路实现 UI 射线,即分别在左右手的控制器上添加发送射线的相关脚本。
不过在此之前,我们先更改一下 XR Origin 下的层级,让它看起来条理更清晰(沿用了上一篇传送教程中的 XR Origin,因此保留了传送的相关脚本):
首先,创建一个名叫 Ray Controller 的空物体,用于统一管理和射线有关的物体。
然后,把原本负责传送射线的 LeftHand Controller 和 RightHand Controller 游戏物体分别重命名为 LeftHand TeleportController 和 RightHand TeleportController,将它们作为 Ray Controller 的子物体。
接着,在 Camera Offset 下新建两个空物体,分别叫做 LeftHand Controller 和 Right Controller,专门负责以后手部的交互功能。并且把原本左右手的模型分别作为它们的子物体。
最后,分别在 Ray Controller 下创建 LeftHand UIController 和 RightHand UIController。然后模仿传送功能,添加上 XR Controller(Action-based),XR Ray Interactor(Line Type 为 Straight Line,因为我们希望 UI 的射线是一条直线),Line Renderer(可以复制 TeleportController 上的 Line Renderer 组件),XR Interactor Line Visual 脚本。因为我们在最早的环境配置中(见第一篇教程)设置了左右手的 Filter,所以 XR Controller 能自动识别绑定的是哪只手的动作配置。
左右手都添加了这些组件后,就能够发射一条直的射线。我们可以运行一下程序,这时候会发现两只手都会射出一条直的射线,当射线射到 UI 上时,按下手柄的 Trigger 键能被可交互的 UI (Button,Toggle,Slider)响应,比如能用射线点击按钮,拖动滑动条。
📕过滤 UI 射线的目标
但是仍然存在一个问题,我们的 XR Interactor Line Visual 脚本规定了当 UI 射线被激活时,射线颜色为白色;未被激活时射线颜色为红色。见 XR Interactor Line Visual 的 Valid Color Gradient 和 Invalid Color Gradient:
但是当我们的 UI 射线射在地面上的时候仍然处于激活的状态,还会显示传送功能中射线末端的 Reticle,并且当我们按下手柄的 Grip 键,居然也会触发传送。(见下图,UI 射线射到地面上时颜色为白色,说明处于激活的状态)
这个问题其实和上一篇传送教程中出现的问题是一样的,此时我们拥有两种射线,一种是传送射线,被上一篇教程中我们自己写的 TeleportationController 脚本所控制;另一种是刚刚创建的 UI 射线,它使用的是默认的配置。
因为我们之前给地面添加了 Teleportation Area 脚本,默认情况下是当射线射到地面的碰撞体时,会视为选中了传送区域,然后因为负责 UI 射线的 XR Controller 中的 Select Action 默认绑定的是 XRI LeftHand/RightHand Interaction 下的 Select 动作,而 Select 动作又绑定了 “Grip 键按下” 这个操作,所以按下 Grip 键会响应到传送的功能。而且是本应该负责与 UI 交互的射线响应了传送的触发。
但我们希望的是 UI 射线只有射到 UI 上的时候才能被激活。所以我们要对能激活 UI 射线的目标做个过滤。解决办法也很简单,我们找到 LeftHand UIController 物体和 RightHand UIController 物体上挂载的 XR Ray Interactor 脚本,把 Raycast Mask 中的 Everything 改成 UI :
修改前:
修改后:
现在我们再运行一下程序,这时候 UI 射线只有射到 UI 上才会变成白色,而射到地面上显示的是红色,说明只有 UI 激活了 UI 射线。
但是这里还可以有个优化,在当前的程序中,我们会看到手部一直射出一条有颜色的射线,即使没有指向 UI,场景中依然存在一条红色的射线。而我们可以这样改进:让射线射到 UI 上时才能显示,而射到其他地方不显示射线。
📕使射线射到 UI 上时才显示射线颜色
改进方法很简单,找到 XR Interactor Line Visual 脚本,修改 Invalid Color Gradient,我们可以把它的透明度改为 0。这样,当射线射到不是 UI 的地方时,射线就是透明的,在我们的眼中就是不显示的。
点开 Invalid Color Gradient 后,找到左上角和右上角白色的角标,点击后找到 Alpha 值,将它改成 0 就能让射线在未激活状态下处于透明状态。
修改前:
修改后:
现在再次运行程序,这时候只有射线射到 UI 上的时候才会看到白色的射线。
📕改变射线发射的位置
现在我们的射线是从大拇指附近射出来的,但是如果我想改变射线发射的位置呢?
其实操作也很简单,我们在手部模型下创建一个子物体作为射线发射的起始点,我这里将起始点的位置移至食指的地方,相当于让射线从食指处发出,射线发射的方向与起始点本地坐标的 z 轴方向一致。
找到 XR Ray Interactor 脚本中的 Ray Origin Transform
然后将刚刚创建的射线起始点分别拖入对应的 XR Ray Interactor 脚本的 Ray Origin Transform
现在试着运行程序,射线就会从食指射出啦!😊
版权归原作者 YY-nb 所有, 如有侵权,请联系我们删除。