社区链接:
Spatial XR 高级社区(知识星球)
Spatial XR 高级社区(爱发电)
这期教程我将会介绍如何在 Unity 中,分别利用 Meta XR SDK 中的 Scene API 和 Depth API,来实现现实物体遮挡位于后方的虚拟物体的效果。
配套的视频链接:
https://www.bilibili.com/video/BV1GH4y1h7Py
一体机开发环境配置可参考:https://blog.csdn.net/qq_46044366/article/details/133967343
配置一个基本的玩家物体可以参考前几期教程:https://blog.csdn.net/qq_46044366/article/details/134097455
MR 透视配置可参考:
https://blog.csdn.net/qq_46044366/article/details/135612769
Scene API 配置可参考:
https://blog.csdn.net/qq_46044366/article/details/135930423
系列教程专栏:https://blog.csdn.net/qq_46044366/category_12118293.html
电脑操作系统:Windows 11
使用的 VR 设备:Meta Quest 3(Quest 系列都适用,但是 Depth API 的部分目前只适用于 Quest 3)
使用的 Unity 版本:2022.3.15 f1c1 LTS
Meta XR SDK 版本:v60
Meta Quest 系统需要是 v40 及以上
官方文档:https://developer.oculus.com/documentation/unity/unity-gs-overview/
Depth API 官方文档:https://developer.oculus.com/documentation/unity/unity-depthapi/
Depth API 官方 Github 项目链接:https://github.com/oculus-samples/Unity-DepthAPI
最终效果:
在上一期配置 Scene API 实现虚拟与现实物体之间碰撞的教程中,我们可以在 Project 窗口的搜索栏中搜索 SelectivePassthrough,在 Packages 文件夹下找到这个材质。
然后我们自己创建了一个和这个官方透视材质一模一样的材质,这样后续可以对材质做一些自定义的设置。我们在 Assets 文件夹下的任意一个文件夹中创建了一个材质,叫做 CustomSelectivePassthrough,然后把 Shader 改成 Oculus/SelectivePassthrough。但是如果我们按照上一期教程的步骤把材质的 Render Queue 设为 5000,那么我们运行程序后,如果把一个虚拟小球放在具有透视材质的现实物体之后,我们还是可以看到墙之后的小球的。
如果想要让具有透视材质的现实物体遮挡虚拟小球,可以把透视材质的 Blend Color 由原来的 ReverseSubstract 改为 Substract 。此外,我在弹球 Demo 中给球加了个高亮材质,当手对准球的时候,显示球的高亮材质。如果我们想要看到球的高亮材质,还需要让透视材质的 Render Queue 小于球的高亮材质,且大于小球本身的材质。(如下图所示)
Render Queue 依据什么修改?首先 Render Queue 越大,材质越透明,并且在渲染顺序中越后渲染。
我们看高亮材质的 Render Queue,它是 3110:
如果透视材质的 Render Queue 按照上期教程设为了 5000,那么它比 3110 大,因此透视材质后渲染,并且这两个材质都是透明的材质。经过 Substract 混合一下会导致高亮材质看不到了,相当于透视材质盖住了高亮材质。
如果透视材质的 Render Queue 小于高亮材质,那么透视材质先渲染,高亮材质后渲染,这种情况下就能正常显示高亮材质。
总结一下,如果透视材质的 Blend Color 设为了 Substract,如果在场景中看不到某个其他的透明材质(比如球的高亮材质),可以让透视材质的 Render Queue 小于该透明材质,这样就能够看到该透明材质。
最终效果:
Scene API 实现的遮挡主要有两个缺点:
Depth API 是 Quest 3 特有的功能,因为 Quest 3 有一个深度传感器,能够获取现实物体与相机之间的深度信息,因此能够判断现实物体和虚拟物体到相机的距离,来处理现实物体和虚拟物体之间的前后遮挡关系。而像 Quest 2 和 Quest Pro 就没有深度传感器,因此无法使用 Depth API。
Depth API 主要解决的是动态遮挡的需求,比如现实的手放在虚拟的物体前能呈现出正确的前后遮挡关系。
使用 Depth API 目前有几个注意事项:
Depth API 官方文档说明:https://developer.oculus.com/documentation/unity/unity-depthapi/(相关要求和配置过程可能会发生改变,一切以官方文档为主)
目前导入 Depth API 需要从 Git URL 导入。我们可以打开 Depth API 官方 Github 样例项目网址:https://github.com/oculus-samples/Unity-DepthAPI
里面有两个 Git 链接,分别适用于不同的渲染管线。
普通渲染管线:https://github.com/oculus-samples/Unity-DepthAPI.git?path=/Packages/com.meta.xr.depthapi
URP 渲染管线:https://github.com/oculus-samples/Unity-DepthAPI.git?path=/Packages/com.meta.xr.depthapi.urp
根据自己的项目选择用哪一种,因为我的项目是默认的普通渲染管线,所以我先把第一个链接复制一下,然后如下图所示,打开 Unity 的 Window > Package Manager,点击界面左上角的 “+” 号,选择 Add package from git URL,将复制的 Git 链接导入。
导入之后可以在 Package Manager 当中的 In Project 里看到 Depth API,同时 Oculus XR Plugin 这个包的版本会转换为 4.2.0-exp-env-depth.2
打开 Unity 的 Edit > Project Settings > Oculus,点击安卓端和 PC 端的 Fix All 和 Apply All,直到列表的所有选项变绿为止。
这个自动修复工具确保了这几件事:
我们在 Project 窗口中搜索 EnvironmentDepthOcclusion,将搜索选项设为 All 或 In Package,可以找到这个预制体 Prefab:
然后把这个预制体拖到场景中,找到它身上的 Environment Depth Occusion Controller 脚本的 Occlusion Type 参数,可以把它改为 Soft Occlusion:
Hard Occlusion:对现实物理的遮挡效果会比较粗糙,但是节约性能
Soft Occlusion:对遮挡效果进行了平滑处理,但是需要更大的 GPU 性能。需要注意的是 Depth API 是在实时进行处理的,所以它本身会消耗更多的算力。
找到虚拟物体的材质,比如我这个小球的材质的 Shader 原本是 Standard,现在需要替换成 Meta/Depth/BiRP/Occlusion Standard:
替换成什么 Shader 可参考下方的表格(前缀是Meta/Depth/BiRP/)。
BiRP(普通渲染管线):
现在运行程序,就可以实现当现实中的物体遮挡住后方的虚拟物体时,能看到虚拟物体前的现实物体。
当我们用现实中的手抓取一个虚拟物体的时候,Depth API 会把虚拟物体的大部分表面遮挡掉,但是现实中的手本身是没有真正抓取一个物体的,就会导致手和虚拟物体穿模,出现很奇怪的视觉效果。我的优化思路是,当现实的手与虚拟物体进行交互时,显示虚拟手部模型,并且取消现实的手对虚拟物体的遮挡效果。如果给虚拟物体录制了抓取手势,因为 Synthetic Hand 对虚拟手部姿态的限制,所以在抓取物体的时候虚拟手部模型就会贴在虚拟物体的表面上,更有抓取的感觉。
Depth API 提供了一个方法,可以取消手腕以上手的部分对虚拟物体的遮挡效果。在 EnvironmentDepthTextureProvider 脚本中有一个 RemoveHands 方法可以实现这个功能。
和 Event Wrapper 搭配的样例:
最终效果: