2024-04-03 NO.4 Quest3 手势追踪抓取物体

文章目录

  • [1 手势抓取方式](#1 手势抓取方式)
    • [1.1 Hand Grab](#1.1 Hand Grab)
    • [1.2 Touch Hand Grab](#1.2 Touch Hand Grab)
    • [1.3 Distance Hand Grab](#1.3 Distance Hand Grab)
  • [2 HandGrabExamples 示例场景](#2 HandGrabExamples 示例场景)
    • [2.1 Interactor 对象](#2.1 Interactor 对象)
    • [2.2 Interactable 对象](#2.2 Interactable 对象)
      • [2.2.1 父子结构](#2.2.1 父子结构)
      • [2.2.2 "Hand Grab lnteractable" 脚本](#2.2.2 “Hand Grab lnteractable” 脚本)
      • [2.2.3 "Move Towards Target Provider" 脚本](#2.2.3 “Move Towards Target Provider” 脚本)
      • [2.2.4 其他 Movement Provider](#2.2.4 其他 Movement Provider)
  • [3 抓取配置](#3 抓取配置)
    • [3.1 玩家配置](#3.1 玩家配置)
      • [3.1.1 自制预制体](#3.1.1 自制预制体)
      • [3.1.2 添加交互功能](#3.1.2 添加交互功能)
    • [3.2 物体配置](#3.2 物体配置)
      • [3.2.1 配置 HandGrabInteractable](#3.2.1 配置 HandGrabInteractable)
      • [3.2.2 One Grab Free Transformer](#3.2.2 One Grab Free Transformer)
      • [3.2.3 Two Grab Free Transformer](#3.2.3 Two Grab Free Transformer)
    • [3.3 颜色高亮显示](#3.3 颜色高亮显示)
  • [4 添加物理抛掷效果](#4 添加物理抛掷效果)
  • [5 录制抓取手势](#5 录制抓取手势)
    • [5.1 场景录制](#5.1 场景录制)
    • [5.2 工具录制](#5.2 工具录制)
    • [5.3 手势镜像和缩放](#5.3 手势镜像和缩放)
  • [6 远距离抓取物体](#6 远距离抓取物体)
    • [6.1 玩家配置](#6.1 玩家配置)
    • [6.2 物体配置](#6.2 物体配置)
      • [6.2.1 抓取配置](#6.2.1 抓取配置)
      • [6.2.2 添加物理效果](#6.2.2 添加物理效果)

1 手势抓取方式

1.1 Hand Grab

  1. 无抓取手势(手和物体会穿模)

    适合非实物的抓取,例如魔法球。

  1. 有抓取手势(给不同形状的物体制作不同的抓取手势)
  • Pinch Grab:手指靠近物体,做捏合动作激活。
  • Palm Grab:手掌靠近物体,做握持动作激活。
  • Pinch Grab + Palm Grab:多个抓取点,每个抓取点对应不同抓取姿势。

适用场景

​ 在需要精准抓取手势或者固定某几个抓取手势时,可使用 Hand Grab。

1.2 Touch Hand Grab

​ 可以在物体表面(准确来说是物体的碰撞体)上的任意位置进行抓取,抓取时手指会贴在物体表面上,可以用任意根手指进行抓取。

​ 相比于 Hand Grab,抓取手势更自由。

1.3 Distance Hand Grab

​ 在远距离通过射线抓取物体,可以将远处的物体抓取到手上,或者在远距离操控物体移动。

2 HandGrabExamples 示例场景

​ VR 中手势交互需要两个对象:

  • Interactor:发起交互的对象。
  • Interactable:可以被交互的对象。

2.1 Interactor 对象

​ 展开玩家物体 OVRCamreaRig,其子物体 OVRInteraction 是所有交互功能的父物体:

  • OVRHmd:头显交互。
  • OVRControllerDrivenHands:手柄交互(手柄控制虚拟手部模型的相关功能)。
  • OVRHands:手势追踪交互。

​ 展开 OVRHands > LeftHand > HandInteractorsLeft,可看到左手的 Interactor 共有两个:

  • HandPokeInteractor:手指点触交互(手指点击虚拟按钮)。
  • HandGrabInteractor:手部抓取交互。
  1. HandGrabAPI:检测 Hand Grab 是否选中或者取消选中可抓取物体。即,检测抓取动作是否发生。

  2. HandWristPoint:控制在抓取时虚拟手部和现实手部在位置和旋转角度上的偏移。

    • Offset:位置偏移。
    • Rotation:角度偏移。
  3. GripPoint:Palm Grab 的探测范围。

    调整 GripPoint 上的 HandWristOffset 脚本参数可以修改探测范围的位置和旋转角度。物体进入探测范围后触发抓取,会被吸到手上。

  4. PinchPoint:Pinch Grab 的探测范围。

    范围大小取决于 PinchPoint 子物体的 Collider 的碰撞体大小。

  5. PinchArea:PinchPoint 的 HandPinchOffset 脚本默认引用 PinchArea , PinchArea 碰撞体的位置会影响 PinchPoint 探测范围的位置。

  6. HandGrabVisual :连接 SyntheticHand ,在手部呈现出完整的抓取手势后固定手部姿态,让抓取手势不与物体穿模。

  7. HandGrabGlow:控制抓取时手部的特效。

    • Glow Color Grabing:抓取时特效的颜色。

    • Glow Color Hover:靠近时特效的颜色。

    • Glow Type:特效类型。

      • Outline:手指轮廓高亮。
      • Fill:手指颜色填充。
      • Both :结合 Outline 和 Fill。

2.2 Interactable 对象

2.2.1 父子结构

​ 可抓取物体上需要添加 "Grabbable" 脚本,以实现在抓取物体的时候控制物体的位移、旋转和缩放。

​ 可抓取物体下有一到多个 HandGrabInteractable 物体,即 Hand Grab 所需要的 Interactable 对象。

​ 在示例场景 HandGrabExamples 中,Interactable 对象被统一存放在 Interactables 路径下。以 SimpleGrab2PalmGrab 为例,其子物体 HandGrabInteractable 挂载了交互脚本 "Hand Grab lnteractable"。

2.2.2 "Hand Grab lnteractable" 脚本

  • Supported Grab Type:抓取方式。

    • Palm:捏合抓取。
    • Pinch:握持抓取。
    • All:二者均可。
  • Pinch / Palm Grab Rules:抓取触发手指的规则。

    Thumb、lndex、Middle、Ring、Max:大拇指、食指、中指、无名指、小指。

    • Required:标记了 Required 的手指,必须参与到抓取的触发过程中。即,想要抓起一个物体,必须要用到 Required 手指。
    • Optional:如果没有 Required 手指,则至少要用到一个标记 Optional 的手指。
    • Ignore:标记了 Ignore 的手指,不会被考虑到抓取的触发过程中。

    Unselect Mode:取消抓取的判定条件。

    • All Released:所有 Required 或者 Optional 手指松开后,视为取消抓取。
    • Any Released:有一个 Required 手指松开后,视为取消抓取。
  • Hand Alignment(Unity 中单词拼写错误):决定虚拟手如何变化到对应的抓取手势。

    • None:没有对应限制,会穿模。与没有添加 SyntheticHand 效果一样。
    • AIign On Grab:靠近物体时(即处于 hover 状态)虚拟手会与物体发生穿模。抓取时手部从物体内部快速调整到物体表面。
    • Attract On Hover:靠近物体时虚拟手会被限制在物体外部,不会穿模。抓取时手部直接吸附在物体表面。
    • Align Fingers On Hover:靠近物体时虚拟手会慢慢靠近物体。抓取时手部慢慢吸附到物体表面,穿模程度较小。
  • [Optional] ScaIed Hand Grab Poses:为不同大小的手配置相应的抓取手势。

    • HandGrab Point:后续专门介绍。

2.2.3 "Move Towards Target Provider" 脚本

​ 在运行程序时,如果当前 HandGrabInteractable 物体上没有挂载 "Move Towards Target Provider" 脚本,"Hand Grab lnteractable" 脚本会自动添加 "Move Towards Target Provider" 脚本,用于控制物体被抓取时朝向手部的移动。

  • Travel Speed:移动速度。值越大,移动时间越长。

​ 如果想在程序运行前控制物体朝向手部的移动速度,可以在 HandGrabInteractable 物体上添加 "Move Towards Target Provider" 脚本,并设置其引用。

2.2.4 其他 Movement Provider

(1)Move From Target Provider

​ 抓取时将手部吸附到物体上,而不是物体吸附到手上。

(2)Follow Target Provider

​ 抓取时物体会跟随手部移动,具有阻尼效果。

  • Speed:物体跟随速度。

3 抓取配置

3.1 玩家配置

3.1.1 自制预制体

(1)将 《2024-04-01 NO.3 Quest3 手势追踪与玩家角色配置》 文章中 SampleScene 场景下的 OVRCameraRig 进行 Prefab Unpack Completely,之后拖拽到 Assets > Prefabs 文件夹下。

3.1.2 添加交互功能

(1)在 Package 中找到 HandGrabInteractor 预制体,将其拖拽为 SampleScene 场景中 MyOVRCameraRig > OVRInteraction > OVRHands > LeftHand > HandInteractorsLeft 的子物体。并对 RightHand 进行同样的操作。

(2)场景中展开 LeftHand 下的 HandGrabInteractor 对象,将其 Visuals 下的两个子对象 HandGrabVisual 和 HandGrabGlow 激活,并设置对应的引用参数。同样的操作应用于 RightHand(步骤中所有 Left 对象改为 Right)。

  • HandGrabVisual:
    • Synthetic Hand <-- OVRLeftHandSynthetic。
  • HandGrabGlow:
    • Hand Visual <-- OVRLeftHandSynthetic > OVRLeftHandVisual。
    • Hand Renderer <-- OVRLeftHandSynthetic > OVRLeftHandVisual > OculusHand_L > l_handMeshNode。
    • Material Editor <-- OVRLeftHandSynthetic > OVRLeftHandVisual > OculusHand_L > l_handMeshNode。

(3)找到 LeftHand > HandInteractorsLeft 物体上的 "Best Hover lnteractor Group" 脚本,将 HandInteractorsLeft 物体拖拽入 Interactors 列表中。同样的操作应用于 RightHand > HandInteractorsRight 物体(步骤中所有 Left 对象改为 Right)。

​ Interactors 列表存储不同种类的 Interactor 脚本。

​ Interactor Group 保证其列表下的所有 Interactor 在同一时刻只有一个进行交互,而其他 Interactor 暂时失活。

​ 此处 Best Hover Interactor Group 是 Meta XR SDK 中 Interactor Group 的其中一种。其特性是:

  1. 保证优先级高的 Interactor 进入到 hover 状态,优先级低的 Interactor 会暂时失活。

  2. 默认情况下,越靠前的列表元素拥有越高的优先级。

3.2 物体配置

3.2.1 配置 HandGrabInteractable

(1)在场景中创建一个桌面(Cube,这里配置了红色材质),桌面上放一个立方体 Cube 用于抓取。

​ 同时,给 Cube 添加 Rigidbody 和 Grabbable 组件,并将其 Box Collider 设置为 Trigger,取消勾选 Rigidbody 的 Use Gravity 选项。

​ 最后,勾选 Grabbable 的 Transfer On Second Selection 选项,以实现左右手交替抓取。

(2)在 Project 中找到 HandGrabInteractable 预制体,将其拖拽为 Cube 的子物体。可以看见 HandGrabInteractable 自动寻找到了其父物体中的 Grabbable 和 Rigidbody。

3.2.2 One Grab Free Transformer

​ 到此,运行程序,可以实现双手抓取移动 Cube。

​ 运行程序时,可以看到 Cube 物体上自动添加了 One Grab Free Transformer 脚本,并且被 Grabbable 脚本引用。

​ Grabbable 脚本通过 Transformer 来控制物体被抓取时的移动旋转和缩放。默认使用 One Grab Free Transformer 脚本(一只手控制)。

​ 其他 One Grab Transformer:

  • One Grab Rotate Transformer:仅控制物体旋转。
  • One Grab Scale Transformer:仅控制物体缩放。
  • One Grab Translate Transformer:仅控制物体平移。
  • One Grab Physics Joint Transformer:相对而言使用的很少。

3.2.3 Two Grab Free Transformer

​ 取消勾选 Cube 挂载的 Grabbable 脚本的 Transfer On Second Selection 选项,并更换 One Grab Free Transformer 脚本为 Two Grab Free Transformer 脚本,即可使用双手操控物体。

​ 若想实现单双手都可操控,则同时添加 One Grab Free Transformer 脚本即可。

3.3 颜色高亮显示

(1)在 Cube 下方新建空子物体 Visuals,用于控制 Cube 的颜色显示。

(2)为 Cube 依次添加以下脚本:

  1. Interactable Color Visual:控制物体在各种状态下显示的颜色。

    需要设置:

    • Interactable View <-- Material Property Block Editor 脚本。
    • Editor <-- Interactable Group View 脚本。
  2. Material Property Block Editor:关联物体材质。

    需要设置:

    • Renderers <-- Cube 的 Mesh Renderer 组件。
  3. Interactable Group View:可交互物体组。

    需要设置:

    • Interactables <-- HandGrabInteractable。

​ 设置完成后,即可通过改变 Interactable Color Visual 中的 Color State 来更改物体对应状态的颜色。

​ 到此,我们可以对 Cube 进行抓取、移动和旋转,但是没有录制抓取手势。

4 添加物理抛掷效果

(1)取消 Cube 的 Box Collider 的 Trigger 选项,并勾选 Rigidbody 的 Use Gravity。此时,手部可以和 Cube 进行碰撞,手部碰撞体在 MyOVRCameraRig > TrackingSpace > LeftHandAnchor > OVRHandPrefab 下(运行状态下可见)。

​ 这里运行时产生碰撞体是因为先前设置了 Enable Physics Capsules 选项。

(2)为 Cube 添加 Physics Grabbable 脚本,添加时会自动关联 Cube 上的 Rigidbody 和 Grabbable。

(3)将 Cube 上的 Physics Grabbable 脚本关联到 HandGrabInteractable 对象上。

(4)在 Project 中找到 HandVelocityCaIculator,将其拖拽为 LeftHand / RightHand 的子物体。

(5)关联对应的 LeftHand / RightHand。

(6)将 HandVelocityCaIculator 关联到 HandInteractorsLeft > HandGrabInteractor 和 HandInteractorsRight > HandGrabInteractor 对象上。

​ 此时,即可完成 Cube 物理抛掷的效果。

​ 如果在抛掷过程中有穿模现象,可以将 Cube 的 Rigidbody 的 Collision Detection 设置为 Continuous Dynamic,进行连续动态的碰撞检测,但性能消耗会更大。

5 录制抓取手势

5.1 场景录制

​ 录制抓取手势需要在 Unity 编辑器运行模式下进行,并且需要将头显和电脑进行串流(串流部分在 《2024-03-28 NO.1 Quest3 开发环境配置教程-CSDN博客》 中提及)。

(1)打开 HandGrabPoseTool 场景,添加待录制的物体 Cube(这里还添加了一个子物体 Cube)。并确保物体上挂载 Rigidbody 组件和 Grabbable 脚本,没有则手动添加。

​ 这里将 BoxCollider 设置为 Trigger,取消勾选了 Rigidbody 的 Use Gravity 选项,并勾选了 Grabbable 脚本的 Transfer On Second Selection。

(2)运行 Unity,按下按钮,开始做抓取手势动作,3s 后将自动结束录制。若想要延长录制准备时间,可在前方点击按钮进行调整。注意,录制完成后不要急着退出运行模式。

(3)录制完成后,可以看见 Cube 下方多了 HandGrabInteractable 子物体。首先将 Cube 拖拽至 Assets > Prefabs 文件夹下成为预制体,再退出 Unity 运行模式。

(4)在 Unity 编辑模式下,删除场景中原有的 Cube,将刚创建的预制体拖入场景,开始进行手势微调。

​ 点击 HandGrabInteractable > HandGrabPose 物体,找到其挂载的 Hand Grab Pose 脚本,调节其参数以达到想要的手势。

  • Fingers Freedom:手指灵活程度。

    • Locked:抓取时,虚拟手指无法跟随现实手指进行弯曲。
    • Constrained:抓取时,虚拟手指可以向外弯曲而不能向内。
    • Free:抓取时,虚拟手指不受限制。
  • Joint Angles:关节角度。

    改变值可旋转每个关节的角度,也可以在 Scene 窗口中直接旋转蓝色圆圈编辑调节。

​ 微调完成后,失活 HandGrabPose 的子物体 Ghost-RightHand(Clone),即可取消显示录制手势。之后抓取物体时,手部会呈现刚录制好的姿势。

5.2 工具录制

​ 点击上方菜单 Oculus > Interaction > Hand Grab Pose Recorder,打开录制窗口。

(1)配置场景中想要录制的手,以及待录制物体的刚体组件。这里选择的是右手。

(2)运行 Unity,在做好手势后用鼠标点击 Record HandGrabPose 按钮即可完成录制。建议录制时将物体的 Collider 选择 Trigger,并取消勾选了 Rigidbody 的 Use Gravity。

​ 由于录制时带着头显,不方便使用鼠标。因此可以配置相应的键盘按键(默认是空格),按下该键盘按键后即可完成录制。使用键盘按键来结束录制时,需要先将鼠标双击

Hand Grab Pose Recorder 录制窗口,以获取焦点。

​ 注意,录制完成后不要急着退出运行模式。

(3)录制完成后,点击 Save To Collection 按钮保存录制结果,再退出 Unity 运行模式。

(4)在 Unity 编辑模式下点击 Load From Collection 按钮,即可获取刚录制的手势。

​ 可以看到,Cube 下方添加了两个 HandGrabInteractable,且其中一个记录了手势。其上方没有手势的 HandGrabInteractable 是因为录制前 Cube 拥有一个 HandGrabInteractable 子物体,在读取结果时将其一并拷贝了进来,这里删除即可。

​ 之后录制时,不需要先给物体配置 HandGrabInteractable,添加好 Rigidbody 后直接录制即可。

5.3 手势镜像和缩放

​ 选中需要镜像手势的父物体 HandGrabInteractable,点击 Create Mirrored HandGrabInteractable 按钮,即可生成镜像手势。

​ 调节 Scaled Hand Grab Poses 下方的 Scale 值,点击 Add HandGrabPose Key with Scale XXX 按钮后,即可生成对应缩放比例的手势。

6 远距离抓取物体

6.1 玩家配置

(1)在 Project 窗口中找到 DistanceHandGrabInteractor 预制体,将其拖拽为 HandInteractorsLeft / HandInteractorsRight 的子物体。同时,将其挂载到 HandInteractorsLeft / HandInteractorsRight 的 Interactors 列表下。

(2)展开 DistanceHandGrabInteractor 的 Visuals 子物体,将其两个子物体激活。并进行如下关联(与 [3.1.2 节](#3.1.2 节) 相同):

  • HandGrabVisual:
    • Synthetic Hand <-- OVRLeftHandSynthetic。
  • HandGrabGlow:
    • Hand Visual <-- OVRLeftHandSynthetic > OVRLeftHandVisual。
    • Hand Renderer <-- OVRLeftHandSynthetic > OVRLeftHandVisual > OculusHand_L > l_handMeshNode。
    • Material Editor <-- OVRLeftHandSynthetic > OVRLeftHandVisual > OculusHand_L > l_handMeshNode。

​ 同样的操作对 OVRRightHandSynthetic 再执行一遍(步骤中所有 Left 对象改为 Right)。

(3)将先前配置好的 HandVelocityCalculator 关联到 DistanceHandGrabInteractor 上。该步骤为可选,但需注意左右手对应配置。

6.2 物体配置

6.2.1 抓取配置

​ 参考 [3.2.1 节](#3.2.1 节) 内容,创建一个 Cube,添加 Rigidbody 和 Grabbable 脚本,并将其设置为 Trigger,取消 Use Gravity。

​ 之后,为该物体添加 Distance Hand Grab Interactable 脚本,添加时会自动关联 Cube 上的 Rigidbody 和 Grabbable。

​ 此时运行 Unity,双手对准 Cube 握拳后,Cube 会被远距离抓到手上。这是因为 Cube 上 Interactable 脚本的 Supported Grab Types 和 RightHand 下 Interactor 的 Supported Grab Types 都是 Pinch。 如果不匹配,则不会被抓取。

6.2.2 添加物理效果

(1)准备模型,这里使用两个 Cube 当成一把剑。其父子结构如下图。

​ 给 Sword 添加 Rigidbody 和 Grabbable 组件,同时添加 Physics Grabbable 脚本。

​ Cube 和 Cube (1) 上带有 BoxCollider,且均设置为 Trigger。

(2)进行手势录制,并做一些微调。这里将所有手指都设置为 Locked。

(3)在生成的 HandGrabInteractable 物体上添加 Distance Hand Grab Interactable 脚本,并为其关联 Physics Grabbable 脚本。

​ 对于 Hand Grab Interactable 脚本,其 Physics Grabbable 的引用在录制时被自动关联,因此这里不需要再重复关联。也可以手动检查确认一下。

(4)恢复物体的 Use Gravity,并且将 Collider 的 Trigger 选项取消。此时这把"剑"便拥有了远距离抓取和抛掷的功能。

相关推荐
小春熙子4 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
Sitarrrr6 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧6 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
逐·風14 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i15 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
Leoysq1 天前
【UGUI】实现点击注册按钮跳转游戏场景
游戏·unity·游戏引擎·ugui
_oP_i1 天前
unity中 骨骼、纹理和材质关系
unity·游戏引擎·材质
Padid2 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
Tp_jh2 天前
推荐一款非常好用的C/C++在线编译器
linux·c语言·c++·ide·单片机·unity·云原生
dangoxiba2 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十八集补充:制作空洞骑士独有的EventSystem和InputModule
游戏·unity·c#·游戏引擎·playmaker