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

一、回顾与引入

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

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

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

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

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

  3. 设置XR Ray Interactor上的射线发射起始点Ray Origin TransformXR 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体验增添了丰富性和真实感。

相关推荐
EQ-雪梨蛋花汤32 分钟前
【Part 3 Unity VR眼镜端播放器开发与优化】第四节|高分辨率VR全景视频播放性能优化
unity·音视频·vr
与火星的孩子对话5 小时前
Unity进阶课程【六】Android、ios、Pad 终端设备打包局域网IP调试、USB调试、性能检测、控制台打印日志等、C#
android·unity·ios·c#·ip
幻世界6 小时前
【Unity智能模型系列】Unity + MediaPipe + Sentis + ArcFace模型:构建高效人脸识别比对系统
unity·游戏引擎
AxureMost9 小时前
Axure常用交互功能案例-免费
交互·axure·photoshop
漫游者Nova13 小时前
虚幻引擎Unreal Engine5恐怖游戏设计制作教程,从入门到精通从零开始完整项目开发实战详细讲解中英字幕
ue5·游戏引擎·虚幻·游戏开发完整教程·恐怖游戏开发
死也不注释1 天前
【Unity 编辑器工具开发:GUILayout 与 EditorGUILayout 对比分析】
unity·编辑器·游戏引擎
大美B端工场-B端系统美颜师1 天前
多模态数据融合预警:从IoT传感器到卫星监测的可视化方案升级
物联网·交互·数据预警
小彭努力中1 天前
141.在 Vue 3 中使用 OpenLayers Link 交互:把地图中心点 / 缩放级别 / 旋转角度实时写进 URL,并同步解析显示
前端·javascript·vue.js·交互
梓贤Vigo1 天前
【Axure高保真原型】动态打字输入效果
交互·产品经理·axure·原型
小赖同学啊1 天前
物联网中的Unity/Unreal引擎集成:数字孪生与可视化控制
物联网·unity·游戏引擎