十、pico+Unity交互开发教程——射线抓取与更多交互功能

一、回顾与引入

复制代码
回顾上一篇直接抓取的教程,VR交互一般需要可交互的对象(Interactable)和发起交互的对象(Interactor)。直接抓取和射线抓取的可交互对象无区别,可参考上一篇教程设置组件。

两者区别在于发起交互的对象不同,直接抓取使用XR Direct Interactor,而射线抓取使用XR Ray Interactor,它可通过射线检测实现远距离交互。

二、添加射线功能的相关组件

  1. 在XR Origin下的LeftHand Controller和RightHand Controller物体创建子物体,选择XR -> Ray Interactor(Action-based),并命名为Distance Grab Interactor。

  2. 删除子物体上的XR Controller,设置LeftHand和RightHand的Tag以实现左右手切换抓取。

  3. 设置XR Ray Interactor上的射线发射起始点Ray Origin Transform和XR Interactor Line Visual的颜色效果,可参考射线交互教程。

  4. 将DistanceGrabInteractor物体拖到Left/RightHand Controller上的XR Interaction Group中,确保一个Interactor被使用时其他Interactor暂时失效。

四、设置Interaction Layer Mask 层级,上一篇说过

  1. 运行程序时发现射线射到地面会激活传送,这是因为XR Ray Interactor的Interaction Layer Mask默认是Everything,而地面的Interaction Layer Mask是Teleport,可交互物体默认是Default。将XR Ray Interactor的Interaction Layer Mask改为Default可解决此问题。

  2. 也可分别为直接抓取和射线抓取设立不同的Interaction Layer,以区分可被不同方式抓取的物体。

五、防止射线抓取的射线与UI发生交互

  1. 当通过射线抓取物体后朝向UI,会发现手部发出射线并能与UI交互,这是DistanceGrab Interactor发出的射线。
  2. 找到DistancegGrab Interactor物体上的XR Ray Interactor组件,取消勾选Raycast Mask的UI选项,防止远距离抓取的射线与UI发生响应。

六、让XR Direct Interactor不对XR Ray Interactor产生干扰(新版XRI不会出现此问题)

  1. 注:此部分针对XR Interaction Toolkit 2.1.1版本,若使用2.3.2或更高版本可跳过。

  2. 当用射线抓取物体后,可能会出现即使按住手柄Grip键不放,也会不小心将另一个物体"吸"过来的问题,这是XR Direct Interactor对XR Ray Interactor产生干扰。

  3. 解决思路是写一个脚本控制,当XR Direct Interactor发挥作用时,将XR Ray Interactor隐藏掉。

  4. 创建脚本GrabRayController,在LeftHand Controller和Right Controller物体上挂载并赋值变量,可解决此问题。

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;

// 抓取射线控制器类
public class GrabRayController : MonoBehaviour
{
    // 射线交互器
    public XRRayInteractor grabRayInteractor;
    // 直接交互器
    public XRDirectInteractor grabDirectInteractor;

    void Update()
    {
        // 根据直接交互器选中的可交互对象数量来决定射线交互器是否启用。
        // 如果直接交互器没有选中任何可交互对象(即数量为0),则启用射线交互器;否则禁用射线交互器。
        grabRayInteractor.enabled = grabDirectInteractor.interactablesSelected.Count == 0;
    }
}

七、使抓取的物体不会吸到手上(Force Grab)

  1. 若想在抓取时让物体和手保持一定距离,营造远程操纵物体的感觉,可取消XR Ray Interactor脚本中的Force Grab勾选。

  2. 若想让射线射到物体上的点作为实际抓取点,可勾选Dynamic Attach。

八、远距离抓取时通过摇杆改变抓取物体的位移和旋转角度(Rotate Anchor Action和Translate Anchor Action)

  1. 在测试射线抓取场景时,发现取消Force Grab后,按下手柄Grip键抓取物体再推动摇杆,物体会发生位移和旋转角度变化,这是由XR Controller(Action-based)和XR Ray Interactor组件的设置引起。
  2. XR Controller(Action-based)上的Rotate Anchor Action和Translate Anchor Action引用了Input System中的Action,可通过查看默认输入配置文件进行设置调整。
  3. XR Ray Interactor上的Anchor Control也与此功能相关。
  4. 当然,如果你不想要远距离抓取时通过摇杆改变抓取物体的位移和旋转角度的功能,就直接将左右手 XR Controller 中的 Rotate Anchor Action 和 Translate Anchor Action 的 Use Reference 取消勾选,然后移除下面新建的 Grab Ray Controller 脚本就行了。

但是可以发现,触发 Rotate Anchor 或 Translate Anchor 的时候也会触发其他与摇杆控制有关的动作,比如传送,持续移动。因此我们希望在对远距离抓取物体进行操作时,不会触发该手柄其他和摇杆控制绑定的动作。

csharp 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.XR.Interaction.Toolkit;

// 抓取射线控制器类
public class GrabRayController : MonoBehaviour
{
    // 射线交互器
    public XRRayInteractor grabRayInteractor;
    // 直接交互器
    public XRDirectInteractor grabDirectInteractor;

    // 旋转锚点动作引用
    public InputActionReference rotateAnchorReference;
    // 平移锚点动作引用
    public InputActionReference translateAnchorReference;
    // 传送激活动作引用
    public InputActionReference teleportActivateReference;
    // 移动动作引用
    public InputActionReference moveReference;
    // 转向动作引用
    public InputActionReference turnReference;

    private void Start()
    {
        // 为射线交互器的 selectEntered 事件添加监听器,当抓取开始时调用 OnEnterGrab 方法
        grabRayInteractor.selectEntered.AddListener(OnEnterGrab);
        // 为射线交互器的 selectExited 事件添加监听器,当抓取结束时调用 OnExitGrab 方法
        grabRayInteractor.selectExited.AddListener(OnExitGrab);
    }

    private void OnDestroy()
    {
        // 在对象销毁时,移除 selectEntered 事件的监听器
        grabRayInteractor.selectEntered.RemoveListener(OnEnterGrab);
        // 在对象销毁时,移除 selectExited 事件的监听器
        grabRayInteractor.selectExited.RemoveListener(OnExitGrab);
    }

    private void OnEnterGrab(SelectEnterEventArgs arg)
    {
        // 禁用传送激活动作
        DisableAction(teleportActivateReference);
        // 禁用移动动作
        DisableAction(moveReference);
        // 禁用转向动作
        DisableAction(turnReference);
        // 启用旋转锚点动作
        EnableAction(rotateAnchorReference);
        // 启用平移锚点动作
        EnableAction(translateAnchorReference);
    }

    private void OnExitGrab(SelectExitEventArgs arg)
    {
        // 启用传送激活动作
        EnableAction(teleportActivateReference);
        // 启用移动动作
        EnableAction(moveReference);
        // 启用转向动作
        EnableAction(turnReference);
        // 禁用旋转锚点动作
        DisableAction(rotateAnchorReference);
        // 禁用平移锚点动作
        DisableAction(translateAnchorReference);
    }

    private void EnableAction(InputActionReference actionReference)
    {
        // 根据动作引用获取输入动作
        var action = GetInputAction(actionReference);
        // 如果动作不为空且未启用,则启用该动作
        if (action!= null &&!action.enabled)
            action.Enable();
    }

    private void DisableAction(InputActionReference actionReference)
    {
        // 根据动作引用获取输入动作
        var action = GetInputAction(actionReference);
        // 如果动作不为空且已启用,则禁用该动作
        if (action!= null && action.enabled)
            action.Disable();
    }

    private InputAction GetInputAction(InputActionReference actionReference)
    {
        // 如果动作引用不为空,则返回对应的输入动作,否则返回 null
        return actionReference!= null? actionReference.action : null;
    }
}

然后在 LeftHand Controller 和 RightHand Controller 物体上分别挂载这个脚本,并且手动赋值。

通过以上步骤,我们实现了Unity VR中的射线抓取功能以及更多复杂的交互控制,为VR体验增添了丰富性和真实感。

相关推荐
辻弋20117 小时前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
天若有情6731 天前
开源|Comfort Lang v1.0.1,一款主打清爽交互的新型命令式编程语言
python·开源·交互·编程语言·项目分享·repl·comfort lang
Martina_03211 天前
AI生成3D场景导入 Unity/Unreal 后,NPC 总串层?用6步检查导航高度与跨层连接
人工智能·游戏·数学建模·3d·unity·自然语言处理·aigc
小贺儿开发1 天前
Unity 局域网遥控幻灯片展示工具 3.0
科技·http·unity·工具·ppt·通信·网页
黑妹天下第一乖1 天前
第 10 讲:阿加犀 AidVoice 端侧语音交互与语音识别实战
图像处理·人工智能·数码相机·opencv·交互·语音识别·xcode
格数致用3 天前
1.7 PySide6 三栏工作台:QPainter 渲染、坐标契约与框选/涂抹交互
交互·pyside6
WarPigs3 天前
Unity对象不应该使用null传播的问题
unity
沫璃染墨4 天前
《Qt从零入门系列(十二):Qt文件操作详解——从QFile读写到QFileInfo与记事本实战》
开发语言·网络·c++·qt·交互·信号处理·文件
每日出拳老爷子4 天前
【VR】【Unity】抓走转放系列21|一天搭完门和抽屉工具槽:小场景按这个次序拼装
unity·vr·驱动·排错·snap zone
一条大祥脚4 天前
26 ICPC上海 交互|二分|重心|构造|二分图|贪心|SOSDP|三进制枚举|线性基|字典序贪心|DFS|分块|单侧递归线段树
算法·深度优先·交互·分块·icpc上海站·单侧递归线段树