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

Если вы не знакомы с голографическим удаленным взаимодействием, ознакомьтесь с нашим обзором.

Важно!

В этом документе описывается создание пользовательского приложения проигрывателя для HoloLens 2. Пользовательские проигрыватели, написанные для HoloLens 2, несовместимы с удаленными приложениями, написанными для HoloLens 1. Это означает, что оба приложения должны использовать пакет NuGet версии 2.x.x.

Создав пользовательское приложение проигрывателя голографического удаленного взаимодействия, можно создать пользовательское приложение, которое может отображать иммерсивные представления на удаленном компьютере на HoloLens 2. Весь код на этой странице и рабочие проекты можно найти в репозитории примеров голографического удаленного взаимодействия GitHub.

Голографический проигрыватель удаленного взаимодействия позволяет вашему приложению отображать голографическое содержимое, отображаемое на настольном компьютере или на устройстве UWP, например Xbox One, с доступом к дополнительным системным ресурсам. Приложение голографического удаленного взаимодействия передает входные данные в удаленное приложение голографического удаленного взаимодействия и получает обратно иммерсивное представление в виде видео- и аудиопотока. Подключение осуществляется с помощью стандартной сети Wi-Fi. Чтобы создать приложение проигрывателя, используйте пакет NuGet для добавления голографического удаленного взаимодействия в приложение UWP. Затем напишите код для обработки соединения и отображения иммерсивного представления.

Предварительные требования

Хорошей отправной точкой является работающее приложение UWP на основе DirectX, которое уже нацелено на API Windows Mixed Reality. Дополнительные сведения см. в статье Обзор разработки DirectX. Если у вас нет существующего приложения и вы хотите начать с нуля , шаблон голографического проекта C++ является хорошей отправной точкой.

Важно!

Любое приложение, использующе голографическое удаленное взаимодействие, должно быть создано для использования многопотокового подразделения. Использование однопотокового подразделения поддерживается, но приведет к неоптимальной производительности и, возможно, заикание во время воспроизведения. При использовании C++/WinRT winrt::init_apartment по умолчанию используется многопоточное подразделение.

Получение пакета NuGet для голографического удаленного взаимодействия

Чтобы добавить пакет NuGet в проект в Visual Studio, необходимо выполнить следующие действия.

  1. Откройте проект в Visual Studio.
  2. Щелкните правой кнопкой мыши узел проекта и выберите Управление пакетами NuGet...
  3. На появиющейся панели выберите Обзор и выполните поиск по запросу "Голографическое удаленное взаимодействие".
  4. Выберите Microsoft.Holographic.Remoting, выберите последнюю версию 2.x.x и нажмите кнопку Установить.
  5. Если откроется диалоговое окно Предварительный просмотр , нажмите кнопку ОК.
  6. Выберите Я принимаю , когда откроется диалоговое окно лицензионного соглашения.

Важно!

В build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl пакете NuGet содержится подробная документация по API, предоставляемому Голографическим удаленным взаимодействием.

Изменение Package.appxmanifest приложения

Чтобы приложение было осведомлено о Microsoft.Holographic.AppRemoting.dll, добавленных пакетом NuGet, в проекте необходимо выполнить следующие действия:

  1. В Обозреватель решений щелкните правой кнопкой мыши файл Package.appxmanifest и выберите Открыть с помощью...
  2. Выберите Редактор XML (текст) и нажмите кнопку ОК.
  3. Добавьте следующие строки в файл и сохраните
  </Capabilities>

  <!--Add lines below -->
  <Extensions>
    <Extension Category="windows.activatableClass.inProcessServer">
      <InProcessServer>
        <Path>Microsoft.Holographic.AppRemoting.dll</Path>
        <ActivatableClass ActivatableClassId="Microsoft.Holographic.AppRemoting.PlayerContext" ThreadingModel="both" />
      </InProcessServer>
    </Extension>
  </Extensions>
  <!--Add lines above -->

</Package>

Создание контекста проигрывателя

В качестве первого шага приложение должно создать контекст игрока.

// class declaration:

#include <winrt/Microsoft.Holographic.AppRemoting.h>

...

private:
// PlayerContext used to connect with a Holographic Remoting remote app and display remotely rendered frames
winrt::Microsoft::Holographic::AppRemoting::PlayerContext m_playerContext = nullptr;
// class implementation:

// Create the player context
// IMPORTANT: This must be done before creating the HolographicSpace (or any other call to the Holographic API).
m_playerContext = winrt::Microsoft::Holographic::AppRemoting::PlayerContext::Create();

Предупреждение

Пользовательский проигрыватель внедряет промежуточный уровень между приложением проигрывателя и средой выполнения Windows Mixed Reality, поставляемой вместе с Windows. Это делается во время создания контекста игрока. По этой причине любой вызов api Windows Mixed Reality перед созданием контекста проигрывателя может привести к непредвиденному поведению. Рекомендуемый подход — как можно раньше создать контекст игрока перед взаимодействием с api Смешанная реальность. Никогда не смешивайте объекты, созданные или полученные с помощью API Windows Mixed Reality до вызова , PlayerContext::Create с объектами, созданными или извлеченными после этого.

Затем можно создать HolographicSpace, вызвав HolographicSpace.CreateForCoreWindow.

m_holographicSpace = winrt::Windows::Graphics::Holographic::HolographicSpace::CreateForCoreWindow(window);

Подключение к удаленному приложению

Когда приложение проигрывателя будет готово для отрисовки содержимого, можно установить подключение к удаленному приложению.

Подключение можно установить одним из следующих способов:

  1. Приложение проигрывателя, работающее на HoloLens 2, подключается к удаленному приложению.
  2. Удаленное приложение подключается к приложению проигрывателя, работающему на HoloLens 2.

Чтобы подключиться из приложения проигрывателя к удаленному приложению, вызовите Connect метод в контексте проигрывателя, указав имя узла и порт. Порт по умолчанию — 8265.

try
{
    m_playerContext.Connect(m_hostname, m_port);
}
catch(winrt::hresult_error& e)
{
    // Failed to connect. Get an error details via e.code() and e.message()
}

Важно!

Как и в случае с любым API Connect C++/WinRT, может вызвать winrt::hresult_error который необходимо обработать.

Прослушивание входящих подключений в приложении проигрывателя можно выполнить, вызвав Listen метод . Во время этого вызова можно указать как порт подтверждения, так и транспортный порт. Порт подтверждения используется для начального подтверждения. Затем данные отправляются через транспортный порт. По умолчанию используются порты 8265 и 8266 .

try
{
    m_playerContext.Listen(L"0.0.0.0", m_port, m_port + 1);
}
catch(winrt::hresult_error& e)
{
    // Failed to listen. Get an error details via e.code() and e.message()
}

предоставляет PlayerContext три события для отслеживания состояния подключения.

  1. OnConnected: активируется при успешном подключении к удаленному приложению.
m_onConnectedEventToken = m_playerContext.OnConnected([]() 
{
    // Handle connection successfully established
});
  1. OnDisconnected: активируется, если установленное подключение прервано или не удается установить соединение.
m_onDisconnectedEventToken = m_playerContext.OnDisconnected([](ConnectionFailureReason failureReason)
{
    switch (failureReason)
    {
        // Handle connection failed or terminated.
        // See ConnectionFailureReason for possible reasons.
    }
}

Примечание

Возможные ConnectionFailureReason значения задокументированы в Microsoft.Holographic.AppRemoting.idlфайле .

  1. OnListening: при прослушивании входящих подключений начинается.
m_onListeningEventToken = m_playerContext.OnListening([]()
{
    // Handle start listening for incoming connections
});

Кроме того, состояние подключения можно запросить с помощью ConnectionState свойства в контексте проигрывателя.

winrt::Microsoft::Holographic::AppRemoting::ConnectionState state = m_playerContext.ConnectionState();

Отображение удаленно отрисованного кадра

Чтобы отобразить удаленно отрисованное содержимое, вызовите PlayerContext::BlitRemoteFrame во время отрисовки HolographicFrame.

BlitRemoteFrame требует, чтобы задний буфер для текущего HolographicFrame был привязан как целевой объект отрисовки. Задний буфер можно получить из HolographicCameraRenderingParameters с помощью свойства Direct3D11BackBuffer .

При вызове BlitRemoteFrame копирует последний полученный кадр из удаленного приложения в BackBuffer элемента HolographicFrame. Кроме того, устанавливается точка фокусировки, если удаленное приложение указало точку фокусировки во время отрисовки удаленного кадра.

// Blit the remote frame into the backbuffer for the HolographicFrame.
winrt::Microsoft::Holographic::AppRemoting::BlitResult result = m_playerContext.BlitRemoteFrame();

Примечание

PlayerContext::BlitRemoteFrame потенциально перезаписывает точку фокуса для текущего кадра.

При успешном выполнении BlitRemoteFrame возвращает .BlitResult::Success_Color В противном случае возвращается причина сбоя:

  • BlitResult::Failed_NoRemoteFrameAvailable: произошел сбой, так как удаленный кадр недоступен.
  • BlitResult::Failed_NoCamera: ошибка из-за отсутствия камеры.
  • BlitResult::Failed_RemoteFrameTooOld: произошел сбой, так как удаленный кадр слишком стар (см. свойство PlayerContext::BlitRemoteFrameTimeout).

Важно!

Начиная с версии 2.1.0 можно использовать перепроецирование глубины с помощью голографического удаленного взаимодействия с помощью пользовательского проигрывателя.

BlitResult также может возвращать BlitResult::Success_Color_Depth при следующих условиях:

  • Удаленное приложение зафиксировало буфер глубины с помощью HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer.
  • Пользовательское приложение проигрывателя привязывает допустимый буфер глубины перед вызовом BlitRemoteFrame.

При соблюдении BlitRemoteFrame этих условий выполняет преобразование удаленной глубины в текущий привязанный локальный буфер глубины. Затем можно отобразить дополнительное локальное содержимое, которое будет иметь пересечение глубины с удаленным отображаемым содержимым. Кроме того, вы можете зафиксировать локальный буфер глубины с помощью HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer в пользовательском проигрывателе, чтобы иметь повторное проецирование глубины для удаленного и локального отрисованного содержимого.

Режим преобразования проекции

Одна из проблем, которая возникает при использовании перепроецирования глубины с помощью голографического удаленного взаимодействия, заключается в том, что удаленное содержимое может быть отрисовано с преобразованием проекции, отличным от локального содержимого, непосредственно отображаемого пользовательским приложением проигрывателя. Распространенным вариантом использования является указание различных значений для ближней и дальней плоскости (с помощью HolographicCamera::SetNearPlaneDistance и HolographicCamera::SetFarPlaneDistance) на стороне проигрывателя и на удаленной стороне. В этом случае неясно, должно ли преобразование проекции на стороне игрока отражать удаленные расстояния ближней и дальней плоскости или локальные.

Начиная с версии 2.1.0 режимом преобразования проекции можно управлять с помощью PlayerContext::ProjectionTransformConfig. Поддерживаются значения:

  • Local - HolographicCameraPose::P rojectionTransform возвращает преобразование проекции, которое отражает расстояния ближней и дальней плоскости, заданные пользовательским приложением проигрывателя в HolographicCamera.
  • Remote — Преобразование проекции отражает расстояния ближней и дальней плоскости, заданные удаленным приложением.
  • Merged — Расстояния близкого и дальнего расстояния от удаленного приложения и пользовательского приложения проигрывателя объединяются. По умолчанию это делается путем принятия минимальных расстояний ближней плоскости и максимума расстояний дальней плоскости. В случае, если удаленная или локальная сторона инвертируется, скажем, далеко < рядом, удаленные расстояния ближнего и дальнего плоскости переворачиваются.

Необязательно: set BlitRemoteFrameTimeout

Важно!

PlayerContext::BlitRemoteFrameTimeout поддерживается начиная с версии 2.0.9.

Свойство PlayerContext::BlitRemoteFrameTimeout указывает время повторного использования удаленного кадра, если новый удаленный кадр не получен.

Распространенным вариантом использования является включение времени ожидания BlitRemoteFrame для отображения пустого экрана, если новые кадры не получены в течение определенного периода времени. Если этот параметр включен, тип возвращаемого BlitRemoteFrame значения метода также можно использовать для переключения на локально отрисованное резервное содержимое.

Чтобы включить время ожидания, задайте для свойства значение длительности, равное или больше 100 мс. Чтобы отключить время ожидания, задайте для свойства значение нулевой длительности. Если время ожидания включено и удаленный кадр не получен в течение заданного периода, BlitRemoteFrame будет завершатся ошибкой и будет возвращаться Failed_RemoteFrameTooOld , пока не будет получен новый удаленный кадр.

using namespace std::chrono_literals;

// Set the BlitRemoteFrame timeout to 0.5s
m_playerContext.BlitRemoteFrameTimeout(500ms);

Необязательно. Получение статистики о последнем удаленном кадре

Для диагностики проблем с производительностью или сетью можно получить статистику о последнем удаленном кадре PlayerContext::LastFrameStatistics с помощью свойства . Статистика обновляется во время вызова HolographicFrame::P resentUsingCurrentPrediction.

// Get statistics for the last presented frame.
winrt::Microsoft::Holographic::AppRemoting::PlayerFrameStatistics statistics = m_playerContext.LastFrameStatistics();

Дополнительные сведения см. в документации PlayerFrameStatistics в Microsoft.Holographic.AppRemoting.idlфайле .

Необязательно. Пользовательские каналы данных

Пользовательские каналы данных можно использовать для отправки пользовательских данных через уже установленное удаленное подключение. Дополнительные сведения см. в разделе Пользовательские каналы данных.

Необязательно: Over-Rendering

Голографическое удаленное взаимодействие прогнозирует, где будет находиться голова пользователя во время отображения отображаемых изображений на дисплеях. Однако этот прогноз является приблизительный. Таким образом, прогнозируемое окно просмотра в удаленном приложении и последующее фактическое окно просмотра в приложении проигрывателя могут отличаться. Более сильные отклонения (например, из-за непредсказуемого движения) могут вызвать черные области на границах смотровой области. Начиная с версии 2.6.0 вы можете использовать Over-Rendering для уменьшения черных областей и улучшения визуального качества за счет искусственного увеличения окна просмотра за пределами области просмотра.

Over-Rendering можно включить с помощью PlayerContext::ConfigureOverRendering.

Указывает OverRenderingConfig дробное увеличение размера до фактического окна просмотра, чтобы прогнозируемое окно просмотра становилось больше и меньше происходит вырезание. При увеличении размера окна просмотра плотность пикселей уменьшается, поэтому OverRenderingConfig позволяет также увеличить разрешение. Если увеличение окна просмотра равно увеличению разрешения, плотность пикселей остается прежней. OverRenderingConfig определяется следующим образом.

struct OverRenderingConfig
{
    float HorizontalViewportIncrease; // The fractional horizontal viewport increase. (e.g. 10% -> 0.1).
    float VerticalViewportIncrease; // The fractional vertical viewport increase. (e.g. 10% -> 0.1).
                
    float HorizontalResolutionIncrease; // The fractional horizontal resolution increase. (e.g. 10% -> 0.1).
    float VerticalResolutionIncrease; // The fractional vertical resolution increase. (e.g. 10% -> 0.1).
};

Необязательно. Синхронизация системы координат

Начиная с версии 2.7.0 синхронизацию системы координат можно использовать для выравнивания пространственных данных между проигрывателем и удаленным приложением. Дополнительные сведения см. в разделе Общие сведения о синхронизации системы координат с голографическим удаленным взаимодействием.

См. также: