版本:Unity 6 (6000.0)
语言:English
单通道实例化渲染和自定义着色器
VR 帧时序

注视点渲染

注视点渲染是一种优化技术,它以较低的分辨率渲染用户视野周边区域的显示区域。注视点渲染可以提高渲染性能,同时对感知到的视觉质量影响很小。

Example of foveated rendering. The tinted area shows the regions of the screen that are rendered at lower resolution to use fewer GPU resources
注视点渲染示例。着色区域显示以较低分辨率渲染的屏幕区域,以减少 GPU 资源的使用

注视点渲染的名称来源于视网膜中央凹,视网膜中央凹是眼睛的一小部分,包含最密集的光感受器神经。注视点渲染的目标是改变屏幕上的渲染分辨率,以便只有中央凹可以感知的部分以最高分辨率渲染。

XR 平台使用各种技术实现注视点渲染,例如可变速率着色 (VRS) 和可变速率光栅化通过为几何体中的每个多边形或三角形计算像素来生成图像的过程。这是一种替代光线追踪的方法。
参见 词汇表
(VRR)。所用的技术可能会改变在注视点渲染处于活动状态时着色器必须采样纹理的方式。为了使资源能够在任何平台上工作,Unity 提供了着色器在 GPU 上运行的程序。 更多信息
参见 词汇表
宏、关键字和预处理器符号,您可以使用这些符号调整着色器,以便屏幕空间计算在所有平台上产生正确的结果。有关如何使用它们的信息,请参阅 注视点渲染着色器。(Unity 和 URP 提供的着色器已经使用了这些宏。)

XR 设备可以通过以下两种模式之一支持注视点渲染

  • 固定注视点渲染以最高分辨率渲染每只眼睛的显示器的中心区域,并降低外围区域的分辨率。
  • 基于注视点的注视点渲染使用眼球追踪来确定屏幕上最高分辨率区域的位置。这种形式的注视点渲染只能在具有眼球追踪功能的设备上支持。

目前,使用VRS虚拟现实 更多信息
参见 词汇表
和统一光栅进行注视点渲染的XR一个涵盖虚拟现实 (VR)、增强现实 (AR) 和混合现实 (MR) 应用程序的总称。支持这些形式的交互式应用程序的设备可以称为 XR 设备。 更多信息
参见 词汇表
平台包括 OpenXRMeta Quest。使用 VRR 和非统一光栅进行注视点渲染的 XR 平台包括 visionOS(使用 Metal 图形 API 进行渲染时)。

先决条件

要使用注视点渲染,您的项目必须满足以下先决条件

  • Unity 6+、2022.3 或 2023.2。
  • 通用渲染管线一系列操作,用于获取场景的内容并在屏幕上显示它们。Unity 允许您从预构建的渲染管线中进行选择,或编写您自己的渲染管线。 更多信息
    参见 词汇表
    (URP)。
  • 在 XR 提供程序插件在 Unity 之外创建的一组代码,用于在 Unity 中创建功能。在 Unity 中可以使用两种类型的插件:托管插件(使用 Visual Studio 等工具创建的托管 .NET 程序集)和原生插件(平台特定的原生代码库)。 更多信息
    参见 词汇表
    中配置的设置(如有必要)。
  • 在 PC 独立 XR 上,项目必须使用 Direct3D12 或 Vulkan 图形 API。
  • 在 PC 独立 XR 上,运行应用程序的计算机必须具有最新的 GPU(例如 Nvidia RTX2000+ 或 AMD RX6000+)。
  • 在独立 XR 平台上,XR 提供程序插件和设备都必须支持注视点渲染。(有关更多信息,请参阅您的提供程序插件文档。)

注释

  • 一些 XR 提供程序插件支持在 2022.3 和内置渲染管线中使用不同的 API 和实现进行注视点渲染。有关更多信息,请参阅插件文档。这些插件包括 OpenXR 和 Oculus。
  • 注视点渲染与动态分辨率一种摄像机设置,允许您动态缩放各个渲染目标以减少 GPU 的工作负载。 更多信息
    参见 词汇表
    不兼容。
  • Unity 不支持在使用内置渲染管线的项目中进行注视点渲染。

启用注视点渲染

要为 Unity 项目启用注视点渲染,请转到项目设置(菜单:编辑 > 项目设置)的XR 插件管理部分。每个支持注视点渲染的插件的设置部分中都会显示一个启用该功能的选项。有关可用设置的信息,请参阅 XR 提供程序插件的文档。

除了在设置中启用该选项外,您还必须在运行时设置注视点渲染级别,如 控制注视点渲染 中所述。

注意:XR 平台可以为注视点渲染提供不同级别的控制。例如,当您在 visionOS 上使用 Metal 渲染时,启用固定注视点渲染时,它始终处于最大强度。

控制注视点渲染

通过将 XRDisplaySubsystemfoveatedRenderingLevel 属性设置为 0 到 1 之间的值来控制注视点渲染。您必须在项目的提供程序插件设置中启用注视点运行时,否则运行时设置将被忽略。

以下示例方法设置注视点级别

public void SetFRLevel(XRDisplaySubsystem xrDisplaySubsystem, float strength)
{
    xrDisplaySubsystem.foveatedRenderingLevel = strength;
}

如果将注视点渲染级别设置为零,则注视点功能将关闭,并且不会影响渲染。

在支持眼球追踪或基于注视点的注视点渲染的设备上,您可以通过设置 XRDisplaySubsystemfoveatedRenderingFlags 属性来启用此功能。

// xrDisplaySubsystem is the active XRDisplaySystem instance
xrDisplaySubsystem.foveatedRenderingFlags = XRDisplaySubsystem.FoveatedRenderingFlags.GazeAllowed;

您可以在支持的设备上通过设置 foveatedRenderingFlags 属性来启用基于注视点的注视点渲染,即使您在运行时选择了固定注视点渲染。

注意:SubsystemManager 获取 XRDisplaySubsystem

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

public class FoveationControl : MonoBehaviour
{
    XRDisplaySubsystem xrDisplaySubsystem;
    public float strength = 1.0f;
    
    void Start()
    {
        // Find the XR display subsystem
        var xrDisplaySubsystems = new List<XRDisplaySubsystem>();
        SubsystemManager.GetSubsystems<XRDisplaySubsystem>(xrDisplaySubsystems);
    
        if (xrDisplaySubsystems.Count < 1)
        {
            Debug.LogError("No XR display subsystems found.");
            return;
        }
        foreach(var subsystem in xrDisplaySubsystems)
        {
            if (subsystem.running)
            {
                xrDisplaySubsystem = subsystem;
                break;
            }
        }
        xrDisplaySubsystem.foveatedRenderingFlags = XRDisplaySubsystem.FoveatedRenderingFlags.GazeAllowed;
        SetFRLevel();
    }
    
    public void SetFRLevel()
    {
        xrDisplaySubsystem.foveatedRenderingLevel = strength;
    }
}

获取注视点渲染功能

您可以从 SystemInfo 对象的 foveatedRenderingCaps 属性获取当前设备的注视点渲染功能。

FoveatedRenderingCaps caps = SystemInfo.foveatedRenderingCaps;

如果该属性报告 FoveatedRenderingCaps.None,则表示设备不支持注视点渲染。缺乏支持可能是由各种原因造成的,包括软件、设备运行时或驱动程序,因此即使平台支持注视点渲染,它也可能在特定设备上不可用。

FoveatedRenderingCaps 的其他值 FoveationImageNonUniformRaster 提供了有关设备实现注视点渲染的方式的信息,如果您正在实现自定义渲染管线,这些信息可能会有用。FoveationImage 指示注视点渲染实现使用 VRS,而 NonUniformRaster 指示它使用 VRR。

注视点渲染着色器

Unity 引擎随附的着色器已经支持用于注视点渲染的统一和非统一光栅化。如果您有执行屏幕空间计算的自定义着色器,则可能需要更新它们以支持在使用非统一光栅技术的平台上进行注视点渲染。

使用非统一光栅渲染的像素计算机图像中最小的单位。像素大小取决于屏幕分辨率。像素照明在每个屏幕像素处计算。 更多信息
参见 词汇表
不再表示规则网格,因此您必须更改任何假定规则网格的屏幕空间计算,以使它们能够与 VRR 正确配合使用。Unity 提供了着色器宏、关键字和预处理器符号,您可以使用这些符号调整着色器,以便屏幕空间计算在所有平台上产生正确的结果。(Unity 和 URP 提供的着色器已经使用了这些宏。)

例如,下图左侧显示了使用 VRR 渲染的场景场景包含游戏环境和菜单。可以将每个唯一的场景文件视为一个唯一的关卡。在每个场景中,您放置环境、障碍物和装饰,本质上是分段设计和构建游戏。 更多信息
参见 词汇表
的视图,但没有校正非统一光栅化。图像右侧显示了正确渲染的相同视图

Uncorrected non-uniform rasterization (left) compared to linear rasterization (right)
未校正的非统一光栅化(左)与线性光栅化(右)的比较

请注意,左侧图像边缘附近的区域是如何被压缩的。这种视觉压缩一种存储数据的方法,可以减少其所需的存储空间。请参阅 纹理压缩动画压缩音频压缩构建压缩
参见 词汇表
发生是因为纹理的外围区域以较低的像素密度进行光栅化。在对该纹理进行采样时,您需要使用非统一 UV 坐标(或使用提供的注视点渲染着色器函数之一将线性 UV 坐标转换为非统一坐标)。

注意:Unity 使用术语“非统一光栅”来描述使用 VRR 技术时像素已被光栅化到的空间,并使用术语“线性光栅”来指代具有规则网格的更常见的光栅化空间。

要更新 URP 的屏幕空间着色器以在注视点渲染下产生正确的结果,请添加以下包含文件(来自 Core RP 库 包)

#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"

这些文件包含注视点渲染的关键字和宏,以及将屏幕空间坐标从非统一映射到线性以及反向映射的函数。

注视点渲染如何影响着色器兼容性

可变速率着色 (VRS) 技术根据区域在用户视野中的位置更改对片段着色器每次调用着色的屏幕像素数量。可变速率着色与现有着色器兼容。您无需更改自定义着色器即可在使用 VRS 的 XR 平台上进行注视点渲染。

可变速率光栅化 (VRR) 技术调整光栅化,使得相邻像素之间的有效距离不再均匀。例如,视场的外围区域可能会渲染到较低分辨率的纹理,然后在合成到最终显示器时进行拉伸。由于光栅化是非均匀的,因此在屏幕空间中执行计算的着色器在 VRR 下可能会产生错误的结果,如果它们假设光栅化使用统一网格。您可能需要更改自定义着色器才能在使用 VRR 的 XR 平台上的注视点渲染下工作。

何时使用注视点渲染函数

当您采样线性纹理时,应使用线性坐标。相反,当您采样非均匀纹理时,应使用非均匀坐标。

顶点着色器在渲染模型时,在 3D 模型的每个顶点上运行的程序。 更多信息
参见术语表
传递到片段(像素)着色器的所有顶点属性始终位于线性空间中,SV_POSITION除外。您可以直接使用SV_POSITION坐标采样非均匀纹理,但如果您使用其他顶点属性进行采样,则必须使用相应的线性到非均匀重新映射函数。类似地,如果您使用SV_POSITION采样线性纹理,则必须使用FoveatedRemapNonUniformToLinear函数。

纹理的坐标空间根据其创建方式而有所不同。Unity 引擎创建的大多数纹理,例如深度缓冲区一个存储器存储,用于保存图像中每个像素的 z 值深度,其中 z 值是每个渲染像素从投影平面的深度。 更多信息
参见术语表
和 G 缓冲区,在使用 VRR 渲染时位于非均匀空间中。(但是,存在例外情况,目前没有记录。)手动创建的屏幕空间纹理,例如艺术家绘制的UI(用户界面) 允许用户与您的应用程序交互。Unity 目前支持三种 UI 系统。 更多信息
参见术语表
叠加层通常是线性的,您应该使用线性 UV 坐标对其进行采样。

在计算着色器中,您必须考虑源纹理和目标纹理是否位于线性空间或非均匀空间中,并在采样或写入它们之前根据需要重新映射坐标。同样,请考虑 UV 坐标的来源、它们如何在计算着色器中计算以及传递给它们的任何函数是否期望线性或非均匀坐标。请参阅计算着色器主题和ComputeShader API,以获取有关 Unity 中计算着色器的常规信息。

注视点渲染的着色器函数

FoveatedRendering.hlsl 定义了一组函数,您可以使用这些函数在自定义着色器中支持注视点渲染。这些函数无论当前注视点渲染类型是线性还是非均匀,以及何时未使用注视点渲染,都会返回正确的结果。这些函数还会根据平台是否将屏幕空间原点放置在屏幕的顶部或底部来处理 y 轴的反转。

注意:这些函数对不使用非均匀注视点渲染 (VRR) 的平台没有性能影响。您不需要使用条件#ifdef语句来排除它们。但是,在确实使用 VRR 的平台上,有一个动态分支来检查着色器常量,即使禁用注视点渲染,也会增加少量开销。

FoveatedRemapLinearToNonUniform

声明:float2 FoveatedRemapLinearToNonUniform(float2 uv)

将线性屏幕空间 UV 坐标转换为非均匀坐标,包括任何必要的 y 轴反转。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的 UV 坐标。

FoveatedRemapNonUniformToLinear

声明:float2 FoveatedRemapNonUniformToLinear(float2 uv)

将非均匀屏幕空间 UV 坐标转换为线性坐标,包括任何必要的 y 轴反转。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的 UV 坐标。

FoveatedRemapPrevFrameLinearToNonUniform

声明:float2 FoveatedRemapPrevFrameLinearToNonUniform(float2 uv)

根据先前渲染的帧重新映射线性屏幕空间 UV 坐标。(在 Metal 上未实现。)

FoveatedRemapPrevFrameNonUniformToLinear

声明:float2 FoveatedRemapPrevFrameNonUniformToLinear(float2 uv)

根据先前渲染的帧重新映射非均匀屏幕空间 UV 坐标。(在 Metal 上未实现。)

FoveatedRemapDensity

声明:float2 FoveatedRemapDensity(float2 uv)

指定屏幕 UV 坐标处屏幕分辨率与光栅分辨率之间的比率。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回 (1.0, 1.0)。(在 Metal 上未实现。)

FoveatedRemapPrevFrameDensity

声明:float2 FoveatedRemapPrevFrameDensity(float2 uv)

上一帧时的密度比率。(在 Metal 上未实现。)

FoveatedRemapLinearToNonUniformCS

声明:float2 FoveatedRemapLinearToNonUniformCS(float2 positionCS)

将线性空间屏幕坐标转换为非均匀空间屏幕坐标。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的坐标。

FoveatedRemapNonUniformToLinearCS

声明:float2 FoveatedRemapNonUniformToLinearCS(float2 positionCS)

将非均匀空间屏幕坐标转换为线性空间屏幕坐标。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的坐标。

转换 UV

要将线性屏幕空间中的 UV 坐标转换为非均匀光栅屏幕空间,请使用以下方法

uvNonUniform = FoveatedRemapLinearToNonUniform(uvLinear);

要将非均匀光栅屏幕空间中的 UV 坐标转换为线性屏幕空间,请使用以下方法

uvLinear = FoveatedRemapNonUniformToLinear(uvNonUniform);

更新效果

要更新效果(例如高斯模糊),请使用以下方法

uvNonUniform = FoveatedRemapDensity(uvLinear);

更新 Shader Graph 效果

Shader Graph 中的屏幕位置节点提供通常用于采样受注视点渲染影响的纹理的坐标。此 Shader Graph 节点的**模式**设置决定了提供坐标的形式。在大多数模式下,当使用 VRR 渲染时,坐标空间是非均匀的。相反,**原始**模式在所有情况下都是线性的。

屏幕位置模式 UV 坐标空间
可变速率着色 (VRS) 和非注视点渲染 可变速率光栅化 (VRR)
默认 线性 非均匀
原始 线性 线性
中心 线性 非均匀
平铺 线性 非均匀
像素 线性 非均匀

如果您使用屏幕位置节点的**原始**模式采样非均匀纹理,则结果将不正确。

为了说明这种情况,请考虑一个 Shader Graph,其中屏幕位置节点连接到场景深度节点,该节点又连接到片段着色器的基本颜色。

Shader Graph with a Screen Position node connected to a Scene Depth node
将屏幕位置节点连接到场景深度节点的 Shader Graph

此着色器根据场景深度缓冲区中的深度值渲染颜色。此着色器在注视点渲染下可以正常工作,因为它使用**默认**模式屏幕位置节点,该节点以与深度缓冲区(以及大多数其他引擎创建的纹理)相同的空间返回其结果。但是,如果您将模式更改为**原始**,则在注视点渲染在使用可变速率光栅化的平台上处于活动状态时,结果将不再正确。

正确与不匹配的采样
Correct coordinate space Mismatched coordinate space
左图显示了四边形一个类似于平面的基本对象,但其边长仅为一个单位,它仅使用 4 个顶点,并且表面位于局部坐标空间的 XY 平面上。 更多信息
参见术语表
上的着色器,并使用正确的坐标空间对场景深度缓冲区进行采样。
右图显示了使用错误的采样纹理坐标空间的注视点渲染 - 请注意采样纹理如何不再与场景几何体对齐。

如果您的 Shader Graph 依赖于原始屏幕位置并且无法使用任何其他模式,则可以在自定义函数节点内使用注视点渲染的着色器函数来重新映射原始坐标(必须进行归一化)

#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"

// The Raw mode screenPosition must first be normalized: position.xy/position.ww
void CorrectedScreenPosition_float(float4 screenPosition, out float2 correctedScreenPosition)
{
    correctedScreenPosition = FoveatedRemapLinearToNonUniform(screenPosition);
}

注意:在这种情况下,您必须创建自定义函数节点以引用文件,因为如果您使用字符串类型,则#include语句将位于函数体内部,并导致语法错误。

例如,以下 Shader Graph 将原始坐标通过两个自定义函数节点路由

Shader Graph that converts the Raw UV coordinates with Custom Function nodes
使用自定义函数节点转换原始 UV 坐标的 Shader Graph

第一个自定义函数通过将 x 和 y 元素除以 w 元素 (B = A.xy/A.ww) 来归一化原始坐标。第二个自定义函数使用FoveatedRemapLinearToNonUniform在需要时将线性坐标映射到非均匀空间。请记住,当注视点渲染关闭或当前平台不使用 VRR 进行注视点渲染时,FoveatedRemapLinearToNonUniform将返回未更改的线性坐标。因此,着色器在所有情况下都正确地对场景深度进行采样。

单通道实例化渲染和自定义着色器
VR 帧时序