草庐IT

Unity VR开发教程 OpenXR+XR Interaction Toolkit (三) 转向和移动

YY-nb 2024-03-26 原文

文章目录


往期回顾:
Unity VR开发教程 OpenXR+XR Interaction Toolkit (一) 安装和配置
Unity VR开发教程 OpenXR+XR Interaction Toolkit (二) 手部动画

在之前的教程中,我们成功实现了用手柄来控制手部模型的姿势。这篇博客,我们一起来实现通过手柄控制人物的转向和移动。


📕教程说明

使用的 Unity 版本: 2020.3.36

使用的 VR 头显: Oculus Quest 2

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

前期的配置:环境配置参考教程一,手部模型参考教程二

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

最终实现的效果:转动右手柄摇杆可以进行转向,转动左手柄摇杆可以进行移动,并且人物可以上楼梯。

效果图:


📕瞬间转向

在一些 VR 游戏里,转动手柄的摇杆会瞬间转过一个角度,那么这个功能要怎么实现呢?

在 XR Interaction Toolkit 中,有一个 Locomotion System 专门处理人物的运动。我们可以在 Hierarchy 窗口中点击鼠标右键,如图所示选择 Locomotion System (Action-based):

可以看到新建了一个游戏物体,然后我们看看 Inspector 面板:



默认是有三个脚本:

  • Locomotion System 可以直接控制场景中的 XR Origin(在 VR 中就是我们自己的身体),从而实现 VR 中人物的运动。XR Origin 的引用会在游戏开始运行时自动赋值。
  • Teleportation Provider 是传送功能需要用到的脚本,这个放到下一篇教程来解释。
  • Snap Turn Provider 就是实现瞬间转向的脚本。

注:只要有 Locomotion System 和 Snap Turn Provider 这两个脚本就能实现瞬间转向,脚本挂载在任意游戏物体上都是可以的。

因为正常来说是一只手柄控制转向,另一只手柄控制移动。所以我们需要根据自己的需求将 Snap Turn Provider 脚本下的 Left Hand Snap Turn Action 和 Right Hand Snap Turn Action 的其中一个取消勾选。我这边是想让右手柄负责转向,所以把左手的 Action 禁用了:

那么现在可以运行游戏看看效果,当转动右手柄的摇杆时,视角会瞬间旋转一个角度:
(注:之后要实现上楼梯的功能,我这边先在场景中搭了一个简单的楼梯,也是作为旋转的参考物。另外我把 XR Origin 下的 LeftHand Controller 和 RightHand Controller 的 XR Ray Interactor 给禁用了,所以手不会发出射线。)

不错!此外,我们可以修改 Turn Amount 的值来调整瞬间转向的旋转角度:


📕持续转向

有时候,我们不希望瞬间转向,而是能看到一段旋转的过程,我们就把这种需求叫做持续转向吧。XR Interaction Toolkit 也提供了相应的脚本,叫做 Continous Turn Provider,我们可以直接添加这个组件:


(注:选择 Action-based 的版本,这是官方推荐的版本,并且之后教程中用的都是 Action-based 的版本,它是基于 Input System,相比基于 XR Input Subsystem 的 Device-based,具有更高的灵活性,因为 Action-based 允许自由配置动作和按键的映射关系)

而 Turn Speed 就是持续转向时的速度,大家可以根据需求更改,感受一下。需要注意的是,如果要使用持续转向,就要把瞬间转向的脚本禁用掉。


📕持续移动

添加 Continuous Move Provider 脚本:

根据需求我把右手的 Action 给禁用了。这时候能通过转动左手柄的摇杆实现持续移动:

可以发现此时有个问题:人物直接从楼梯中间穿了过去。这是因为此时我们还没设置人物的碰撞。说起移动过程中玩家的碰撞,我们可以使用 Unity 自带的一个脚本:Character Controller

📕为移动添加碰撞效果

⭐添加 Character Controller

因为 XR Origin 这个游戏物体代表了 VR 中的玩家自己,所以我们要在这个物体上添加 Character Controller 组件,然后调整一下 Center Y 和 Radius 的值:

现在,人物和楼梯间就有了碰撞,上楼梯的功能也就实现了。

⭐添加 Character Controller Driver (仍有瑕疵)

但是这个时候其实还有一个问题,就是 Character Controller 的高度是固定的,不会随着头显的位置动态地调整高度和中心点,比如我想在现实中蹲下站立时,VR 中的人物碰撞体高度能进行动态地调整。好在 XR Interaction Toolkit 提供了一个脚本来解决这个问题:Character Controller Driver它能在运动事件(包含持续移动、传送、转向)发生后根据 XR Origin 的位置调整 Character Controller 的高度

我们在 Locomotion System 游戏物体上添加这个脚本。可能有人会有疑问:能在其他物体上添加这个脚本吗?比如把 Character Controller Driver 和 Character Controller 都挂载到 XR Origin 上。答案是可以的,只不过有一些注意点,稍后我会进行说明。

然后把 Continuous Move Provider 这个脚本(本教程中是 Locomotion System 这个物体)拖到 Locomotion Provider 这个变量上:

现在来回答之前的疑问。如果把 Character Controller Driver 这个脚本挂载到了其他物体上,那么我们就没法像上图展示的那样直接拖动脚本,而是只能把 Continuous Move Provider 这个脚本所属的游戏物体(本例中就是 Locomotion System 这个游戏物体)拖到 Locomotion Provider 上

需要注意的是:
Continuous Move Provider , Teleportation Provider, 还有负责转向的 Snap Turn Provider 或者 Continuous Turn Provider 都是 Locomotion Provider 的子类,如果像上图展示的 Locomotion System 一样,挂载了两个及以上的 Locomotion Provider 脚本,那么就需要把 Continuous Move Provider 这个脚本移动至所有 Locomotion Provider 的最上方,如图所示:

这样,当我们把挂有多个 Locomotion Provider 脚本的物体拖给 Character Controller Driver 脚本的 Locomotion Provider 变量后,Character Controller Driver 会将组件位置处于更上方的 Continuous Move Provider 作为 Locomotion Provider。

当然,如果游戏中只需要持续移动的功能,完全可以移除 Teleportation Provider 脚本,这取决于大家自己的项目需求。😊

总结来说,添加了 Character Controller Driver 这个脚本后,需要确保 Continuous Move Provider 这个脚本赋给了 Character Controller Driver 的 Locomotion Provider 变量。

现在,我们试着运行程序。但是会发现仍然存在一个问题:在利用摇杆进行持续移动的过程中, Character Controller 的高度和中心会被动态调整。但是,在不动摇杆的情况下,Character Controller 并不会随着现实中头显的高度变化而发生改变。比如我只在现实中做蹲起的动作,游戏中 Character Controller 的高度和中心不会变化。

我们可以看一下 Character Controller Driver 的源码,顺藤摸瓜分析下其中的原理。
首先找到 UpdateCharacterController 这个方法,这就是改变 Character Controller 高度的核心代码。大概就是根据相机位置和 Character Controller 的参数去调整高度和中心。

那么这个方法在什么地方被调用呢?我们可以查看这个方法在什么地方被引用:


具体有这么几个地方:

(1)获取属性时被调用(见下图),但是查看这个属性的引用时,发现它没有被引用的地方,所以至少在这个脚本里,这部分的代码不会被调用。因此这个属性的用处应该是在用户自定义的脚本里更新 Locomotion Provider。因为之前也有提到,Continuous Move Provider , Teleportation Provider, 还有负责转向的 Snap Turn Provider 或者 Continuous Turn Provider 都是 Locomotion Provider 的子类。我们目前是以 Contiunous Move Provider 作为 Locomotion Provider。之后可以通过这个属性进行 Locomotion Provider 的变更。

(2) Start 方法里被调用。这个也正常,初始化 Character Controller 的高度和中心。

(3)开始运动和结束运动时调用。

那么这两个方法又在什么地方被调用呢?我们继续查看引用,以 OnBeginLocomotion 为例:


可以看到这边是把更新 Character Controller 的方法绑定到开始运动的事件中,这个事件隶属于 LocomotionProvider。我们现在可以回看一下我之前写的 CharacterControllerDriver 脚本的作用:

能在运动事件(包含持续移动、传送、转向)发生后根据 XR Origin 的位置调整 Character Controller 的高度

所以更新 Character Controller 的方法除了初始化的时候被调用,大部分情况是只有运动事件发生时才会被调用的。但是,我们的需求是根据头显的高度实时更新 Character Controller 的高度和中心。所以,这个更新方法应该也要在 Unity 的 Update 方法里被调用。这里建议最好不要直接更改 XR Interaction Toolkit 的代码,为了有更好的拓展性,我们可以新建一个脚本去继承 CharacterControllerDriver,然后补充它的逻辑。

⭐自定义继承 Character Controller Driver 的脚本(最终方案)

代码如下:

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

public class CustomCharacterControllerDriver : CharacterControllerDriver
{
    void Update()
    {
        UpdateCharacterController();       
    }
}

直接在 Update 方法里调用 UpdateCharacterController 方法。然后我们移除原来的 CharacterControllerDriver 脚本,把这个新建的脚本加上,并且给 Locomotion Provider 赋值:

除此之外,大家可以根据自己的需求更改 Min Height 和 Max Height,它们分别代表 Character Controller 变化的最小高度和最大高度。在运行游戏的过程中,大家可以观察 Character Controller 的 Center 的数值,如果是动态更改的,那么就说明我们新建的脚本已经成功运行了。

那么到现在为止,我们的 Demo 就大功告成了,大家快去试试 VR 世界中的转向和持续移动吧!🌹

有关Unity VR开发教程 OpenXR+XR Interaction Toolkit (三) 转向和移动的更多相关文章

  1. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  2. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  3. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  4. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  5. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  6. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  7. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  8. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

随机推荐