全息影像防抖动 — MRTK2

性能

为使基础混合现实平台和设备带来最佳结果,实现高性能帧速率至关重要。 目标帧速率(例如 60 FPS 或 90 FPS)因平台和设备而异。 但是,符合帧速率要求的混合现实应用程序将具有稳定的全息影像以及高效的头部跟踪、手部跟踪等。

环境跟踪

稳定的全息渲染在很大程度上依赖于平台和设备的头部姿势跟踪。 Unity 将渲染由基础平台估计和提供的摄像头姿势捕捉的每一帧场景。 如果此跟踪不能正确地跟随实际的头部运动,全息影像在视觉上就会显得不准确。 这对于像 HoloLens 这样的 AR 设备来说尤其明显和重要,因为用户会将虚拟全息影像与现实世界联系起来。 性能对于可靠的头部追踪来说非常重要,但某些其他的重要功能也是如此。 影响用户体验的环境元素类型将取决于目标平台的具体功能。

Windows Mixed Reality

Windows Mixed Reality 平台提供了一些引用材料,用于在平台上稳定全息影像。 不过,开发人员可以利用一些重要工具来改善用户的全息影像视觉体验。

深度缓冲区共享

Unity 开发人员可以选择与平台共享应用程序的深度缓冲区。 这会提供全息影像在当前帧内所在位置的信息,平台可以利用这些信息,通过称为“后期阶段重新投影”的硬件辅助过程来稳定全息影像。

后期阶段重新投影

在某一帧渲染结束时,Windows Mixed Reality 平台会获取应用程序生成的颜色和深度渲染目标,并对最终的屏幕输出进行转换,以考虑到自上次头部姿势预测以来的任何微小的头部运动。 应用程序的游戏循环需要一段时间来执行。 例如,采用 60 FPS 速度时,意味着应用程序需要大约 16.667 毫秒来渲染一帧。 尽管这看起来是微乎其微的时间,但用户头部的位置和方向会发生变化,从而导致相机渲染新的投影矩阵。 后期阶段重新投影会对最终图像中的像素进行转换,以考虑到这一新的视角。

每像素与防抖动平面 LSR

根据在 Windows Mixed Reality 设备上运行的设备终结点和 OS 版本,后期阶段重新投影算法将按像素或通过防抖动平面来执行。

基于每像素深度

基于每像素深度的重新投影过程会利用深度缓冲区来修改每像素图像输出,从而稳定不同距离的全息影像。 例如,一个 1 米远的球体可能在 10 米远的立柱前面。 如果用户头部稍稍偏向一侧,则表示球体的像素将与远处表示立柱的像素具有不同的转换。 每像素重新投影将考虑到每个像素在距离上的差异,以便更准确地重新投影。

防抖动平面

如果无法创建准确的深度缓冲区来与平台共享,另一种形式的 LSR 会利用防抖动平面。 场景中的所有全息影像都将获得一定程度的稳定性,但位于所需平面中的全息影像将获得最大程度的硬件稳定性。 该平面的点和法线可以通过 Unity 提供HolographicSettings.SetFocusPointForFrame API 提供给平台。

深度缓冲区格式

如果面向 HoloLens 开发,强烈建议使用 16 位深度缓冲区格式,而不是 24 位。 尽管深度值的精度较低,但这也会极大地节省性能。 若要弥补较低的精度并避免 Z 竞争,建议降低远裁剪平面的值(Unity 设置的默认值为 1000 米)。

注意

如果使用 16 位深度格式,模具缓冲区所需效果将不起作用,因为在此设置中,Unity 不会创建模具缓冲区。 相反,选择 24 位深度格式通常会创建 8 位模具缓冲区(如果适用于终结点图形平台)

Unity 中的深度缓冲区共享

若要利用基于深度的 LSR,开发人员需要执行两个重要步骤。

  1. 在“编辑”>“项目设置”>“播放器”>“XR 设置”>“虚拟现实 SDK”下,启用“深度缓冲区共享”
    1. 如果是面向 HoloLens,建议同时选择“16 位深度格式”
  2. 在屏幕上渲染颜色时,同时渲染深度

Unity 中的不透明 GameObject 通常会自动写入深度。 但是,默认情况下,透明和文本对象通常不会写入到深度。 如果利用 MRTK 标准着色器或 Text Mesh Pro,可以轻松解决此问题。

注意

若要快速确定场景中不在视觉上写入深度缓冲区的对象,可以使用 MRTK 配置文件的“编辑器设置”下的“渲染深度缓冲区”实用工具

透明 MRTK 标准着色器

对于使用 MRTK 标准着色器的透明材料,请选择该材料以在“检查器”窗口中查看它。 然后单击“立即修复”按钮,将该材料转换为写入深度(例如“Z-Write On”)。

之前

Depth Buffer Before Fix MRTK Standard Shader

之后

Depth Buffer Fixed MRTK Standard Shader

Text Mesh Pro

对于 Text Mesh Pro 对象,请选择 TMP GameObject 以在检查器中查看它。 在材料组件下,将所分配材料的着色器切换为使用 MRTK TextMeshPro 着色器。

Text Mesh Pro Depth Buffer Fix

自定义着色器

如果编写自定义着色器,请将 ZWrite 标志添加到 Pass 块定义的顶部,以将着色器配置为写入深度缓冲区。

Shader "Custom/MyShader"
{
    SubShader
    {
        Pass
        {
            ...
            ZWrite On
            ...
        }
    }
}
不透明后备

如果以上方法不适用于给定场景(例如使用 Unity UI),可能需要将其他对象写入深度缓冲区。 常见示例是在场景中的浮动面板上使用 Unity UI 文本。 通过使面板不透明或至少写入到深度,平台将稳定文本和面板,因为它们之间的 Z 值非常接近。

WorldAnchor (HoloLens)

除了确保满足正确的配置以保证视觉稳定性外,还必须确保全息影像在正确的物理位置保持稳定。 为了让平台了解物理空间中的重要位置,开发人员可以对需要保持在某个位置的游戏对象利用 WorldAnchorWorldAnchor 是添加到 GameObject 的一个组件,可绝对控制对象的转换。

HoloLens 等设备会不断扫描和了解环境。 因此,当 HoloLens 跟踪空间中的运动和位置时,会更新其估计值并调整 Unity 坐标系统。 例如,如果某个 GameObject 在开始时放置在距离摄像头 1 米的位置,当 HoloLens 跟踪环境时,它可能意识到 GameObject 所在的物理点实际距离摄像头 1.1 米。 这可能导致全息影像发生偏移。 将 WorldAnchor 应用于 GameObject 将启用定位点来控制对象的转换,以便对象保持在正确的物理位置上(即更新到 1.1 米远,而不是运行时的 1 米)。 若要跨应用会话保持 WorldAnchor,开发人员可以使用 WorldAnchorStore保存和加载 WorldAnchor

注意

将 WorldAnchor 组件添加到 GameObject 后,无法修改 GameObject 的转换(即 transform.position = x)。 开发人员必须删除 WorldAnchor 以编辑转换。

WorldAnchor m_anchor;

public void AddAnchor()
{
    this.m_anchor = this.gameObject.AddComponent<WorldAnchor>();
}

public void RemoveAnchor()
{
    DestroyImmediate(m_anchor);
}

如果希望采用替代方法来手动使用定位点,请查看 Microsoft World Locking Tools。

另请参阅