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

news2024/10/18 16:40:52

一、回顾与引入

回顾上一篇直接抓取的教程,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物体上挂载并赋值变量,可解决此问题。

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 的时候也会触发其他与摇杆控制有关的动作,比如传送,持续移动。因此我们希望在对远距离抓取物体进行操作时,不会触发该手柄其他和摇杆控制绑定的动作。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2217898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vercel】Vercel静态部署踩坑

背景 在现代的软件开发中,自动化部署是一个不可或缺的环节。Vercel作为一个流行的前端部署平台,提供了与GitHub的无缝集成,使得开发者能够在每次提交代码后自动触发部署流程。然而,自动化部署过程中可能会遇到一些挑战&#xff0…

性能测试:流量回放工具-GoReplay!结合一款无需CA证书即可抓取HTTPS明文的工具,简直无敌

性能测试:流量回放工具-GoReplay!结合一款无需CA证书即可抓取HTTPS明文的工具,简直无敌。 GoReplay 是一个开源网络监控工具,可以将实时 HTTP 流量捕获并重放到测试环境。 应用成熟的过程中,测试所需的工作量往往会成…

学习干货小白女友看完这篇文章后,面试工作和护网蓝队初级竟然秒通过!

小白女友看完这篇文章后,面试工作和护网蓝队初级竟然秒通过! 前言:本文中涉及到的相关技术或工具仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担,如有侵权请联系。 还在学怎么挖通用漏…

【Linux】<互斥量>解决<抢票问题>——【多线程竞争问题】

前言 大家好吖,欢迎来到 YY 滴Linux系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 主要内容含: 欢迎订阅 YY滴C专栏!更多干货持续更新!以下是传送门! YY的《C》专栏YY的《C11》专栏YY的《Lin…

Axure树形菜单展开与折叠

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:Axure树形菜单展开与折叠 主要内容:树形菜单制作——层级关系——隐藏与显示——值的变化——多层交互 应用场景:关系树、菜…

老机MicroServer Gen8再玩 OCP万兆光口+IT直通

手上有一台放了很久的GEN8微型服务器,放了很多年,具体什么时候买的我居然已经记不清了 只记得开始装修的时候搬家出去就没用了,结果搬出去有了第1个孩子,孩子小的时候也没时间折腾,等孩子大一点的时候,又有…

MongoDB查询操作

🌷启动mongo 🎈启动mongo shell (1)在指定目录下创建mongodb文件夹、其子文件夹data、log以及文件mongodb.log cd /home/ubuntu mkdir -p mongodb/data mkdir -p mongodb/log touch mongodb/log/mongodb.log(2)先执行mongodb命…

《计算机视觉》—— 疲劳检测

文章目录 一、疲劳检测实现的思想二、代码实现 一、疲劳检测实现的思想 了解以下几篇文章有助于了解疲劳检测的方法 基于dlib库的人脸检测 https://blog.csdn.net/weixin_73504499/article/details/142977202?spm1001.2014.3001.5501 基于dlib库的人脸关键点定位 https://blo…

基于开源Jetlinks物联网平台协议包-MQTT自定义主题数据的自动回复

目录 1.根据需要自动回复某些主题 2.调用doReply方法进行自动回复 1.根据需要自动回复某些主题 根据主题判断,哪些主题是需要自动回复的,比如设备登录,需要自动回复。 2.调用doReply方法进行自动回复(代码不一定全部正确&#xf…

第 5 章:vuex

1. 理解 vuex vuex 是什么: 概念:专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式&am…

安乃达:用CRM构建从销售到管理到售后的全链路数字化运营平台

安乃达驱动技术(上海)股份有限公司((简称:“安乃达”,股票代码为:“603350”))自2011年以来,公司通过多年的研发与积累现有直驱轮毂电机、减速轮毂电机和中置电机三大系列产品,并具备与电机相匹配的控制器、传感器、仪表等电驱动成…

springboot旧物置换网站

作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 系统展示 【2024最新】基于JavaSpringBootVueMySQL的,前后端分离。 开发语言:Java数据库:MySQL技术:…

ThinkPHP 3.2 + Nginx 页面404问题

学习公司Callout项目时,发现公司项目所使用的TP版本是3.2,所以才可以使用例如,C,M,A等方法 因此我用phpEnv搭建了一个项目,域名为thinkphp,所选根目录如下 我打开网页,访问 thinkphp/ 和 thinkphp/index.p…

ROS 的 urdf 中 link 和 joint 的子标签中 origin 的含义

主要参考文章——主要文章,官方关于urdf的介绍和官方文档的翻译解析 link标签里面的origin含义 link标签里面有三个主要的子标签,分别是visual——连杆的外观和坐标系,collisoin——连杆的碰撞属性和inertial——连杆的惯性设置 首先&…

C++ | AVL树

前言 本篇博客讲解c中数据结构AVL树,看这篇博客之前请先去看:C | 二叉搜索树-CSDN博客 💓 个人主页:普通young man-CSDN博客 ⏩ 文章专栏:C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青年 (pu-tong-young-m…

2024最新:零基础到精通的大模型AI产品经理全学习路线

随着人工智能技术的发展,尤其是大模型(Large Model)的兴起,越来越多的企业开始重视这一领域的投入。作为大模型产品经理,你需要具备一系列跨学科的知识和技能,以便有效地推动产品的开发、优化和市场化。以下…

第51期 C语言实现中断<一>

Q:怎样理解用C语言实现中断的过程呢? A:以下是一段使用C语言实现中断的主程序,和汇编语言实现中断一样也使用了定时器中断和按键中断。执行该主程序会在DE2-115的红色LED上显示流水灯,按下KEY1可以改变流水灯移动的…

FreeRTOS - 任务通知

1. 任务通知 所谓"任务通知",你可以反过来读"通知任务"。 我们使用队列、信号量、事件组等等方法时,并不知道对方是谁。使用任务通知时,可以明确指定:通知哪个任务。 使用队列、信号量、事件组时&#xff…

【DBA Part01】国产Linux上安装Oracle进行数据迁移

内容如下: 1.1.生产环境RHEL/OEL Linux8Oracle11gR2安装配置 1.2.国产麒麟操作系统Oracle11gR2安装配置 1.3.国产麒麟操作系统Oracle11gR2 RAC集群安装配置 1.4.Oracle11gR2迁移到国产麒麟操作系统(单机/RAC) 本阶段课程项目需求说明&am…

[C++刷题] 基础小知识点(1) 乘方函数pow()

乘方 pow() 该函数在math.h头文件中 例如: 求圆的面积公式 s3.14*pow(r,2); 也可用于开方 pow(4,1.0/3) 注意这里要写1.0, 不然1/30,该函数会失效 例题: #include<iostream> using namespace std; #include<math.h>) int main() {int h;int r;cin >> h &g…