Version: 6000.3
语言: 中文
单通道实例化渲染和自定义着色器
多视图渲染区域(Multiview Render Regions)

注视点渲染

注视点渲染是一种优化技术,其中用户视觉外围的显示器区域以较低的分辨率渲染。注视点渲染可以提高渲染性能,而对感知视觉质量的影响很小。

注视点渲染示例。着色区域显示以较低分辨率渲染以使用较少 GPU 资源的屏幕区域
注视点渲染示例。着色区域显示以较低分辨率渲染以使用较少 GPU 资源的屏幕区域

注视点渲染得名于中央凹,中央凹是眼睛的一小部分,包含最密集的感光神经群。注视点渲染的目标是改变整个屏幕上的渲染分辨率,以便仅以最高分辨率渲染中央凹可以感知的部分。

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

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

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

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

先决条件

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

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

笔记:

  • 某些XR提供程序插件支持2022.3上的注视点渲染,并使用不同的API和实现支持内置渲染管线。有关更多信息,请参阅插件文档。这些插件包括OpenXR和Oculus。
  • 固定注视点渲染兼容动态分辨率相机设置,允许您动态缩放单个呈现目标以减少 GPU 上的工作负载。更多信息
    请参阅术语表
    XRSettings.renderViewportScale. 有关详细信息,请参阅 XR 项目中的分辨率控制
  • 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 渲染,而不校正非均匀光栅化。正确渲染时,图像的右侧显示相同的视图:


未校正的非均匀光栅化(左)与线性光栅化(右)的比较。

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

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

要更新 URP 的屏幕空间着色器,以便在注视点渲染下生成正确的结果,请添加以下包含文件(来自核心 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 叠加层)通常是线性的,您应该使用线性 UV 坐标对其进行采样。

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

用于注视点渲染的着色器函数

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

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

注视点RemapLinearToNonUniform

声明:float2 FoveatedRemapLinearToNonUniform(float2 uv)

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

注视点重新映射非均匀到线性

声明:float2 FoveatedRemapNonUniformToLinear(float2 uv)

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

注视点RemapPrevFrame线性到非均匀

声明:float2 FoveatedRemapPrevFrameLinearToNonUniform(float2 uv)

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

注视点RemapPrevFrameNonUniformToLinear

声明:float2 FoveatedRemapPrevFrameNonUniformToLinear(float2 uv)

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

注视点重映射密度(FoveatedRemapDensity)

声明:float2 FoveatedRemapDensity(float2 uv)

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

注视点RemapPrevFrame密度

声明:float2 FoveatedRemapPrevFrameDensity(float2 uv)

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

注视点RemapLinearToNonUniformCS

声明:float2 FoveatedRemapLinearToNonUniformCS(float2 positionCS)

将线性空间屏幕坐标转换为非均匀空间屏幕坐标。如果注视点渲染未处于活动状态,或者平台未使用非均匀光栅化,则该函数将返回不变的坐标。

注视点重新映射NonUniformToLinearCS

声明:float2 FoveatedRemapNonUniformToLinearCS(float2 positionCS)

将非均匀空间屏幕坐标转换为线性空间屏幕坐标。如果注视点渲染未处于活动状态,或者平台未使用非均匀光栅化,则该函数将返回不变的坐标。

转换UV

要将线性屏幕空间中的 UV 坐标转换为非均匀栅格屏幕空间,请使用以下命令:

uvNonUniform = FoveatedRemapLinearToNonUniform(uvLinear);

要将非均匀栅格屏幕空间中的 UV 坐标转换为线性屏幕空间,请使用以下命令:

uvLinear = FoveatedRemapNonUniformToLinear(uvNonUniform);

更新效果

要更新效果(例如高斯模糊),请使用以下命令:

uvNonUniform = FoveatedRemapDensity(uvLinear);

更新着色器图表效果

着色器图表中的 屏幕位置(Screen Position) 节点提供的坐标通常用于对受注视点渲染影响的纹理进行采样。此着色器图表节点的 模式(Mode) 设置确定提供坐标的形式。在大多数模式下,使用 VRR 渲染时,坐标空间是不均匀的。相比之下,原始模式在所有情况下都是线性的。

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

如果你使用 Screen Position 节点的 Raw 模式对不均匀的纹理进行采样,则结果将不正确。

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

将屏幕位置节点连接到场景深度节点的着色器图表
将屏幕位置节点连接到场景深度节点的着色器图表

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

在以下示例中,左图显示了quad 类似于平面但其边只有一个单位长的图元对象,它只使用 4 个顶点,并且表面定向在局部坐标空间的 XY 平面上。更多信息
请参阅术语表
使用正确的坐标空间对场景深度缓冲区进行采样。右图显示了对采样纹理使用错误坐标空间的注视点渲染 - 请注意采样纹理如何不再与场景几何体对齐:


正确(左)与不匹配(右)抽样。

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

#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);
}

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

例如,以下着色器图表通过两个自定义函数节点路由原始坐标:

着色器图表,使用自定义函数节点转换原始UV坐标
着色器图表,使用自定义函数节点转换原始UV坐标

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

单通道实例化渲染和自定义着色器
多视图渲染区域(Multiview Render Regions)