九、pico+Unity交互开发——触碰抓取

一、VR交互的类型

  1. Hover(悬停)
    • 定义:发起交互的对象停留在可交互对象的交互区域。例如,当手触摸到物品表面(可交互区域)时,视为触发了Hover。
  2. Grab(抓取)
    • 概念:把物品抓起来。
  3. Use(使用)
    • 基于“抓取”。例如抓取一把枪后,按下枪的扳机发射子弹则视为Use。

三、发起交互的对象(Interactor)

  1. XR Direct Interactor脚本

    • 为了让双手成为发起交互的对象,在LeftHand Controller和RightHand Controller下分别创建Direct Interactor子物体,并添加XR Direct Interactor脚本。
  2. 添加可交互区域

    • XR Direct Interactor需要一个Trigger类型的碰撞体作为可交互区域,且需和它挂载在同一游戏物体上。如在左手和右手的Direct Interactor上分别添加Sphere Collider,调整Radius并勾选Is Trigger。当可交互对象进入该区域后,可进行交互。 ,并设置合适的参数。

在这里插入图片描述

四、可交互的对象(Interactable)创建一个3d对象,比如立方体

  1. 添加刚体

    • 因为手与物品的交互基于物理效果,所以要为可交互物体添加刚体。
    • 在这里插入图片描述
  2. XR Simple Interactable脚本

    • 为方块添加XR Simple Interactable脚本,但是它没有自带抓取的功能。
    • 物体有刚体后该脚本才生效,且挂载脚本的物体还需一个碰撞体。如果是创建的3d对象不需要额外加,如果是自定义模型的话,别忘了手动添加碰撞体
      在这里插入图片描述

2.1、可交互事件

  • 实现功能:
    • 手触碰到方块时,方块颜色改变(模拟Hover,即悬停在可交互区域)。
    • 触碰方块后按下手柄Grip键,方块颜色变成蓝色。
    • 触碰方块后按住Grip键再按Trigger键,方块颜色变回红色。
  • 实现方法:
    • 使用XR Simple Interactable脚本中的Interactable Events
    • 其中Hover Entered对应开始悬停在可交互区域触发的事件,可手动设置更改方块材质。
    • Select EnteredActivated事件分别对应上述第二、三个功能
    • 在Inspector面板中手动绑定事件,Select动作绑定“按下Grip键抓取键”,Activate动作绑定“按下Trigger键扳机键”。 Activate动作以Select动作为前提,Interactable Events中的所有事件以“与可交互对象发生交互”为前提。
      在这里插入图片描述
  1. XR Grab Interactable脚本、和XR Simple Interactable脚本脚本类似,但是有抓取效果;所以需要移除刚刚的XR Simple Interactable脚本

    • Movement Type 移动类型

      • Instantaneous:物体移动位置和姿态完全跟随手的移动,无延迟但无物理刚体效果,物体可穿过碰撞体且碰撞效果非物理。
      • Kinematic:通过Kinematic Rigidbody移动,有延迟,移动中不受力和碰撞作用,但可对其他刚体施加物理效果。
      • Velocity Tracking:通过设置刚体速度和角速度移动,有延迟,有刚体物理效果,可与碰撞体碰撞并对其他刚体产生力的效果。
        在这里插入图片描述
    • Attach Transform 抓取点

      • XR Grab Interactable脚本中有Attach Transform变量可赋值作为抓取点,若未赋值,默认以物体position为抓取点。如抓取枪时,抓取点应在枪柄;
      • 实现功能:可创建枪的子物体Attach Point并赋值给Attach Transform,然后调整其Position位置Rotation以优化抓取效果。但仅设置Attach Transform会有穿模现象,若要实现精细抓取,可参考相关教程。
  2. 代码实现Use功能(制作简易手枪)

    • 核心脚本

      • 创建GunController脚本挂载到枪的游戏物体上。获取XRGrabInteractable中的activated事件,通过AddListener绑定FireBullet函数。
    • 制作子弹预制体

      • 创建子弹Prefab(需刚体和碰撞体),并将子弹Rigidbody的Collision Detection设为Continous Dynamic,防止高速运动时检测不到碰撞。
        在这里插入图片描述
    • 制作子弹发射位置

      • 创建枪的子物体Spawn Point作为子弹生成位置,其z轴箭头方向对应子弹发射方向,将子弹和Spawn Point赋给Gun Controller。
        在这里插入图片描述
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;// 枪支控制器类
public class GunController : MonoBehaviour
{// 子弹预制体public GameObject bullet;// 子弹发射位置的变换组件public Transform spawnPoint;// 子弹发射速度public float fireSpeed = 40;void Start(){// 获取当前物体上的 XRGrabInteractable 组件XRGrabInteractable grabbable = GetComponent<XRGrabInteractable>();// 为 grabbable 的 activated 事件添加监听器,当该事件触发时调用 FireBullet 方法grabbable.activated.AddListener(FireBullet);}private void FireBullet(ActivateEventArgs arg){// 在 spawnPoint 的位置和旋转处实例化子弹预制体GameObject spawnBullet = Instantiate(bullet, spawnPoint.position, spawnPoint.rotation);// 设置实例化出的子弹的刚体速度,使其沿着 spawnPoint 的前方以 fireSpeed 的速度飞行spawnBullet.GetComponent<Rigidbody>().velocity = spawnPoint.forward * fireSpeed;// 在 5 秒后销毁这个子弹对象Destroy(spawnBullet, 5);}
}
  1. 优化一:左右手抓取(判断哪只手与物体交互)
  • 方法一(不推荐)
    • GunController脚本中,给XRGrabInteractableSelectEntered事件绑定ChangeAttachTransform函数,通过判断Interactor是左手还是右手控制器来切换Attach Transform。
      也就是创建两个抓取点,并进行监听ChangeAttachTransform判断左右手、来重新设置抓取点
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;// 枪支控制器类
public class GunController : MonoBehaviour
{// 子弹游戏对象public GameObject bullet;// 子弹发射位置的变换组件public Transform spawnPoint;// 子弹发射速度public float fireSpeed = 40;// 左手抓取点的变换组件private Transform leftHandAttachPoint;// 右手抓取点的变换组件private Transform rightHandAttachPoint;// 当前物体上的可抓取交互组件private XRGrabInteractable grabbable;void Start(){// 在当前物体下查找名为"LeftHand Attach Point"的子物体,获取其变换组件leftHandAttachPoint = transform.Find("LeftHand Attach Point");// 在当前物体下查找名为"RightHand Attach Point"的子物体,获取其变换组件rightHandAttachPoint = transform.Find("RightHand Attach Point");// 获取当前物体上的 XRGrabInteractable 组件grabbable = GetComponent<XRGrabInteractable>();// 为可抓取交互组件的 selectEntered 事件添加监听器,当该事件触发时调用 ChangeAttachTransform 方法grabbable.selectEntered.AddListener(ChangeAttachTransform);// 为可抓取交互组件的 activated 事件添加监听器,当该事件触发时调用 FireBullet 方法grabbable.activated.AddListener(FireBullet);}private void ChangeAttachTransform(SelectEnterEventArgs arg){// 获取触发 selectEntered 事件的交互器的变换组件Transform interactor = arg.interactorObject.transform;// 如果交互器的父物体名称为"Left Controller",表示是左手控制器if (interactor.transform.parent.name == "Left Controller"){// 将当前物体的抓取点设置为左手抓取点grabbable.attachTransform = leftHandAttachPoint;}else if (interactor.transform.parent.name == "Right Controller"){// 如果交互器的父物体名称为"Right Controller",表示是右手控制器// 将当前物体的抓取点设置为右手抓取点grabbable.attachTransform = rightHandAttachPoint;}}private void FireBullet(ActivateEventArgs arg){// 在 spawnPoint 的位置和旋转处实例化子弹游戏对象GameObject spawnBullet = Instantiate(bullet, spawnPoint.position, spawnPoint.rotation);// 获取实例化出的子弹的刚体组件Rigidbody bulletRigidbody = spawnBullet.GetComponent<Rigidbody>();// 设置子弹的速度,使其沿着 spawnPoint 的前方以 fireSpeed 的速度飞行bulletRigidbody.velocity = spawnPoint.forward * fireSpeed;// 在 5 秒后销毁这个子弹对象Destroy(spawnBullet, 5);}
}
  • 方法二减少耦合性
  • 新建脚本XRGrabInteractableTwoAttach继承XRGrabInteractable,重写OnSelectEntered方法,根据Interactor的Tag判断是左手还是右手,切换相应的Attach Transform
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;// 自定义的可抓取交互类,继承自 XRGrabInteractable
public class XRGrabInteractableTwoAttach : XRGrabInteractable
{// 左手的抓取点变换public Transform leftAttachTransform;// 右手的抓取点变换public Transform rightAttachTransform;// 重写 OnSelectEntered 方法,在选择进入时触发protected override void OnSelectEntered(SelectEnterEventArgs args){// 如果交互对象的标签是“Left Hand”(左手)if (args.interactorObject.transform.CompareTag("Left Hand")){// 将当前物体的抓取点设置为左手抓取点attachTransform = leftAttachTransform;}// 如果交互对象的标签是“Right Hand”(右手)else if (args.interactorObject.transform.CompareTag("Right Hand")){// 将当前物体的抓取点设置为右手抓取点attachTransform = rightAttachTransform;}// 调用基类的 OnSelectEntered 方法base.OnSelectEntered(args);}
}

在这里插入图片描述

  • 将枪上的XRGrabInteractable抓取脚本替换为XRGrabInteractableTwoAttach,并在编辑器中为左右手Attach Transform赋值并给Direct Interactor添加Tag

在这里插入图片描述
在这里插入图片描述

  • 第一次抓取或第一次切换抓取位置错误解决方法
    - 方法一
    - 在可抓取物体Gun被抓取物体上添加XRSingleGrabFreeTransformer脚本,游戏运行时会自动添加到XRGrabInteractableTwoAttach脚本。
    在这里插入图片描述

方法二
- 重写刚刚新建的XRGrabInteractableTwoAttach脚本的GetAttachTransform方法,而不是OnSelectEntered方法。根据InteractorTag返回相应的Attach Transform,若Tag不匹配则返回基类的GetAttachTransform结果。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;public class XRGrabInteractableTwoAttach : XRGrabInteractable
{public Transform leftAttachTransform;public Transform rightAttachTransform;public override Transform GetAttachTransform(IXRInteractor interactor){Transform i_attachTransform = null;if (interactor.transform.CompareTag("Left Hand")){i_attachTransform = leftAttachTransform;}if (interactor.transform.CompareTag("Right Hand")){i_attachTransform = rightAttachTransform;}return i_attachTransform != null ? i_attachTransform : base.GetAttachTransform(interactor);}
}

因为之前学的射线交互层级是Everything层级比较高和物体交互层级有重复,所以也能实现射线抓取;然后将与传送有关的 XR Ray Interactor 和 Teleport Area 的 Interaction Layer Mask 改成 Teleport,就可以避免出现这类问题
在这里插入图片描述
在这里插入图片描述

  1. 其他功能一:将与物体接触的地方作为抓取点(Dynamic Attach),也就是碰哪里抓哪里,没有固定抓取点

    • 创建细长Cube作为测试物体,添加碰撞体、刚体和XR Grab Interactable脚本,勾选Use Dynamic Attach后,可根据需求设置Match Position、Match Rotation、Snap To Collider等选项,实现手抓在物体接触部位的效果。

Match Position(匹配位置):当启用相关功能时,确保被抓取物体的位置与抓取点的位置相匹配。例如在使用特定的抓取方式时,可使被抓取物体在被抓取瞬间其位置与抓取点重合,以实现更真实的抓取效果。
Match Rotation(匹配旋转):类似 “匹配位置”,当启用此选项时,被抓取物体的旋转会与抓取点的旋转相匹配。这样可以确保被抓取物体在抓取过程中以合适的角度呈现,增强真实感和交互性。
Snap To Collider(吸附到碰撞体):当开启这个功能后,抓取操作会使被抓取物体吸附到抓取点所在的碰撞体上。这可以使抓取更加精准,并且在抓取过程中物体与抓取点的连接更加紧密,避免出现不合理的位置偏差。

在这里插入图片描述

五、XR Tint Interactable Visual脚本

  1. 功能:可挂载到可交互对象上,当Interactor悬停(Hover)或选中(Select动作触发)可交互对象时,能暂时改变其颜色。
    .在这里插入图片描述2. 设置:调整Tint Color设置颜色,勾选Tint On Hover在Hover时改变颜色,勾选Tint On Selection在Select时改变颜色。注意要把使用的XR Grab Interactable放置到最上层。
    在这里插入图片描述

六、取消身体和可抓取物体的物理碰撞

  1. 设置Layer:将XR Origin的Layer设为Player(仅设置Character Controller所在物体Layer,子物体选No),将所有可抓取物体Layer设为Interactable。
    在这里插入图片描述

  2. 配置Physics:打开Unity编辑器上方菜单栏的Edit编辑 -> Project Settings项目设置-> Physics物理,找到Layer Collision Matrix图层碰撞器,将Player和Interactable的交叉点取消勾选,避免身体与可抓取物体发生物理碰撞。
    在这里插入图片描述

七、XR Interaction Group

  1. 功能:XR Interaction Toolkit 2.3新组件,可管理多个Interactor。当其中一个Interactor生效时,Group内其他Interactor会暂时失效。
    在这里插入图片描述

  2. 应用示例:如在Left/RightHand Controller物体上添加XR Interaction Group组件,将Direct Interactor物体和UI Ray Interactor物体拖到Group中,可实现在抓取物体时让UI射线暂时失效。

八、XR Direct Interactor脚本中的Select Action Trigger

在这里插入图片描述

  1. 参数说明
    • Toggle:以抓取为例,选择Toggle后,靠近物体按下手柄抓取键,物体会被抓在手上,松开抓取键物体仍在手上,下次按下抓取键才会释放。
    • Sticky:按下手柄抓取键物体被抓手上,松开抓取键物体仍在手上,下次按下并松开抓取键物体才会释放。
    • State和State Change的区别(在可抓取物体Select Mode选择Single时)
      • State:可能出现一只手无法接管另一只手抓取权的情况,只有先松开当前抓取手的抓取键才会进行切换抓取。
      • State Change:可以随意切换抓取,推荐在抓取功能上使用State Change。

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

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

相关文章

京东笔试题

和谐敏感词 &#x1f517; 题目地址 &#x1f389; 模拟 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();String s scanner.next();String[] words new String[…

【毕业设计】基于SpringBoot的网上商城系统

前言 &#x1f525;本系统可以选作为毕业设计&#xff0c;运用了现在主流的SSM框架&#xff0c;采用Maven来帮助我们管理依赖&#xff0c;所选结构非常合适大学生所学的技术&#xff0c;非常合适作为大学的毕业设计&#xff0c;难以适中。 &#x1f525;采用技术&#xff1a;Sp…

C++:模板(2)

目录 非类型模板参数 模板的特化 概念 函数模板特化 类模板特化 全特化 偏特化 模板的分离编译 分离编译的概念 模板的分离编译 ​编辑 模板总结 非类型模板参数 模板参数分为类型形参与非类型形参。 类型形参&#xff1a;在模板参数列表中&#xff0c;跟在class…

HttpURLConnection构造请求体传文件

HttpURLConnection构造请求体传文件 在Java中&#xff0c;使用HttpURLConnection构造请求体传输文件&#xff0c;你需要做以下几步&#xff1a; 1、创建URL对象指向你想要请求的资源。 2、通过URL打开连接&#xff0c;转换为HttpURLConnection实例。 3、设置请求方法为POST。 …

GB/T28181-2022规范解读、应用场景和技术实现探究

GB/T28181-2022和GB/T28181-2016区别 GB/T28181-2022《公共安全视频监控联网系统信息传输、交换、控制技术要求》与 GB/T28181-2016 相比&#xff0c;主要有以下区别&#xff1a; 术语和定义方面&#xff1a; 术语删减&#xff1a;GB/T28181-2022 删除了 “联网系统信息”“数…

Win安装Redis

目录 1、下载 2、解压文件并修改名称 3、前台简单启动 4、将redis设置成服务后台启动 5、命令启停redis 6、配置文件设置 1、下载 【下载地址】 2、解压文件并修改名称 3、前台简单启动 redis-server.exe redis.windows.conf 4、将redis设置成服务后台启动 redis-server -…

pikachu靶场CSRF-post测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、抓包使用burp生成csrf脚本 四、源代码分析 五、结论 一、测试环境 1、系统环境 渗透机&#xff1a;本机(127.0.0.1) 靶 机&#xff1a;本机(127.0.0.1) 2、使用工具/软件 Burp sui…

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

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

【去哪儿-注册安全分析报告-缺少轨迹的滑动条】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

RabbitMQ service is already present - only updating service parameters

Windows下卸载RabbitMQ之后,然后重新注册RabbitMQ服务的时候,报错以下信息: D:\software\rabbitmq-server-4.0.2\rabbitmq_server-4.0.2\sbin>D:\software\rabbitmq-server-4.0.2\rabbitmq_server-4.0.2\sbin\rabbitmq-service.bat install RabbitMQ service is already …

kafka自定义配置信息踩坑

org.apache.kafka.common.config.ConfigException: Invalid value 0 for configuration acks: Expected value to be a string, but it was a java.lang.Integer 场景描述&#xff1a; 单个kafka使用springboot框架自带的 yml 配置完全OK&#xff08;因为底层会帮我们处理好类…

调查显示软件供应链攻击增加

OpenText 发布了《2024 年全球勒索软件调查》&#xff0c;强调了网络攻击的重要趋势&#xff0c;特别是在软件供应链中&#xff0c;以及生成式人工智能在网络钓鱼诈骗中的使用日益增多。 尽管各国政府努力加强网络安全措施&#xff0c;但调查显示&#xff0c;仍有相当一部分企…

CentOS7安装RabbitMQ-3.13.7、修改端口号

本文安装版本&#xff1a; Erlang&#xff1a;26.0 官网下载地址 Erlang RabbitMQ&#xff1a;3.13.7 官网下载地址 RabbitMQ RabbitMQ和Erlang对应关系查看&#xff1a;https://www.rabbitmq.com/which-erlang.html 注&#xff1a;安装erlang之前先安装下依赖文件&#xff0…

【Qt】控件——Qt多元素控件、常见的多元素控件、多元素控件的使用、List Widget、Table Widget、Tree Widget

文章目录 QtQt多元素控件List WidgetTable WidgetTree Widget Qt Qt多元素控件 List Widget 使用 QListWidget 能够显示一个纵向的列表。 属性说明currentRow当前被选中的是第几行。count一共有多少行。sortingEnabled是否允许排序。isWrapping是否允许换行。itemAlignment元素…

Tomcat日志文件详解及catalina.out日志清理方法

目录 前言1. Tomcat日志文件详解1.1 catalina.out1.2 localhost_access_log1.3 catalina.<date>.log1.4 host-manager.<date>.log 和 manager.<date>.log1.5 localhost.<date>.log 2. catalina.out文件管理与清理方法2.1 为什么不能直接删除catalina.o…

【火山引擎】AIGC图像风格化 | 风格实践 | PYTHON

目录 1 准备工作 2 实践 代码 效果图 1 准备工作 ① 服务开通 确保已开通需要访问的服务。您可前往火山引擎控制台,在左侧菜单中选择或在顶部搜索栏中搜索需要使用的服务,进入服务控制台内完成开通流程。

开发工具(上)

前面我们在Linux部分了解文件权限&#xff0c;和基本指令的内容&#xff0c;但对于开发工具还是没有很多的接触&#xff0c;现在这一篇就是主要讲基础的工具&#xff1b;如yum&#xff0c;yum源&#xff0c;包管理器等等&#xff1b; Linux中的安装软件&#xff1a; 源码安装 …

JAVA——IO流(2)

目录 1.缓冲流 a.字节缓冲流 1.构造方法 2.常见方法 3.底层原理 b.字符缓冲流 1.构造方法 2.特有方法 2.转换流 a.概述 b.编码问题 c.InputStreamReader类 1.概述 2.构造方法 d.OutputStreamWrite类 1.概述 2.构造方法 3.序列化流 a.概述 b.ObjectOutputStr…

TCP的建立与终止——三次握手、四次挥手

目录 1. UDP和TCP的区别 2. TCP概述 3. TCP连接的建立&#xff08;三次握手&#xff09; 3.1 为什么TCP客户端最后还要发送一次确认&#xff1f; 3.2 什么是半连接队列&#xff1f; 3.3 半连接队列被填满或遇到SYN洪泛攻击是如何处理&#xff1f; 3.4 三次握手过程中可以…

力扣 简单 746.使用最小花费爬楼梯

文章目录 题目介绍题解 题目介绍 题解 思路分析&#xff1a; 确定dp数组以及下标的含义&#xff1a;dp[i]的定义为到达第i台阶所花费的最少体力。确定递推公式&#xff1a;可以有两个途径得到dp[i]&#xff0c;一个是dp[i-1] 一个是dp[i-2]。dp[i - 1] 跳到 dp[i] 需要花费 d…