unityvr开发教程openxr+xrinteractiontoolkit手部动画(代码片段)

YY-nb YY-nb     2023-04-07     123

关键词:

文章目录


往期回顾:
Unity VR开发教程 OpenXR+XR Interaction Toolkit (一) 安装和配置
上一篇教程我们成功安装和配置了 Unity OpenXR+XR Interaction Toolkit 开发 VR 的环境,最终将 VR 头显和电脑进行串流后,能通过头显看到 Unity 中的场景,并且头部、手柄的位移和转动也能准确定位。

但是因为我们没有添加手部的模型,所以手柄的位置是空荡荡的,如下图:

而 VR 世界里怎么能看不见自己的手呢?🤔 所以本篇教程就来介绍如何在我们的 VR 世界中添加手部模型,以及如何用手柄的按键来控制手部模型的动作。


📕教程说明

使用的 Unity 版本: 2020.3.36

使用的 VR 头显: Oculus Quest 2

教程使用的 XR Interaction Toolkit 版本:2.1.1(此教程尽量考虑了向上兼容,如果有过期的地方,欢迎大家指出)

前期的配置:见教程一

项目源码(持续更新):https://github.com/YY-nb/Unity_XRInteractionToolkit_Tutorial2022/tree/master

最终实现的手部动画:按下手柄的 Trigger 键让大拇指和食指做出捏合的动画,按下手柄的 Grip 键让整只手做出抓握的动画。了解原理后也可以自定义手部动画和手柄按键的对应关系,做出适合自己需求的手部动画。

效果图:

注:本篇博客的内容参考自油管大佬的这个视频 https://m.youtube.com/watch?v=8PCNNro7Rt0 ,相当于基于这个教程整理的一篇学习笔记。


📕第一步:导入手部模型

我使用的是 Oculus Hand Unity 资源包,里面自带了手部模型的动画。这里提供一个百度云盘的下载链接:

链接:https://pan.baidu.com/s/15Y03XzgMUf7TQO_060zWyg?pwd=1voo
提取码:1voo

还有一个 CSDN 资源的链接:

Oculus Hands VR手部模型Unity资源包 (含有动画)

接下来我会简单分析一下这个资源包,以及手部动画制作的思路。如果你用了其他模型,并且想制作自己的手部动画,那么也可以用类似的思路进行制作。

下载完毕后就是一个 Unity 的 Package,然后我们要在 Unity 中导入这个资源,点击菜单栏的
Assets -> Import Package -> Custom Package,导入成功后可以看到 Unity 中多出了这个文件夹:

注:这个资源包的模型需要用到 URP 渲染管线如果项目是普通的 3D 项目,需要将项目升级为 URP,升级方法可以自行搜索,网上也有很多相关的教程。

然后我们简单地看一下这个资源包, Prefabs 里就是左手和右手的模型:

关键是 Animations 文件夹,这个资源包已经帮我们做好了一些手部的动画,包含了 Animator Controller 和相应的 Animation:

然后我们打开左手的 Animator Controller 看一看,发现里面有一个动画混合树:

控制动画的 Parameter 包含了 float 类型的 Grip 和 Trigger,代表了按下手柄的 Grip 键和 Trigger 键。为什么是 float 类型呢?因为这两个手柄的按键会有一个按下的程度,按下的程度不同,手部的动画也会有所不同。比如轻微按下 Grip 键,手做出微微抓取的姿势;完全按下 Grip 键,手做出紧紧抓握的姿势。

然后打开 Blend Tree ,可以看到这是一个 2D 混合树:

这边就两个重要的动画,一个是捏合(hand_pinch_anim),一个是抓握(hand_first)。我们可以点击下图中的这些动画文件查看具体的动画:

我这边打开一个 l_hand_pinch_anim,具体面板见下图:

第二个关键帧的手部模型姿势如下:

因此上图就是完全按下 Trigger 键后手部应该有的姿势。因为这个资源包里的动画是只读的,所以我们没法对这些动画进行修改。如果对已有的手部动画不满意,或者导入的是其他不带动画的手部模型,我们可以模仿它的思路,自定义手部的姿势。感兴趣的小伙伴可以自己创建手部的 Animation ,在第二个关键帧去修改手部模型各个关节的旋转角度,如下图的这些节点:


那么这个 Oculus Hands 资源包的讲解差不多就到这。我们也可以模仿它的做法去自定义 Animator Controller 和 相应的手部动画。当然也可以不用 2D 混合树去混合动画,因为很多时候我们会用三个按键去控制手的动画(大部分 VR 应用是这样),那么这时候也可以用动画分层的思想,为每个按键分配一个动画层,然后将状态间的切换进行连线。


📕第二步:将手部模型拖入场景

首先依照本系列教程的第一篇配置好场景:

然后把左手和右手的模型分别作为 LeftHand Controller 和 RightHand Controller 的子物体:

在手的 Prefab 中加上对应的 Animator Controller:

这个时候我们可以试着运行一下程序,我们可以发现手部模型已经可以跟随手柄运动了,但是按下手柄的按键后手没有任何反应。因此,我们需要写个脚本去控制 Animator。


📕第三步:编写脚本控制手部动画(版本一:基于 Input System,推荐做法)

我们新建一个脚本,挂载到手部模型上,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class AnimateHandController : MonoBehaviour

    public InputActionProperty pinchActionProperty;
    public InputActionProperty gripActionProperty;
    private InputAction pinchAction;
    private InputAction gripAction;
    private Animator animator;
    // Start is called before the first frame update
    void Start()
    
        pinchAction = pinchActionProperty.action;
        gripAction = gripActionProperty.action;
        animator = GetComponent<Animator>();
    

    // Update is called once per frame
    void Update()
    
        float triggerValue = pinchAction.ReadValue<float>();
        animator.SetFloat("Trigger", triggerValue);

        float gripValue = gripAction.ReadValue<float>();
        animator.SetFloat("Grip", gripValue);
    


注意点:

1)需要 using UnityEngine.InputSystem,因为我们按键绑定的动作已经在默认 Input Action Asset 中配置好了(这个东西是在配置环境的时候创建的),所以会用到 InputSystem 的一些知识。

2)我们需要将 Input Action Asset 中的动作和我们创建的这个脚本进行绑定,分别需要按下 Trigger 键的动作和按下 Grip 键的动作。这里我使用了 InputActionProperty 这个类,既可以引用 Input Action Asset 中已经存在的 Action,也可以自己新建 Action,Inspector 面板里显示如下:

我们直接用已有的 Action,所以勾选 Use Reference:

那么我们需要将什么东西赋给这些 Reference 呢?我们可以打开默认的 Input Action Asset(如下):

这里以左手为例(见下图):

找到 XRI LeftHand Interaction 下的 Select Value 和 Activate Value,可以看到 Select Value 代表了 grip 按键, Activate Value 代表了 trigger 按键。那为什么是选 Value 呢?这和 Animator Controller 中的 Parameter 是一样的道理,我们需要根据按键按下的程度,来决定动画播放的程序。

那么接下来就是找到我们想要的 InputActionReference,右手也是同理。


3)读取手部按键按下的程度使用 InputAction 类的 ReadValue<T>() 这个方法,而使用 InputActionProperty 类中的 action 属性可以获取它的 InputAtion。所以现在,你应该能够看懂上面的这一段代码了吧。

接下来,我们可以运行一下程序,正常来说,这时候手的动画能够成功运行了。但实际上,你应该会感觉此时的效果离我们想象中的还有一些差距,所以我们还需要做一些微调。

📕第三步:编写脚本控制手部动画(版本二:基于 XR Input Subsystem)

版本一的脚本运用了 Input System 的知识。而 XR Input Subsytem 是 Unity 提供的另一种用于处理设备输入的系统,需要运用到 UnityEngine.XR 这个命名空间,以下是基于 XR Input Subsystem 实现的手部动画控制代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;

public class HandPresence : MonoBehaviour

    public InputDeviceCharacteristics controllerCharacteristics;    
    private InputDevice targetDevice;
    private Animator handAnimator;
    
    private void Start()
    
        handAnimator = GetComponent<Animator>();
        TryInitialize();
    


    private void TryInitialize()
    
        List<InputDevice> devices = new List<InputDevice>();

        InputDevices.GetDevicesWithCharacteristics(controllerCharacteristics, devices);
        if (devices.Count > 0)
        
            targetDevice = devices[0];
        
    

    private void UpdateHandAnimation()
    
        if (targetDevice.TryGetFeatureValue(CommonUsages.trigger, out float triggerValue))
        
            handAnimator.SetFloat("Trigger", triggerValue);
        
        else
        
            handAnimator.SetFloat("Trigger", 0);
        

        if (targetDevice.TryGetFeatureValue(CommonUsages.grip, out float gripValue))
        
            handAnimator.SetFloat("Grip", gripValue);
        
        else
        
            handAnimator.SetFloat("Grip", 0);
        
    

    private void Update()
    
        if(!targetDevice.isValid)
        
            TryInitialize();
        
        else
        
            UpdateHandAnimation();
        
    


Unity 的 XR 架构提供了不同厂商的硬件设备和输入之间的映射。虽然不同设备的设计会有些不同,但是可以检测相同的输入的动作,比如不同的手柄都能触发 “trigger”,“grip” 等动作。因此 Unity 只要检测某个输入动作是否发生,就能将这个输入动作映射到不同硬件设备的按键上,比如我按下了 Oculus 手柄的 Grip 按键,就代表输入了 “grip” 这个动作;再比如我转动 Oculus 手柄的摇杆(JoyStick)或者转动 Vive 手柄上的那个圆形触摸板(Touchpad),都可以用 “primary2DAxis” 来表示,得到的是一个 Vector2 类型的坐标,代表摇杆或触摸板位移的程度,这经常用于人物的移动当中。这样做能消除不同硬件设备的差异,和 Input System,OpenXR 的思想是类似的。

下图是 Unity 官方文档的不同厂商设备按键与动作输入的映射表,这些是 Unity 目前支持的设备:

上图中第一列的 InputFeatureUsage 类型的变量都存储在了 CommonUsages 这个静态类中,如图:

那怎么去使用这些变量呢?我们还需要了解一下其他相关的类。

Unity 的 XR 系统用 InputDevice 这个类来表示用于检测输入的硬件设备,用 InputDeviceCharacteristics 这个类来表示硬件设备的一些特征。我们回看版本二的脚本代码,在开头声明了 public InputDeviceCharacteristics controllerCharacteristics; 因此,我们可以到 Unity 编辑器的 Inspector 面板中看看这是什么东西。在此之前,我们要把这个脚本分别挂载到左手和右手的模型 Prefab 上,如图:

可以看到这边有个类似选项框的东西,有很多选项可以选择(可多选):

这些选项就包含了输入设备的一些特征。因为我们要检测手柄的输入,所以左手柄选择 Controller 和 Left,右手柄选择 Controller 和 Right。

约束了特征之后,就能够借助 InputDevices.GetDevicesWithCharacteristics 这个方法筛选出想要检测输入的设备列表。因为一个手部动画的脚本对应一个手柄输入的检测,所以返回列表的第一个元素就能得到对应的 InputDevice 类型的手柄。

然后用 InputDevice 类下的 TryGetFeatureValue 方法就能获取按键输入的值:

targetDevice.TryGetFeatureValue(CommonUsages.trigger, out float triggerValue)
targetDevice.TryGetFeatureValue(CommonUsages.grip, out float gripValue)

接下来的思路就和版本一的代码差不多了,读取到了按键的输入,我们就可以将输入的值用于 Animator。此外,最好在 Update 里判断一下当前的设备是否还有效,如果失去检测了,需要重新初始化检测的设备。

private void Update()
    
        if(!targetDevice.isValid)
        
            TryInitialize();
        
        else
        
            UpdateHandAnimation();
        
    

以上便是版本二的代码讲解,大家可以从两个版本中选择一个自己喜欢的作为手部动画的控制脚本。基于 XR Input Subsystem 的版本在 Inspector 面板中的操作更为方便,而基于 Input System 的版本在动作与输入的绑定上更加灵活。因为 XR Input Subsystem 中的动作与设备的按键是绑死了的,而 Input System 可以自定义动作与哪个按键进行绑定,比如我想按下手柄的 Trigger 键来进行抓握,可以直接在 Input Action Asset 里进行更改。但是 XR Input Subsystem 只允许按下手柄的 Grip 键来进行抓握。


📕第四步:调整场景

这时候,可能会存在这么几个问题,那么我们就来一个一个解决它们。

问题一:
手部模型的旋转角度看起来不大对。模型默认是手背朝上,但是这和现实中我们拿着手柄的角度是不同的,所以这时候的手感是比较奇怪的。

解决方法:
调整手部模型的旋转角度,我这里把左手的 Z Rotation 设为 90,把右手的 Z Rotation 设为 -90。这个时候,模型的角度如下,可以看到手的侧面朝上,这与现实中拿手柄的角度是接近的。

问题二:
VR 里手的位置会和现实世界的手有些偏移,造成使用手感较为奇怪。

解决方法:
调整手部模型的 position。我这边调的 position 如下,大家可以用来参考,测试手部模型和现实中手部的位置的偏移程度。

问题三:
手的阴影显示不正常。看到的是奇怪的形状,而不是手的阴影。

解决方法:
找到 URP 的配置文件,调整 Shadows -> Cascade Count 的值,如图所示:

我这里把值调到了 4,此时阴影显示就稍微正常了些。如果想要影子的效果更精细一点,可以试试调整 Shadows 下的其他数值。


这时候,你也许会疑惑为什么我的手没有发出射线。其实我先把它关闭了,大家可以分别在 LeftHand Controller 和 RightHand Controller 游戏物体找到 XR Ray Interactor 这个组件,然后将它关闭。


那么现在,咱们的 Demo 就大功告成了!快去试一试用手柄控制虚拟世界中的双手吧!😊

unityvr开发教程openxr+xrinteractiontoolkit手部动画(代码片段)

...Subsystem)📕第四步:调整场景往期回顾:UnityVR开发教程OpenXR+XRInteractionToolkit(一)安装和配置上一篇教程我们成功安装和配置了UnityOpenXR+XRInteractionToolkit开发VR的环境,最终将VR头显和电脑进行串流后,... 查看详情

unityvr开发教程openxr+xrinteractiontoolkit(六)手与物品交互(触摸抓取)(代码片段)

文章目录📕教程说明📕VR交互的类型📕发起交互的对象(Interactor)⭐XRDirectInteractor脚本⭐添加可交互区域📕可交互的对象(Interactable)⭐添加刚体⭐XRSimpleInteractable脚本⭐InteractableEvents⭐XRGrabInter... 查看详情

unity开发openxr|使用openxr制作一款简单vr示例场景的全过程详细教程,包含两个实战案例。

文章目录 查看详情

unity开发openxr|使用openxr添加一个运动系统,实现传送抓取功能的简单vr示例场景的全过程详细教程

文章目录 查看详情

unity开发openxr|使用openxr制作一款简单vr示例场景的全过程详细教程,包含两个实战案例。(代码片段)

文章目录📢前言🎬OpenXR|使用OpenXR制作一个简单VR示例场景的全过程详细教程🏳️‍🌈打开UnityHub新建一个Unity项目🏳️‍🌈添加XRPluginManagment🏳️‍🌈配置安卓版本🏳️‍🌈导入XRInterac... 查看详情

unity开发openxr|openxr是什么?一文带你全面了解openxr的相关知识,上车收藏不迷路

文章目录OpenXROpenXR出现的背景标准化有何好处Khronos百度百科Khronos相关标准OpenXR概念行业行情总结OpenXR“OpenXR”旨在标准化各种VR/AR平台上的设备和应用程序之间的规范。它由KhronosGroup制定,KhronosGroup是一个由VR/AR相关公司组... 查看详情

unityxrunity开发openxr

Unity开发OpenXR介绍OpenXR相关依赖插件OpenXROpenXRPluginXRInteractionToolkitXRPluginManagement安装OpenXR相关依赖插件PackageManagerUnityVR模板配置OpenXR相关依赖插件安装PicoXRSDK下载PICOUnityIntegrationSDKPackageManager导入SDK介绍OpenXR相关依赖插件OpenXROpenXR... 查看详情

unity开发openxr|使用openxr制作一款《保龄球demo》加深对controller控制器的理解使用

查看详情

unity使用openxr和xrinteractiontoolkit开发htcvive(vivecosmos)(代码片段)

Unity使用OpenXR和XRInteractionToolkit开发HTCVive(ViveCosmos)提示:作者是Unity2020.3以上版本做的开发。开发VR程序需要安装Steam,SteamVR,(ViveCosmos,需要再安装VIVEPORT,VIVEConsole)OpenXR控制设备(头盔,手柄)通信。XR... 查看详情

unityvr视频/图片开发心得

  上回说到了普通的全景图片,这回讲真正的VR。  由于这种图片分为两部分,所以我们需要两个Camera对象以及两个球体。首先新建一个Camera对象,并将其命名为RightEye(其它名字也无妨,只要你自己清楚就行了),将本来... 查看详情

unityvr视频/图片开发心得

  现在的VR似乎没有之前那么火热了,于是乎我居然开始了VR征程。。。  说起VR,对于没有接受过相关知识的人来说可能看起来比较高大上,但是VR的原理却没有想象中那么复杂。总的来说,VR之所以能够产生立体感,是因... 查看详情

unityvr关于oculus如何连接unity编译器,无需打包就可以看到场景的教程(代码片段)

前言几天的碰壁,没有白费,可以说光是做一个能让让Oculus跑起来的demo这个过程中,几乎是一个坑连着一个坑,国内教程不完善,google也有少量的坑。。。下面就开始吧,我尽量每一步都说详细点!切... 查看详情

unityvr开发结合vrtk4.0:将浮点数从交互器传递到可交互对象(代码片段)

语录:   愿你熬得过万丈孤独,藏得下星辰大海。前言:    默认情况下,交互器只能将单个布尔操作传递给可交互对象,后者控制可交互对象上的抓取操作。在其他时候,交互器中的其他操作可能希... 查看详情

unityvr开发结合vrtk4.0:将浮点操作转换为布尔操作

语录:奈何桥上奈何愁,奈何桥下浣溪流,奈何人人奈何泪,奈何奈何洗春秋。前言:   有时,您可能希望使用一个值来激活或停用操作类型。例如,按下控制器上的扳机轴会导致在完全按下扳机时... 查看详情

vr/ar标准委员会成立,宣布全新的标准openxr

Khronos集团在今天早些时候宣布了开放VR/AR标准委员会——OpenXR工作组。这一组织也将会由世界领头羊VR/AR公司的代表组成。而宣布的公司中包括:Facebook子公司Oculus、valve、unity、Epic、三星和谷歌,但是并不包含HTC的子公司Vive。Vi... 查看详情

unityvr一体机报错:gl_out_of_memory,[egl]unabletoacquirecontext

开发和部署环境Unity:2020.3.40PicoG24k一、报错信息一览(1)[EGL]Unabletoacquirecontext:EUnity:[EGL]Unabletoacquirecontext:EGL_BAD_SURFACE:AnEGLSurfaceargumentdoesnotnameavalidsurface(window,pixelbufferorpixmap)configuredforGLrendering.解决办法:多线程渲... 查看详情

unityvr&arunity播放全景视频及优化极点变形twist问题(代码片段)

2016年是VR元年,这一年度多少少做了点东西,都是关于VR&AR的,虽然现在是冷冬期,个人认为前景还是有的,只不过会曲折前进,工业革命还分好几次呢,对吧!好了,最近比较空闲,会... 查看详情

关于在unityvr中,可以让电脑显示屏幕显示另一个视角的画面,而步影响到vr里面的视角操作vrasymmetrical

第一步是新建一个场景然后不要删除场景中的maincamera,把这个摄像机当成运行后,另一个视角然后将steamvrplugin导入,将里面prefab文件中的cameraRig拖到场景中,然后建一个脚本,在start里面就执行一行代码UnityEngine.VR.VRSettings.ShowDe... 查看详情