注视点渲染是一种优化技术,它以较低的分辨率渲染用户视野周边区域的显示区域。注视点渲染可以提高渲染性能,同时对感知到的视觉质量影响很小。
注视点渲染的名称来源于视网膜中央凹,视网膜中央凹是眼睛的一小部分,包含最密集的光感受器神经。注视点渲染的目标是改变屏幕上的渲染分辨率,以便只有中央凹可以感知的部分以最高分辨率渲染。
XR 平台使用各种技术实现注视点渲染,例如可变速率着色 (VRS) 和可变速率光栅化通过为几何体中的每个多边形或三角形计算像素来生成图像的过程。这是一种替代光线追踪的方法。
参见 词汇表 (VRR)。所用的技术可能会改变在注视点渲染处于活动状态时着色器必须采样纹理的方式。为了使资源能够在任何平台上工作,Unity 提供了着色器在 GPU 上运行的程序。 更多信息
参见 词汇表宏、关键字和预处理器符号,您可以使用这些符号调整着色器,以便屏幕空间计算在所有平台上产生正确的结果。有关如何使用它们的信息,请参阅 注视点渲染着色器。(Unity 和 URP 提供的着色器已经使用了这些宏。)
XR 设备可以通过以下两种模式之一支持注视点渲染
目前,使用VRS虚拟现实 更多信息
参见 词汇表和统一光栅进行注视点渲染的XR一个涵盖虚拟现实 (VR)、增强现实 (AR) 和混合现实 (MR) 应用程序的总称。支持这些形式的交互式应用程序的设备可以称为 XR 设备。 更多信息
参见 词汇表平台包括 OpenXR 和 Meta Quest。使用 VRR 和非统一光栅进行注视点渲染的 XR 平台包括 visionOS(使用 Metal 图形 API 进行渲染时)。
要使用注视点渲染,您的项目必须满足以下先决条件
注释
要为 Unity 项目启用注视点渲染,请转到项目设置(菜单:编辑 > 项目设置)的XR 插件管理部分。每个支持注视点渲染的插件的设置部分中都会显示一个启用该功能的选项。有关可用设置的信息,请参阅 XR 提供程序插件的文档。
除了在设置中启用该选项外,您还必须在运行时设置注视点渲染级别,如 控制注视点渲染 中所述。
注意:XR 平台可以为注视点渲染提供不同级别的控制。例如,当您在 visionOS 上使用 Metal 渲染时,启用固定注视点渲染时,它始终处于最大强度。
通过将 XRDisplaySubsystem 的 foveatedRenderingLevel 属性设置为 0 到 1 之间的值来控制注视点渲染。您必须在项目的提供程序插件设置中启用注视点运行时,否则运行时设置将被忽略。
以下示例方法设置注视点级别
public void SetFRLevel(XRDisplaySubsystem xrDisplaySubsystem, float strength)
{
xrDisplaySubsystem.foveatedRenderingLevel = strength;
}
如果将注视点渲染级别设置为零,则注视点功能将关闭,并且不会影响渲染。
在支持眼球追踪或基于注视点的注视点渲染的设备上,您可以通过设置 XRDisplaySubsystem 的 foveatedRenderingFlags 属性来启用此功能。
// 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 的其他值 FoveationImage 和 NonUniformRaster 提供了有关设备实现注视点渲染的方式的信息,如果您正在实现自定义渲染管线,这些信息可能会有用。FoveationImage
指示注视点渲染实现使用 VRS,而 NonUniformRaster
指示它使用 VRR。
Unity 引擎随附的着色器已经支持用于注视点渲染的统一和非统一光栅化。如果您有执行屏幕空间计算的自定义着色器,则可能需要更新它们以支持在使用非统一光栅技术的平台上进行注视点渲染。
使用非统一光栅渲染的像素计算机图像中最小的单位。像素大小取决于屏幕分辨率。像素照明在每个屏幕像素处计算。 更多信息
参见 词汇表不再表示规则网格,因此您必须更改任何假定规则网格的屏幕空间计算,以使它们能够与 VRR 正确配合使用。Unity 提供了着色器宏、关键字和预处理器符号,您可以使用这些符号调整着色器,以便屏幕空间计算在所有平台上产生正确的结果。(Unity 和 URP 提供的着色器已经使用了这些宏。)
例如,下图左侧显示了使用 VRR 渲染的场景场景包含游戏环境和菜单。可以将每个唯一的场景文件视为一个唯一的关卡。在每个场景中,您放置环境、障碍物和装饰,本质上是分段设计和构建游戏。 更多信息
参见 词汇表的视图,但没有校正非统一光栅化。图像右侧显示了正确渲染的相同视图
请注意,左侧图像边缘附近的区域是如何被压缩的。这种视觉压缩一种存储数据的方法,可以减少其所需的存储空间。请参阅 纹理压缩、动画压缩、音频压缩、构建压缩。
参见 词汇表发生是因为纹理的外围区域以较低的像素密度进行光栅化。在对该纹理进行采样时,您需要使用非统一 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 的平台上,有一个动态分支来检查着色器常量,即使禁用注视点渲染,也会增加少量开销。
声明:float2 FoveatedRemapLinearToNonUniform(float2 uv)
将线性屏幕空间 UV 坐标转换为非均匀坐标,包括任何必要的 y 轴反转。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的 UV 坐标。
声明:float2 FoveatedRemapNonUniformToLinear(float2 uv)
将非均匀屏幕空间 UV 坐标转换为线性坐标,包括任何必要的 y 轴反转。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的 UV 坐标。
声明:float2 FoveatedRemapPrevFrameLinearToNonUniform(float2 uv)
根据先前渲染的帧重新映射线性屏幕空间 UV 坐标。(在 Metal 上未实现。)
声明:float2 FoveatedRemapPrevFrameNonUniformToLinear(float2 uv)
根据先前渲染的帧重新映射非均匀屏幕空间 UV 坐标。(在 Metal 上未实现。)
声明:float2 FoveatedRemapDensity(float2 uv)
指定屏幕 UV 坐标处屏幕分辨率与光栅分辨率之间的比率。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回 (1.0, 1.0)。(在 Metal 上未实现。)
声明:float2 FoveatedRemapPrevFrameDensity(float2 uv)
上一帧时的密度比率。(在 Metal 上未实现。)
声明:float2 FoveatedRemapLinearToNonUniformCS(float2 positionCS)
将线性空间屏幕坐标转换为非均匀空间屏幕坐标。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的坐标。
声明:float2 FoveatedRemapNonUniformToLinearCS(float2 positionCS)
将非均匀空间屏幕坐标转换为线性空间屏幕坐标。如果注视点渲染未激活或平台未使用非均匀光栅化,则该函数将返回未更改的坐标。
要将线性屏幕空间中的 UV 坐标转换为非均匀光栅屏幕空间,请使用以下方法
uvNonUniform = FoveatedRemapLinearToNonUniform(uvLinear);
要将非均匀光栅屏幕空间中的 UV 坐标转换为线性屏幕空间,请使用以下方法
uvLinear = FoveatedRemapNonUniformToLinear(uvNonUniform);
要更新效果(例如高斯模糊),请使用以下方法
uvNonUniform = FoveatedRemapDensity(uvLinear);
Shader Graph 中的屏幕位置节点提供通常用于采样受注视点渲染影响的纹理的坐标。此 Shader Graph 节点的**模式**设置决定了提供坐标的形式。在大多数模式下,当使用 VRR 渲染时,坐标空间是非均匀的。相反,**原始**模式在所有情况下都是线性的。
屏幕位置模式 | UV 坐标空间 | |
---|---|---|
可变速率着色 (VRS) 和非注视点渲染 | 可变速率光栅化 (VRR) | |
默认 | 线性 | 非均匀 |
原始 | 线性 | 线性 |
中心 | 线性 | 非均匀 |
平铺 | 线性 | 非均匀 |
像素 | 线性 | 非均匀 |
如果您使用屏幕位置节点的**原始**模式采样非均匀纹理,则结果将不正确。
为了说明这种情况,请考虑一个 Shader Graph,其中屏幕位置节点连接到场景深度节点,该节点又连接到片段着色器的基本颜色。
此着色器根据场景深度缓冲区中的深度值渲染颜色。此着色器在注视点渲染下可以正常工作,因为它使用**默认**模式屏幕位置节点,该节点以与深度缓冲区(以及大多数其他引擎创建的纹理)相同的空间返回其结果。但是,如果您将模式更改为**原始**,则在注视点渲染在使用可变速率光栅化的平台上处于活动状态时,结果将不再正确。
正确与不匹配的采样 | |
---|---|
左图显示了四边形一个类似于平面的基本对象,但其边长仅为一个单位,它仅使用 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 将原始坐标通过两个自定义函数节点路由
第一个自定义函数通过将 x 和 y 元素除以 w 元素 (B = A.xy/A.ww
) 来归一化原始坐标。第二个自定义函数使用FoveatedRemapLinearToNonUniform
在需要时将线性坐标映射到非均匀空间。请记住,当注视点渲染关闭或当前平台不使用 VRR 进行注视点渲染时,FoveatedRemapLinearToNonUniform
将返回未更改的线性坐标。因此,着色器在所有情况下都正确地对场景深度进行采样。