十、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体验增添了丰富性和真实感。

相关推荐
babywang02 小时前
Unity笔记--AssetBundle详解
unity·游戏引擎
魔士于安3 小时前
经典Game
游戏·游戏引擎·贴图·技术美术·模型
淡海水3 小时前
01-04-认知篇-Unity内存全景
unity·c#·游戏引擎·.net·gc
598866753@qq.com13 小时前
Codex与Unity
unity·游戏引擎
淡海水14 小时前
01-03-认知篇-C#内存模型深度解析
unity·c#·游戏引擎·.net·gc
新新学长搞科研21 小时前
【往届稳定EI+scopus检索】第三届人工智能、数字媒体技术与交互设计国际学术会议(ICADI 2026)
人工智能·交互·媒体
警醒与鞭策1 天前
Direct3D 12 中的内存管理
3d·游戏引擎·direct3d
平头哥~1 天前
从文化 IP 解读到伴手礼定制,文创设计师智能体背后是 端到端具身交互智能落地
网络协议·tcp/ip·交互
淡海水1 天前
16-02-C#常用数据结构源码-附录B-源码索引速查
unity·c#·游戏引擎·il2cpp
速易达网络1 天前
无人机远程操控仿真
游戏引擎·cocos2d