Разработка
Разработка
Выберите платформу

Расширенные настройки рендеринга

По умолчанию SDK генерирует значения настройки для оптимизации качества рендеринга.
Он также предоставляет определенную степень гибкости. Например, вы можете изменить параметры текстур при однобуферной прорисовке.
В этом разделе описаны изменения, которые можно сделать, выбирая между качеством рендеринга и производительностью, или если используемый вами движок накладывает ограничения.

Решение проблем с модульностью однобуферной прорисовки в графическом API и аппаратном обеспечении

SDK разработан исходя из предположения, что вы хотите максимально эффективно использовать видеопамять и можете точно настроить размер однобуферной прорисовки в соответствии с необходимостью.
Однако реальные видеокарты и графические API имеют ограничения по размеру (у всех есть максимальный, а у некоторых также минимальный размер). Также могут существовать ограничения по модульности, например возможность создания только однобуферных прорисовок, размеры которых кратны 32 пикселям, или ограничения на возможные соотношения сторон. Разработчики могут задавать дополнительные ограничения для минимизации использования графической памяти.
Кроме того, размер поверхности однобуферной прорисовки в памяти не всегда совпадает с размером области, на которую выполняется отрисовка. Размер последней может быть немного меньше. Поскольку он задается как поле видимости, обычно для него не предусмотрено ограничений по модульности. При привязке однобуферной прорисовки в качестве текстуры используется вся поверхность, поэтому UV-координаты нужно корректировать с учетом разницы между размерами области рендеринга и самой поверхности. API сделает это, но вам нужно сообщить ему необходимые данные.
В следующем коде показан двухэтапный метод настройки разрешения однобуферной прорисовки. На первом этапе код вызывает функцию ovr_GetFovTextureSize, чтобы рассчитать оптимальный размер однобуферной прорисовки. На следующем шаге вызывается графическая библиотека для создания целевой однобуферной прорисовки с нужным разрешением. Из-за особенностей платформы и оборудования, размер получаемой текстуры может отличаться от запрашиваемого.
// Get recommended left and right eye render target sizes.
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left,
                              session->DefaultEyeFov[0], pixelsPerDisplayPixel);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right,
                              session->DefaultEyeFov[1], pixelsPerDisplayPixel);

// Determine dimensions to fit into a single render target.
Sizei renderTargetSize;
renderTargetSize.w = recommenedTex0Size.w + recommenedTex1Size.w;
renderTargetSize.h = max ( recommenedTex0Size.h, recommenedTex1Size.h );

// Create texture.
pRendertargetTexture = pRender->CreateTexture(renderTargetSize.w, renderTargetSize.h);

// The actual RT size may be different due to HW limits.
renderTargetSize.w = pRendertargetTexture->GetWidth();
renderTargetSize.h = pRendertargetTexture->GetHeight();

// Initialize eye rendering information.
// The viewport sizes are re-computed in case RenderTargetSize changed due to HW limitations.
ovrFovPort eyeFov[2] = { session->DefaultEyeFov[0], session->DefaultEyeFov[1] };

EyeRenderViewport[0].Pos  = Vector2i(0,0);
EyeRenderViewport[0].Size = Sizei(renderTargetSize.w / 2, renderTargetSize.h);
EyeRenderViewport[1].Pos  = Vector2i((renderTargetSize.w + 1) / 2, 0);
EyeRenderViewport[1].Size = EyeRenderViewport[0].Size;
Эти данные передаются в ovr_EndFrame в составе описания слоя.
Вы можете задать размер текстуры однобуферной прорисовки и параметры полей видимости для левого и правого глаза на свое усмотрение, если укажете эти значения при вызове ovr_EndFrame с использованием ovrTexture. Однако использование ovr_GetFovTextureSize гарантирует, выделение оптимального размера для конкретной используемой гарнитуры. В следующих разделах описано, как изменить конфигурации по умолчанию для достижения баланса между качеством и производительностью. Обратите внимание: API поддерживает использование отдельных однобуферных прорисовок для левого и правого глаза, если ваш движок требует этого, однако единая однобуферная прорисовка обычно работает быстрее, так как уменьшается количество переключений контекста. В OculusWorldDemo можно включить или отключить общую однобуферную прорисовку в меню настроек (нажмите Tab). Для этого выберите значение параметра Share RenderTarget (Общая однобуферная прорисовка).

Принудительное использование симметричного поля зрения

Обычно API возвращает несимметричные поля зрения для каждого глаза, то есть левый и правый края находятся на разном расстоянии от центра.
Это связано с тем, что как у людей, так и у Rift поле зрения при взгляде наружу оказывается шире. Когда вы смотрите внутрь, обзору мешает нос. Нам проще смотреть вниз, чем вверх. По схожим причинам обзор в Rift не симметричен. Это регулируется формой линзы, элементами из пластика и краями экрана. Точные детали зависят от формы вашего лица, межзрачкового расстояния и того, как именно вы надеваете Rift на лицо. Всё это настраивается в инструменте конфигурации и сохраняется в профиле пользователя. В результате почти никогда все четыре края угла обзора не видны под одинаковым углом, поэтому результирующий усеченный конус будет смещен от центра. Кроме того, у большинства людей поля зрения для обоих глаз будут различаться. Они будут близки, но редко идентичны.
В коде и документации они называются "половинными углами", поскольку традиционно поле зрения выражается как полный угол от края до края. В этом примере общий горизонтальный угол обзора составляет 50,3 + 58,7 = 109,0 градусов, а общий вертикальный угол обзора — 53,6 + 58,9 = 112,5 градусов.
Рекомендуемые и максимальные поля зрения можно получить из гарнитуры, как показано ниже:
ovrFovPort defaultLeftFOV = session->DefaultEyeFov[ovrEye_Left];

ovrFovPort maxLeftFOV = session->MaxEyeFov[ovrEye_Left];
DefaultEyeFov относится к рекомендуемым значениям поля зрения, основанные на текущих настройках профиля пользователя (межзрачковое расстояние, расстояние между глазами и т. д.).MaxEyeFov относится к максимальному полю зрения, которое может отобразить гарнитура, вне зависимости от настроек профиля.
Значения по умолчанию обеспечивают хороший пользовательский опыт без излишней нагрузки на ГП. Если ваше приложение не потребляет значительных ресурсов ГП, вы можете использовать максимальные настройки угла обзора, чтобы снизить зависимость от точности настроек профиля. Вы можете добавить в панель управления приложением ползунок, который позволит пользователям выбирать интерполяцию настроек поля зрения между значением по умолчанию и максимальным. Однако если приложение сильно нагружает ГП, вы можете уменьшить поле зрения, выбрав значения меньше значений по умолчанию, как описано в разделе Повышение производительности за счет уменьшения поля зрения.
Углы обзора поля зрения вверх, вниз, влево и вправо (выраженные как тангенсы полууглов) — наиболее удобная форма для настройки отсечения или границ порталов в графическом движке. Значения поля зрения также используются для определения матрицы проекции, применяемой при рендеринге сцены для левого и правого глаза. Для этого мы предоставляем вспомогательную функцию API ovrMatrix4f_Projection.
ovrFovPort fov;

// Determine fov.
...

ovrMatrix4f projMatrix = ovrMatrix4f_Projection(fov, znear, zfar, 0);
Обычно верхние и нижние границы поля зрения не совпадают с левыми и правыми границами при просмотре на мониторе ПК. Это часто называется соотношением сторон дисплея, и очень немногие дисплеи имеют квадратную форму. Однако некоторые графические движки не поддерживают смещенные усеченные конусы. Чтобы обеспечить совместимость с этими движками, вам нужно изменить значения поля зрение, указанные в структуре ovrHmdDesc. В общем случае лучше расширять границы, чем сужать их. Это создаст немного большую нагрузку на графический движок, но обеспечит пользователю полный эффект погружения, даже если некоторые из отрисованных пикселей не будут видны.
Для некоторых графических движков нужно указывать симметричные по горизонтали и вертикали поля зрения, а другие используют менее прямой метод, например горизонтальный угол обзора и соотношение сторон. Некоторые также не принимают частые изменения угла обзора и могут настаивать на том, чтобы для обоих глаз был установлен одинаковый угол. Вот пример кода для обработки этого граничного случая:
ovrFovPort fovLeft = session->DefaultEyeFov[ovrEye_Left];
ovrFovPort fovRight = session->DefaultEyeFov[ovrEye_Right];

ovrFovPort fovMax = FovPort::Max(fovLeft, fovRight);
float combinedTanHalfFovHorizontal = max ( fovMax.LeftTan, fovMax.RightTan );
float combinedTanHalfFovVertical = max ( fovMax.UpTan, fovMax.DownTan );

ovrFovPort fovBoth;
fovBoth.LeftTan = fovBoth.RightTan = combinedTanHalfFovHorizontal;
fovBoth.UpTan = fovBoth.DownTan = combinedTanHalfFovVertical;

// Create render target.
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left,
                                                    fovBoth, pixelsPerDisplayPixel);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right,
                                                    fovBoth, pixelsPerDisplayPixel);

...

// Initialize rendering info.
ovrFovPort eyeFov[2];
eyeFov[0]                       = fovBoth;
eyeFov[1]                       = fovBoth;

...

// Compute the parameters to feed to the rendering engine.
// In this case we are assuming it wants a horizontal FOV and an aspect ratio.
float horizontalFullFovInRadians = 2.0f * atanf ( combinedTanHalfFovHorizontal );
float aspectRatio = combinedTanHalfFovHorizontal / combinedTanHalfFovVertical;

GraphicsEngineSetFovAndAspect ( horizontalFullFovInRadians, aspectRatio );
...
Примечание.: Поле зрения необходимо определить до создания однобуферной прорисовки, поскольку оно влияет на размер рекомендованной однобуферной прорисовки для заданного качества.

Повышение производительности за счет уменьшения плотности пикселей

Для виртуальной реальности снижение частоты кадров ниже 60 Гц приводит к крайне плохому пользовательскому опыту. Всегда лучше уменьшить разрешение, но сохранить стабильную частоту кадров. Это аналогично ситуации, когда пользователь имеет монитор с высоким разрешением 2 560 x 1 600. Очень немногие 3D-приложения могут работать на этом нативном разрешении с полной скоростью, поэтому большинство из них позволяют пользователю выбрать более низкое разрешение, которое монитор масштабирует, чтобы заполнить экран.
Вы можете использовать ту же стратегию для гарнитуры виртуальной реальности. То есть вы можете запустить приложение с более низким разрешением видео и позволить оборудованию выполнить масштабирование за вас. Однако это добавляет два этапа фильтрации: один на этапе обработки искажения, а другой на этапе масштабирования видео. К сожалению, такая двойная фильтрация приводит к появлению значительных артефактов. Обычно эффективнее оставить для видеорежима нативное разрешение, но ограничить размер промежуточной однобуферной прорисовки. Это дает аналогичное увеличение производительности, но сохраняет больше деталей.
Один из способов решить эту проблему — предоставить пользователю возможность настроить разрешение с помощью селектора. Однако реальное разрешение однобуферной прорисовки зависит от конфигурации пользователя, а не от стандартных аппаратных настроек. Это означает, что нативное разрешение может быть разным для разных пользователей. Кроме того, отображение разрешений, превышающих физическое разрешение оборудования, может запутать некоторых пользователей. Они могут не понять, что выбор разрешения 1 280 x 800 означает значительное снижение качества, даже если это разрешение указано оборудованием.
Лучшим вариантом будет изменить значение pixelsPerDisplayPixel, которое передается в функцию ovr_GetFovTextureSize. Это также можно реализовать ползунком, представленным в настройках рендеринга приложения. Это определяет относительный размер пикселей однобуферной прорисовки, когда они отображаются на пикселях в центре экрана. Например, значение 0,5 уменьшит размер однобуферной прорисовки с 2 000 x 1 056 до 1 000 x 528 пикселей, в результате чего видеокарты среднего уровня для ПК смогут поддерживать частоту обновления 60 Гц.
float pixelsPerDisplayPixel = GetPixelsPerDisplayFromApplicationSettings();

Sizei recommenedTexSize = ovr_GetFovTextureSize(session, ovrEye_Left,  fovLeft,
                                                   pixelsPerDisplayPixel);

Вы можете задать для параметра значение больше 1,0, чтобы получить промежуточную однобуферную прорисовку с более высоким разрешением, однако мы не обнаружили какого-либо заметного повышения качества и при этом ощутимо сказывается на производительности.
OculusWorldDemo позволяет вам экспериментировать с изменением плотности пикселей целевой однобуферной прорисовки. Перейдите в меню настроек (нажмите клавишу Tab) и выберите пункт Pixel Density (Плотность пикселей). Нажимайте клавиши со стрелками вверх и вниз, чтобы настроить плотность пикселей в центре проекции глаза. Значение 1,0 задает плотность пикселей однобуферной прорисовки на поверхности экрана в соотношении 1:1 в этой точке экрана. Значение 0,5 задает плотность пикселей однобуферной прорисовки, равную половинной плотности пикселей поверхности экрана. Кроме того, вы можете выбрать динамическое масштабирование разрешения (Dynamic Res Scaling), которое будет автоматически регулировать плотность пикселей в диапазоне от 0 до 1.

Повышение производительности за счет уменьшения поля зрения

Помимо уменьшения количества пикселей в промежуточной однобуферной прорисовке, вы можете повысить производительность, уменьшив поле зрения, на которой эти пиксели растягиваются.
В зависимости от степени уменьшения это может привести к эффекту туннельного зрения, что снижает ощущение погружения. Однако уменьшение поля зрения улучшает два аспекта производительности. Самый очевидный — скорость заполнения. При фиксированной плотности пикселей на сетчатке меньшее поле зрения задействует меньшее количество пикселей. Из-за свойств проективной математики самые дальние края поля зрения оказываются самыми затратными с точки зрения количества пикселей. Вторая причина — тот факт, что при меньшем поле зрения в каждом кадре видно меньше объектов, что подразумевает меньше анимации, меньше изменений состояния и меньше вызовов отрисовки.
Уменьшение поля зрения, заданного игроком, — крайне сложное решение. Один из ключевых аспектов виртуальной реальности — погружение в симулированный мир, и значительную роль в этом играет широкое поле зрения. Мы крайне неохотно советуем жертвовать этим аспектом. Если вы уже максимально снизили разрешение, но приложение по-прежнему не достигает 60 Гц на устройстве пользователя, это будет последний вариант.
Мы рекомендуем предоставить игрокам ползунок для настройки максимального поля зрения, который определяет четыре границы поля зрения каждого глаза.
ovrFovPort defaultFovLeft = session->DefaultEyeFov[ovrEye_Left];
ovrFovPort defaultFovRight = session->DefaultEyeFov[ovrEye_Right];

float maxFovAngle = ...get value from game settings panel...;
float maxTanHalfFovAngle = tanf ( DegreeToRad ( 0.5f * maxFovAngle ) );

ovrFovPort newFovLeft  = FovPort::Min(defaultFovLeft, FovPort(maxTanHalfFovAngle));
ovrFovPort newFovRight = FovPort::Min(defaultFovRight, FovPort(maxTanHalfFovAngle));


// Create render target.
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left  newFovLeft, pixelsPerDisplayPixel);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right, newFovRight, pixelsPerDisplayPixel);

...


// Initialize rendering info.
ovrFovPort eyeFov[2];
eyeFov[0]                       = newFovLeft;
eyeFov[1]                       = newFovRight;

...


// Determine projection matrices.
ovrMatrix4f projMatrixLeft = ovrMatrix4f_Projection(newFovLeft, znear, zfar, 0);
ovrMatrix4f projMatrixRight = ovrMatrix4f_Projection(newFovRight, znear, zfar, 0);

Поэкспериментируйте с неквадратными полями зрения. Например, можно значительно ограничить диапазоны вверх и вниз (например, до 70 градусов), сохранив при этом полное горизонтальное поле зрения, чтобы создать эффект синемаскопа.
OculusWorldDemo позволяет экспериментировать с уменьшением поля зрения ниже значений по умолчанию. Перейдите в меню настроек (нажмите клавишу Tab) и выберите значение Max FOV (Максимальное поле зрения). Нажимайте стрелки вверх и вниз, чтобы изменить максимальный угол в градусах.

Повышение производительности за счет рендеринга в монокулярном режиме

Одна из ключевых затрат стереоскопического рендеринга — необходимость рендеринга отдельного изображения для каждого глаза.
Для некоторых приложений стереоскопический аспект может быть не особенно важен, а монокулярный вид может повысить производительность. У некоторых пользователей может возникать напряжение глаз от стереоскопического вида, и они могут захотеть переключиться на монокулярный. При этом они хотят по-прежнему использовать гарнитуру виртуальной реальности, поскольку она предлагает широкое поле зрения и возможности отслеживания головы.
В OculusWorldDemo пользователь может переключиться в режим монокулярного рендеринга, нажав клавишу F7.
Чтобы выполнять рендеринг в монокулярном режиме, в коде потребуются следующие изменения:
  • установите для поля зрения максимальное симметричное значение, основанное на данных от обоих глаз;
  • используйте функцию ovhHmd_GetFovTextureSize с этим значением поля зрения для расчета рекомендуемого размера текстуры однобуферной прорисовки;
  • настройте оба глаза для использования одной однобуферной прорисовки и одинакового поля видимости при вызове ovr_EndFrame;
  • отрисуйте один раз в общую однобуферную прорисовку.
Поля зрения левого и правого глаза будут объединены в единый промежуточный рендер. Этот рендер всё ещё будет искажен дважды, по одному разу для каждого глаза, потому что линзы не находятся точно перед глазами пользователя. Однако это всё равно значительно улучшит производительность.
Установка нулевого значения для виртуального межзрачкового расстояния приведет к тому, что все объекты будут выглядеть гигантскими и бесконечно удаленными, так что пользователь утратит ощущение глубины в сцене.
Примечание. Важно масштабировать виртуальное межзрачковое расстояние и виртуальное движение головы вместе, поэтому если для виртуального межзрачкового расстояния задано нулевое значение, все виртуальные движения головы, вызванные движением шеи, также будут устранены. К сожалению, это приводит к потере значительной части сигналов о глубине из-за параллакса. Однако если движение головы и межзрачковое расстояние не согласуются, это может вызвать значительную дезориентацию и дискомфорт. Экспериментируйте с осторожностью!

Использование октолинейного рендеринга для технологии NVIDIA Lens Matched Shading

Октолинейный рендеринг реализует технологию NVIDIA Lens Matched Shading. Вы можете использовать октолинейный рендеринг для повышения производительности приложения, если оно выполняется на ГП NVIDIA.
Октолинейный рендеринг позволяет избежать необходимости рендеринга значительного количества пикселей, которые в противном случае были бы отброшены перед выводом изображения на гарнитуру. Приложение должно создавать изображение большего размера, чем отображаемое на Rift. Это требует дополнительного времени для отрисовки этих увеличенных изображений. Таким образом, технология Lens Matched Shading позволяет системе отрисовывать изображение меньшего размера, так как она создает предварительно сжатое изображение. Октолинейное изображение выглядит следующим образом:
Использование октолинейного рендеринга уменьшает размер области отрисовки примерно на 20 %. Границы остаются такими же, как и для неоктолинейного изображения.
Требования для использования октолинейного рендеринга:
  1. Приложение необходимо запускать на ГП NVIDIA с поддержкой линзового маппинга шейдинга. (Подробнее см. в документации NVIDIA.)
  2. Необходимо использовать NVIDIA SDK с поддержкой функции линзового маппинга шейдинга ГП. (Подробнее см. в документации NVIDIA.)
  3. Вы должны генерировать текстуры в правильном формате с помощью NVIDIA SDK.
  4. Приложение должно вызвать ovr_EnableExtension для включения октолинейного расширения на стороне гарнитуры.
  5. Затем среда выполнения автоматически обработает ваши изображения в специальном формате во время выполнения.

Защита контента

Иногда нужно, чтобы контент отображался только на гарнитуре. Функция защиты контента предназначена для предотвращения дублирования компоновщика.
Чтобы использовать функцию защиты контента, настройте приложение таким образом, чтобы оно создавало один или несколько объектов ovrTextureSwapChain с флагом ovrTextureMisc_ProtectedContent. Любая отправка, ссылающаяся на защищенную цепочку обмена, считается защищенным кадром. Все защищенные кадры компонуются и отображаются в гарнитуре, но не дублируются на зеркала и недоступны для API буфера захвата.
Если гарнитура не соответствует стандарту HDCP, при попытке создания цепочки текстур API выдаст ошибку ovrError_ContentProtectionNotAvailable. Если текстуры можно создать (гарнитура поддерживает HDCP), но позже соединение будет разорвано, следующий вызов ovr_EndFrame, который ссылается на защищенные цепочки обмена текстур, завершится с ошибкой ovrError_ContentProtectionNotAvailable. Настройте приложение так, чтобы оно реагировало соответственно. Например, можно отправить следующий кадр без защищенных цепочек обмена, но с более низким качеством, которое не требует защиты. Можно также остановить воспроизведение и показать пользователю сообщение об ошибке или предупреждение.
Примечание. Так как отображением в зеркальном окне управляет ваше приложение, то в случае, если оно не использует зеркальную текстуру, оно должно самостоятельно отрисовывать какое-то содержимое в окне предварительного просмотра. Убедитесь, что приложение не отображает защищенный контент. Так как операционная система не защищает эти поверхности, они будут отображаться в обычном виде в приложении, которое их создало.
Чтобы включить защищенный контент, укажите флаг ovrTextureMisc_ProtectedContent следующим образом:
ovrTextureSwapChainDesc desc = {};
desc.Type = ovrTexture_2D;
desc.ArraySize = 1;
desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
desc.Width = sizeW;
desc.Height = sizeH;
desc.MipLevels = 1;
desc.SampleCount = 1;
desc.MiscFlags = ovrTextureMisc_DX_Typeless | ovrTextureMisc_ProtectedContent;
desc.BindFlags = ovrTextureBind_DX_RenderTarget;
desc.StaticImage = ovrFalse;

ovrResult result = ovr_CreateTextureSwapChainDX(session, Device, &desc, &TextureChain);
Логотип навигации
Русский
© 2026 Meta