Фовированное отображение
Foveated рендеринг является методом оптимизации, в котором области дисплея на периферии зрения пользователя отображаются с более низким разрешением. Foveated рендеринг может улучшить производительность отображения с небольшим влиянием на воспринимаемое качество изображения.
Фовеатное отображение получает свое название от фовеи, которая является небольшой частью глаза, содержащей наиболее плотную группу фоторецепторных нервов. Цель фовеатного отображения заключается в изменении разрешения отображения по экрану, так что только та часть, которая может быть воспринята фовеей, отображается с самым высоким разрешением.
XR платформы реализуют foveated отображения с различными методами, такими как Variable Rate Shading (VRSи растрирование с переменной скоростью (VRR). Используемый метод может изменить, как шейдеры должны семплировать текстуры, когда активное рендеринг. Чтобы ассеты работали на любой платформе, Unity предоставляет макросы шейдера, ключевые слова и символы предпроцессора, которые можно использовать для адаптации шейдеров, чтобы расчеты экранного пространства давали правильные результаты на всех платформах. Шейдеры рендеринга Foveated (Шейдеры предоставляются Unity и URP уже используют эти макросы.)
Устройства XR могут поддерживать рендеринг в одном из двух режимов:
- Фиксированное отображение с фокусом отображает центральную область дисплея для каждого глаза с самым высоким разрешением и снижает разрешение периферии.
- Фовированное отображение на основе зрения использует отслеживание глаз, чтобы определить, где расположена область экрана с самым высоким разрешением. Эта форма отображения может поддерживаться только на устройствах с отслеживанием глаз.
В настоящее время, платформы XR, которые используют VRS и унифицированный растр для рендеринга, включают OpenXR и Meta Quest. Платформы XR, которые используют VRR и неунифицированный растр для рендеринга, включают visionOS (при рендеринге с графикой Metal API).
Предварительные условия
Для использования рендеринга с помощью фовеатов ваш проект должен соответствовать следующим предварительным условиям:
- Unity 6+, 2022.3 или 2023.2.
- Universal Render Pipeline (URP).
- Параметры, настроенные в плагине поставщика XR, если это необходимо.
- На PC автономном XR, проект должен использовать Direct3D12 или Vulkan графики APIs.
- Для автономного PC XR компьютера, на котором запущено приложение, необходимо иметь недавно установленную GPU (например, Nvidia RTX2000+ или AMD RX6000+).
- На автономных платформах XR как плагин поставщика XR, так и устройство должны поддерживать отображение в формате foveated. (Дополнительные сведения см. в документации по плагину поставщика.)
Примечания:
- Некоторые плагины поставщика XR поддерживают foveated-рендеринг на 2022.3 и Built-in Render Pipeline с использованием другого API и реализации. См. документацию плагина для более подробной информации. Эти плагины включают OpenXR и Oculus.
- Фиксированное рендеринг совместим с динамическим разрешением с помощью
XRSettings.renderViewportScale. См. Управление разрешением в XR проектах для более подробной информации. - Unity не поддерживает рендеринг в проектах, использующих встроенный конвейер рендеринга.
Включить отображение с помощью фонов
Чтобы включить рендеринг с фокусом для проекта Unity, перейдите в раздел XR Plug-in Management вашего Project Настройки (меню: Изменить > Project Настройки). В разделе настроек каждого плагина, поддерживающего рендеринг с фокусом, появляется опция включения этой функции. Информацию о доступных настройках см. в документации плагина поставщика XR.
В дополнение к включению этой опции в настройках, вы также должны установить уровень отображения во время выполнения, как описано в Управление отображением во время выполнения.
Примечание: платформы и XR могут обеспечивать различные уровни контроля для рендеринга с фиксированным фокусом. Например, когда вы используете рендеринг Metal на visionOS, фиксированное рендеринг с фиксированным фокусом всегда в полной силе, когда включено.
Контроль фовеатированного отображения
Управляйте отображением с использованием фовеатов, установив свойство foveatedRenderingLevel свойства XRDisplaySubsystem на значение между нулем и одним. Вы должны включить фовеатное время выполнения в настройках плагина поставщика проекта, в противном случае настройка времени выполнения будет проигнорирована.
Следующий пример метода устанавливает уровень фовеации:
public void SetFRLevel(XRDisplaySubsystem xrDisplaySubsystem, float strength)
{
xrDisplaySubsystem.foveatedRenderingLevel = strength;
}
Если вы установите уровень отображения в нуле, то отображение отключается и не влияет на отображение.
На устройствах, поддерживающих отображение с отслеживанием движения глаз или на основе взгляда, вы можете включить эту функцию, установив свойство foveatedRenderingFlags свойства XRDisplaySubsystem:
// xrDisplaySubsystem is the active XRDisplaySystem instance
xrDisplaySubsystem.foveatedRenderingFlags = XRDisplaySubsystem.FoveatedRenderingFlags.GazeAllowed;
Вы можете включить отображение на основе взгляда, установив свойство foveatedRenderingFlags на поддерживающих его устройствах, даже если вы выбрали фиксированное отображение на основе взгляда во время выполнения.
Примечание: Получить XRDisplaySubsystem от SubsystemManager. Полная инициализация XRDisplaySubsystem может занять до трёх кадров. Прежде чем обращаться к свойствам и методам класса, следует подождать три кадра.
В следующем примере включено отображение с фокусировкой на 50% и установлены флаги отображения, чтобы разрешить отображение с фокусировкой на основе взгляда. В этом примере используется сопутствующая программа, которая ожидает три кадра, чтобы убедиться, что подсистема готова.
using UnityEngine;
using UnityEngine.Android;
using UnityEngine.XR;
using System.Collections.Generic;
using System.Collections;
public class FoveationStarter : MonoBehaviour
{
[Range(0, 1)]
public float foveationStrength = 0.5f;
public bool AllowGaze = false;
List<XRDisplaySubsystem> xrDisplays = new List<XRDisplaySubsystem>();
void Start()
{
StartCoroutine(WaitForXRDisplay());
if (AllowGaze)
{
// Request eye tracking permission for Quest devices
Permission.RequestUserPermission("com.oculus.permission.EYE_TRACKING");
}
}
IEnumerator WaitForXRDisplay()
{
yield return new WaitUntil(() => Time.frameCount >= 3);
SubsystemManager.GetSubsystems(xrDisplays);
if (xrDisplays.Count == 1)
{
xrDisplays[0].foveatedRenderingLevel = foveationStrength;
if(AllowGaze){
xrDisplays[0].foveatedRenderingFlags =
XRDisplaySubsystem.FoveatedRenderingFlags.GazeAllowed;
}
Debug.Log($"Foveated rendering set to {xrDisplays[0].foveatedRenderingLevel}.");
}
else
{
Debug.LogWarning($"Couldn't find an XRDisplaySubsystem for foveated rendering.");
}
}
}
На некоторых устройствах требуется запросить разрешение пользователя, прежде чем можно будет получить доступ к данным eye tracking. В примере показано, как запросить это разрешение для устройства Quest Pro на базе Android. Другие устройства и платформы XR используют другие строки разрешений, APIs или другие механизмы запроса разрешений.
Получить foveated возможности рендеринга
Вы можете получить информацию о возможностях отображения текущего устройства из свойства foveatedRenderingCaps объекта SystemInfo.
FoveatedRenderingCaps caps = SystemInfo.foveatedRenderingCaps;
Если свойство сообщает FoveatedRenderingCaps.None, то устройство не поддерживает отображение в режиме foveated. Отсутствие поддержки может быть вызвано различными причинами, включая программное обеспечение, время выполнения устройства или драйверы, поэтому даже если платформа поддерживает отображение в режиме foveated, оно может быть недоступно на конкретном устройстве.
Другие значения ,FoveatedRenderingCaps,, ,FoveationImage, и ,NonUniformRaster,предоставляют информацию о том, как устройство реализует рендеринг с использованием фов, и могут быть полезны при реализации пользовательского конвейера рендеринга. FoveationImage указывает, что реализация рендеринга с использованием фов использует VRS, а NonUniformRaster указывает, что она использует VRR..
Шейдеры рендеринга Foveated
Шейдеры, входящие в состав движка Unity, уже поддерживают как унифицированную, так и неунифицированную растровую расстановку для отображения с фиксированным фокусом. Если у вас есть пользовательские шейдеры, выполняющие расчеты экранного пространства, вам, возможно, придется обновить их для поддержки отображения с фиксированным фокусом на платформах, использующих неунифицированный растровый метод.
Пиксели, отображаемые с помощью неоднородного растра, больше не представляют регулярную сетку, так что вы должны изменить любые расчеты экранного пространства, которые предполагают регулярную сетку, чтобы они работали правильно с VRR. Unity предоставляет макросы шейдеров, ключевые слова и символы препроцессора, которые вы можете использовать для адаптации шейдеров, чтобы расчеты экранного пространства давали правильные результаты на всех платформах. (Шейдеры, предоставляемые Unity и URP уже используют эти макросы.)
Например, левая сторона следующего изображения показывает вид сцены, рендируемой с помощью VRR без корректировки на неоднородную растровую обработку. Правая сторона изображения показывает тот же вид, когда рендируется правильно:


Нескорректированная неоднородная растровая обработка (слева) по сравнению с линейной растровой обработкой (справа).
Обратите внимание, как сжаты области вблизи краев изображения слева. Это визуальное сжатие происходит потому, что периферийные области текстуры были растрированы с меньшей плотностью пикселей. При семплировании этой текстуры вам нужно будет использовать неоднородные координаты UV (или преобразовать линейные координаты UV в неоднородные с помощью одной из предоставленных функций рендеринга).
Примечание: Unity использует термин «неоднородный растр», чтобы описать пространство, в которое были растрированы пиксели при использовании техники VRR, и использует термин «линейный растр», чтобы относиться к более обычному пространству растрирования с регулярной сеткой.
Чтобы обновить ваши screen-space shaders для URP, чтобы получить правильные результаты при рендеринге в режиме foveated, добавьте следующие файлы включения (из пакета Core RP Library):
#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
Эти файлы содержат ключевые слова и макросы для рендеринга, а также функции для отображения координат экранного пространства от неоднородных до линейных и наоборот.
Как фовеатное отображение влияет на совместимость шейдеров
Методы затенения с переменной скоростью (VRS) изменяют количество экранных пикселей, затененных каждым вызовом к фрагменту шейдера, в зависимости от того, где регион находится в поле зрения пользователя. Затенение с переменной скоростью совместимо с существующими шейдерами. Вам не нужно менять пользовательские шейдеры, чтобы работать под foveated рендирование на XR платформы, которые используют VRS.
Метод растрирования с переменной скоростью (VRR) регулирует растрирование таким образом, что эффективное расстояние между соседними пикселами больше не является единообразным. Например, периферийная область поля зрения может быть отображена текстурой более низкого разрешения, которая затем растягивается при композитации до окончательного отображения. Поскольку растрирование не является единообразным, шейдеры, выполняющие расчеты в экранном пространстве, могут давать неправильные результаты под VRR, если они предполагают, что растрирование использует единообразную сетку. Вам может потребоваться изменить пользовательские шейдеры, чтобы работать под фовеированным отображением на XR платформах, которые используют VRR.
Когда использовать функции отображения
При выборке линейной текстуры следует использовать линейные координаты. И наоборот, при выборке неоднородной текстуры следует использовать неоднородные координаты.
Все вершинные атрибуты, передаваемые от вершинного шейдера к фрагментному (пиксельному) шейдеру, всегда находятся в линейном пространстве, за исключением SV_POSITION. Вы можете семплировать неоднородную текстуру с координатами SV_POSITION непосредственно, но если вы используете другие вершинные атрибуты для семплирования, вы должны использовать соответствующую функцию переотображения линейного на неоднородное. Аналогичным образом, если вы используете SV_POSITION для семплирования линейной текстуры, вы должны использовать функцию FoveatedRemapNonUniformToLinear.
Координатное пространство текстур варьируется в зависимости от того, как они созданы. Большинство текстур, созданных движком Unity, таких как буфер глубины и G-буферы, находятся в неоднородном пространстве при рендеринге с VRR. (Однако, есть исключения, которые в настоящее время не документированы.) Вручную созданные текстуры экранного пространства, такие как накладка 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
Узел Screen Position в Shader Graph предоставляет координаты, которые часто используются для выборки текстур, затронутых рендерингом с фокусом. Настройка Режим этого узла Shader Graph определяет форму, в которой предоставляются координаты. В большинстве режимов координатное пространство не является единообразным при рендеринге с VRR.. Напротив, Сырое режим во всех случаях линейный.
| - | UV координатное пространство | UV координатное пространство |
|---|---|---|
| Режим положения экрана | Затенение с переменной скоростью (VRS) и рендеринг без фона | Растеризация с переменной скоростью (VRR) |
| По умолчанию | линейный | неоднородные |
| Сырое | линейный | линейный |
| Центр | линейный | неоднородные |
| Плитка | линейный | неоднородные |
| Пиксель | линейный | неоднородные |
Если вы используете режим Сырое узла Screen Position для выборки неоднородной текстуры, то результаты будут неправильными.
Чтобы проиллюстрировать ситуацию, рассмотрим Shader Graph с узлом Screen Position, связанным с узлом Scene Depth, который, в свою очередь, связан с базовым цветом шейдера фрагмента.
Этот шейдер отображает цвета в соответствии со значениями глубины в буфере глубины сцены. Этот шейдер работает правильно при отображении с фокусом, потому что он использует узел По умолчанию режим Screen Position, который возвращает свои результаты в том же пространстве, что и буфер глубины (и большинство других текстур, созданных движком). Если вы изменили режим на Сырое, результаты больше не будут правильными при отображении с фокусом на платформе, которая использует растрирование с переменной скоростью.
В следующем примере, на левом изображении показан шейдер на кваде и использование правильного координатного пространства для семплирования буфера глубины сцены. Правое изображение показывает рендеринг foveated с использованием неправильного координатного пространства для семплированной текстуры — обратите внимание, как семплированная текстура больше не выстраивается с геометрией сцены:


Правильная (слева) и неправильная (справа) выборка.
Если ваш Shader Graph зависит от положения Raw экрана и не может использовать ни один из других режимов, вы можете использовать функции Shader для фовеатированного рендеринга внутри узла Custom Function для переотображения raw координат (которые должны быть нормализованы):
#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 маршрутизирует координаты Raw через два узла Custom Function:
Первая пользовательская функция нормализует необработанные координаты путем деления элементов x и y на элемент w (B = A.xy/A.ww). Вторая пользовательская функция использует FoveatedRemapLinearToNonUniform для отображения линейных координат в неоднородном пространстве, когда это необходимо. Напомним, что когда отображение с фокусом выключено или текущая платформа не использует VRR для отображения с фокусом, тогда FoveatedRemapLinearToNonUniform возвращает линейные координаты без изменений. Таким образом, шейдер правильно семплирует глубину сцены во всех ситуациях.