Como escrever um aplicativo do Holographic Remoting Player personalizado

Se você não estiver familiarizado com a Comunicação Remota Holográfica, talvez queira ler nossa visão geral.

Importante

Este documento descreve a criação de um aplicativo player personalizado para HoloLens 2. Os players personalizados escritos para HoloLens 2 não são compatíveis com aplicativos remotos escritos para o HoloLens 1. Isso implica que ambos os aplicativos devem usar o pacote NuGet versão 2.x.x.

Ao criar um aplicativo personalizado do Player de Comunicação Remota Holográfica, você pode criar um aplicativo personalizado capaz de exibir exibições imersivas em um computador remoto em seu HoloLens 2. Todos os códigos nesta página e projetos de trabalho podem ser encontrados no repositório github de exemplos de Comunicação Remota Holográfica.

Um player de Comunicação Remota Holográfica permite que seu aplicativo exiba o conteúdo holográfico renderizado em um computador desktop ou dispositivo UWP como o Xbox One com acesso a mais recursos do sistema. Um aplicativo de player de Comunicação Remota Holográfica transmite dados de entrada para um aplicativo remoto de Comunicação Remota Holográfica e recebe de volta uma exibição imersiva como fluxo de vídeo e áudio. A conexão é feita usando Wi-Fi padrão. Para criar um aplicativo player, use um pacote NuGet para adicionar a Comunicação Remota Holográfica ao seu aplicativo UWP. Em seguida, escreva código para manipular a conexão e exibir uma exibição imersiva.

Pré-requisitos

Um bom ponto de partida é um aplicativo UWP baseado em DirectX que já tem como destino a API Windows Mixed Reality. Para obter detalhes , confira Visão geral do desenvolvimento do DirectX. Se você não tiver um aplicativo existente e quiser começar do zero, o modelo de projeto holográfico do C++ será um bom ponto de partida.

Importante

Qualquer aplicativo que use a Comunicação Remota Holográfica deve ser criado para usar um apartment multi-threaded. Há suporte para o uso de um apartamento de thread único , mas levará a um desempenho abaixo do ideal e possivelmente gaguejar durante a reprodução. Ao usar o C++/WinRT winrt::init_apartment um apartment multi-threaded é o padrão.

Obter o pacote NuGet de Comunicação Remota Holográfica

As etapas a seguir são necessárias para adicionar o pacote NuGet a um projeto no Visual Studio.

  1. Abra o projeto no Visual Studio.
  2. Clique com o botão direito do mouse no nó do projeto e selecione Gerenciar Pacotes NuGet...
  3. No painel exibido, selecione Procurar e pesquise "Comunicação Remota Holográfica".
  4. Selecione Microsoft.Holographic.Remoting, escolha a versão mais recente do 2.x.x e selecione Instalar.
  5. Se a caixa de diálogo Visualizar for exibida, selecione OK.
  6. Selecione Aceito quando a caixa de diálogo do contrato de licença for exibida.

Importante

O build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl dentro do pacote NuGet contém documentação detalhada para a API exposta pela Comunicação Remota Holográfica.

Modificar o Package.appxmanifest do aplicativo

Para tornar o aplicativo ciente do Microsoft.Holographic.AppRemoting.dll adicionado pelo pacote NuGet, as seguintes etapas precisam ser executadas no projeto:

  1. Na Gerenciador de Soluções, clique com o botão direito do mouse no arquivo Package.appxmanifest e selecione Abrir com...
  2. Selecione Editor XML (Texto) e selecione OK
  3. Adicione as seguintes linhas ao arquivo e salve
  </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>

Criar o contexto do player

Como primeira etapa, o aplicativo deve criar um contexto de player.

// 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();

Aviso

Um player personalizado injeta uma camada intermediária entre o aplicativo player e o runtime do Windows Mixed Reality fornecido com o Windows. Isso é feito durante a criação do contexto do jogador. Por esse motivo, qualquer chamada em qualquer API Windows Mixed Reality antes de criar o contexto do player pode resultar em um comportamento inesperado. A abordagem recomendada é criar o contexto do player o mais cedo possível antes da interação com qualquer API Realidade Misturada. Nunca misture objetos criados ou recuperados por meio de nenhuma API Windows Mixed Reality antes da chamada para PlayerContext::Create com objetos criados ou recuperados posteriormente.

Em seguida, o HolographicSpace pode ser criado chamando HolographicSpace.CreateForCoreWindow.

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

Conectar-se ao aplicativo remoto

Depois que o aplicativo player estiver pronto para renderizar o conteúdo, uma conexão com o aplicativo remoto poderá ser estabelecida.

A conexão pode ser estabelecida de uma das seguintes maneiras:

  1. O aplicativo player em execução no HoloLens 2 se conecta ao aplicativo remoto.
  2. O aplicativo remoto se conecta ao aplicativo player em execução no HoloLens 2.

Para se conectar do aplicativo player ao aplicativo remoto, chame o Connect método no contexto do player especificando o nome do host e a porta. A porta padrão é 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()
}

Importante

Assim como acontece com qualquer API Connect do C++/WinRT, pode gerar um winrt::hresult_error que precisa ser tratado.

A escuta de conexões de entrada no aplicativo player pode ser feita chamando o Listen método . A porta de handshake e a porta de transporte podem ser especificadas durante essa chamada. A porta de handshake é usada para o handshake inicial. Em seguida, os dados são enviados pela porta de transporte. Por padrão, são usados os números de porta 8265 e 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()
}

O PlayerContext expõe três eventos para monitorar o estado da conexão

  1. OnConnected: disparado quando uma conexão com o aplicativo remoto foi estabelecida com êxito.
m_onConnectedEventToken = m_playerContext.OnConnected([]() 
{
    // Handle connection successfully established
});
  1. OnDisconnected: disparado se uma conexão estabelecida for encerrada ou se uma conexão não puder ser estabelecida.
m_onDisconnectedEventToken = m_playerContext.OnDisconnected([](ConnectionFailureReason failureReason)
{
    switch (failureReason)
    {
        // Handle connection failed or terminated.
        // See ConnectionFailureReason for possible reasons.
    }
}

Observação

Os valores possíveis ConnectionFailureReason estão documentados no Microsoft.Holographic.AppRemoting.idlarquivo.

  1. OnListening: quando a escuta de conexões de entrada é iniciada.
m_onListeningEventToken = m_playerContext.OnListening([]()
{
    // Handle start listening for incoming connections
});

Além disso, o estado da conexão pode ser consultado usando a ConnectionState propriedade no contexto do player.

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

Exibir o quadro renderizado remotamente

Para exibir o conteúdo renderizado remotamente, chame PlayerContext::BlitRemoteFrame ao renderizar um HolographicFrame.

BlitRemoteFrame requer que o buffer de fundo para o HolographicFrame atual esteja associado como destino de renderização. O buffer de fundo pode ser recebido do HolographicCameraRenderingParameters por meio da propriedade Direct3D11BackBuffer .

Quando chamado, BlitRemoteFrame copia o quadro recebido mais recente do aplicativo remoto para o BackBuffer do HolographicFrame. Além disso, o conjunto de pontos de foco será definido, se o aplicativo remoto tiver especificado um ponto de foco durante a renderização do quadro remoto.

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

Observação

PlayerContext::BlitRemoteFrame potencialmente substitui o ponto de foco para o quadro atual.

Em caso de êxito, BlitRemoteFrame retorna BlitResult::Success_Color. Caso contrário, ele retornará o motivo da falha:

  • BlitResult::Failed_NoRemoteFrameAvailable: falha porque nenhum quadro remoto está disponível.
  • BlitResult::Failed_NoCamera: falha porque não há câmera presente.
  • BlitResult::Failed_RemoteFrameTooOld: falha porque o quadro remoto é muito antigo (consulte a propriedade PlayerContext::BlitRemoteFrameTimeout).

Importante

A partir da versão 2.1.0 , é possível com um player personalizado usar a reprojeção de profundidade por meio da Comunicação Remota Holográfica.

BlitResult também pode retornar BlitResult::Success_Color_Depth sob as seguintes condições:

Se essas condições forem atendidas, BlitRemoteFrame a profundidade remota será cortada no buffer de profundidade local associado no momento. Em seguida, você pode renderizar conteúdo local adicional, que terá interseção de profundidade com o conteúdo renderizado remoto. Além disso, você pode confirmar o buffer de profundidade local por meio de HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer em seu player personalizado para ter uma reprojeção de profundidade para conteúdo renderizado remoto e local.

Modo de Transformação de Projeção

Um problema que surge ao usar a reprojeção de profundidade por meio da Comunicação Remota Holográfica é que o conteúdo remoto pode ser renderizado com uma transformação de projeção diferente do conteúdo local renderizado diretamente pelo aplicativo player personalizado. Um caso de uso comum é especificar valores diferentes para plano próximo e distante (via HolographicCamera::SetNearPlaneDistance e HolographicCamera::SetFarPlaneDistance) no lado do jogador e no lado remoto. Nesse caso, não está claro se a transformação de projeção no lado do jogador deve refletir as distâncias remotas do plano próximo/distante ou as locais.

A partir da versão 2.1.0 , você pode controlar o modo de transformação de projeção por meio de PlayerContext::ProjectionTransformConfig. Os valores com suporte são:

  • Local - HolographicCameraPose::P rojectionTransform retorna uma transformação de projeção, que reflete as distâncias de plano próximas/distantes definidas pelo aplicativo player personalizado no HolographicCamera.
  • Remote – A transformação de projeção reflete as distâncias do plano próximo/distante especificadas pelo aplicativo remoto.
  • Merged - As distâncias do plano próximo/distante do aplicativo remoto e do aplicativo de player personalizado são mescladas. Por padrão, isso é feito tomando o mínimo das distâncias do plano próximo e o máximo das distâncias distantes do plano. Caso o lado remoto ou local seja invertido, digamos, muito < perto, as distâncias remotas do plano próximo/distante são viradas.

Opcional: Definir BlitRemoteFrameTimeout

Importante

PlayerContext::BlitRemoteFrameTimeout tem suporte a partir da versão 2.0.9.

A PlayerContext::BlitRemoteFrameTimeout propriedade especifica a quantidade de tempo em que um quadro remoto é reutilizado se nenhum novo quadro remoto for recebido.

Um caso de uso comum é habilitar o tempo limite de BlitRemoteFrame para exibir uma tela em branco se nenhum novo quadro for recebido por um determinado período de tempo. Quando habilitado, o tipo de retorno do BlitRemoteFrame método também pode ser usado para alternar para um conteúdo de fallback renderizado localmente.

Para habilitar o tempo limite, defina o valor da propriedade como uma duração igual ou maior que 100 ms. Para desabilitar o tempo limite, defina a propriedade como duração zero. Se o tempo limite estiver habilitado e nenhum quadro remoto for recebido durante o conjunto, BlitRemoteFrame falhará e retornará Failed_RemoteFrameTooOld até que um novo quadro remoto seja recebido.

using namespace std::chrono_literals;

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

Opcional: obter estatísticas sobre o último quadro remoto

Para diagnosticar problemas de desempenho ou de rede, as estatísticas sobre o último quadro remoto podem ser recuperadas por meio da PlayerContext::LastFrameStatistics propriedade . As estatísticas são atualizadas durante a chamada para HolographicFrame::P resentUsingCurrentPrediction.

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

Para obter mais informações, consulte a PlayerFrameStatistics documentação no Microsoft.Holographic.AppRemoting.idlarquivo .

Opcional: canais de dados personalizados

Canais de dados personalizados podem ser usados para enviar dados do usuário pela conexão remota já estabelecida. Para obter mais informações, consulte canais de dados personalizados.

Opcional: Over-Rendering

A Comunicação Remota Holográfica prevê onde a cabeça do usuário estará no momento em que as imagens renderizadas aparecerem nas exibições. No entanto, essa previsão é uma aproximação. Portanto, o visor previsto no aplicativo remoto e o visor real posterior no aplicativo player podem ser diferentes. Desvios mais fortes (por exemplo, devido a movimento imprevisível) podem causar regiões negras nas bordas do tronco de exibição. A partir da versão 2.6.0 , você pode usar Over-Rendering para reduzir as regiões pretas e melhorar a qualidade visual aumentando artificialmente o visor além do frusto de exibição.

Over-Rendering pode ser habilitado por meio de PlayerContext::ConfigureOverRendering.

O OverRenderingConfig especifica um aumento de tamanho fracionário para o visor real, de modo que o visor previsto se torne maior e menos corte ocorra. Com um tamanho maior do visor, a densidade de pixel diminui, portanto, OverRenderingConfig permite que você aumente a resolução também. Se o aumento do visor for igual ao aumento da resolução, a densidade de pixel permanecerá a mesma. OverRenderingConfig é definido como:

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

Opcional: sincronização do sistema de coordenadas

A partir da versão 2.7.0 , a sincronização do sistema de coordenadas pode ser usada para alinhar dados espaciais entre o player e o aplicativo remoto. Para obter mais informações, consulte Visão geral da sincronização do sistema de coordenadas com a comunicação remota holográfica.

Consulte Também