九、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.rhkb.cn/news/454964.html

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

相关文章

张雪峰:如果你现在是计算机专业,一定要优先报网络安全,它是未来国家发展的大方向

&#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 前言 “计算机专业 一定要优先报 网络安全 它是未来国家发展的大方向” 为什么推荐学网络安全&#xff1f; “没有网络安全就没有国家安全。”当前&#xff…

优化UVM环境(九)-将interface文件放在env pkg外面

书接上回&#xff1a; 优化UVM环境&#xff08;八&#xff09;-整理project_common_pkg文件 My_env_pkg.sv里不能包含interface&#xff0c;需要将my_intf.sv文件放在pkg之外

使用飞桨AI Studio平台训练数据,并进行图像识别分析得牡丹花测试

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

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

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

【vue 封装一个select组件】封装一个select组件,包括select样式的修改,以及解决select,onchange事件失效问题

实现效果:封装一个下拉菜单组件,效果如下图 父组件代码如下: 子组件代码: <template><div><form><select name="languages" id="lang" ><option :value="item.value" v-for="item in optionList" >…

【火山引擎】语音合成 | HTTP接口 | 一次性合成 | python

目录 一 准备工作 二 HTTP接口(一次性合成-非流式) 1 接口说明 2 身份认证 3 请求方式 三 实践 四 注意事项 火山引擎语音合成TTS(Text-to-Speech)是一种基于云计算的语音合成服务,可以将文本转化为自然、流畅的语音。以下是火山引擎TTS的主要功能和特点: ①多种语音…

CMOS 图像传感器:像素寻址与信号处理

CMOS image sensor : pixel addressing and signal processing CMOS image sensor 对于寻址和信号处理有三种架构 pixel serial readout and processingcolumn parallel readout and processingpixel parallel readout and processing 其中&#xff0c;column parallel reado…

kebuadm部署k8s集群

官方文档&#xff1a; Installing kubeadm | Kubernetes 切记要关闭防⽕墙、selinux、禁用交换空间&#xff0c; cpu核⼼数⾄少为2 内存4G kubeadm部署k8s⾼可用集群的官方文档&#xff1a; Creating Highly Available Clusters with kubeadm | Kubernetes 你需要在每台…

Docker 安装Postgres和PostGIS,并制作镜像

1. 查找postgres和postgis现有的镜像和版本号 镜像搜索网站&#xff1a;https://docker.aityp.com/ 测试使用的是postgres:15.4 和 postgis:15-3.4 2、镜像拉取 docker pull postgres:15.4docker pull postgis/postgis:15-3.4镜像下载完成&#xff0c;docker images 查看如…

konvajs -基础图形-标签-箭头,动画,学习笔记

官网&#xff1a; Konva 框架概述 |Konva - JavaScript 2d 画布 图书馆 (konvajs.org)https://konvajs.org/docs/overview.html konva是canvas的一个库&#xff0c;可快速画出想要的图形。 基础创建步骤&#xff1a; // 第一步&#xff0c;创建一个Stage舞台 var stage new…

element设置时间和日期框早于现在的时间和日期禁用

效果: 今日此时此刻之前的日期、时间禁止选用&#xff0c;切换日期和时间为“2024-10-19 00:00:00"&#xff0c;再切换为”2024-10-18 00:00:00"时&#xff0c; 会给form.time默认赋值为今日此时此刻&#xff08;日期时间少于今日此时此刻则重新赋值&#xff09; 安…

Go语言基础学习(Go安装配置、基础语法)

一、简介及安装教程 1、为什么学习Go&#xff1f; 简单好记的关键词和语法&#xff1b;更高的效率&#xff1b;生态强大&#xff1b;语法检查严格&#xff0c;安全性高&#xff1b;严格的依赖管理&#xff0c; go mod 命令&#xff1b;强大的编译检查、严格的编码规范和完整的…

【优选算法】探索双指针之美(一):双指针与单调性的完美邂逅

文章目录 前言&#xff1a;1.盛水最多的容器2.有效三角形个数3. 和为s的两个数字4. 三数之和5. 四数之和 最后想说&#xff1a; 前言&#xff1a; 在上一章中我们已经认识到了双指针&#xff0c;在这章里我们就来探索一下当双指针和单调性遇见后会擦出怎样的火花呢&#xff1f…

几何算法系列:空间实体体积计算公式推导

1.前言 面积和体积的计算是常见和基础的几何算法话题&#xff0c;面积和体积通常作为面或构件的基本信息参与相关的建模、计算、分析等过程。 有关面积的计算&#xff0c;可以参考博主此前的文章&#xff0c; 一种误差较小的轮廓面积计算算法_轮廓面积计算原理-CSDN博客文章…

深入理解Qt中的QTableView、Model与Delegate机制

文章目录 显示效果QTableViewModel(模型)Delegate(委托)ITEM控件主函数调用项目下载在Qt中,视图(View)、模型(Model)和委托(Delegate)机制是一种非常强大的架构,它们实现了MVC(模型-视图-控制器)设计模式。这种架构分离了数据存储(模型)、数据展示(视图)和数据操作(委托),使…

Apple 新品发布会亮点有哪些 | Swift 周报 issue 61

文章目录 前言新闻和社区苹果据称正洽谈投资 OpenAI 英伟达也有意跟投消息称苹果公司服务部门将裁员约百人&#xff0c;波及 Apple Books / Apple News 等业务苹果拟 9 月 10 日举行今年最重磅新品发布会&#xff0c;iPhone 16 亮相&#xff1f;都有哪些看点&#xff1f; 提案正…

京东笔试题

和谐敏感词 &#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[…

【Spring篇】Spring中的Bean管理

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;Spring IOC容器 &#x1f6a…

如何开启华为交换机 http

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

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;因为底层会帮我们处理好类…