Partilhar via


Escrevendo um aplicativo Holográfico Remoting Player personalizado

Se você é novo no Holographic Remoting, você pode querer ler nossa visão geral.

Importante

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

Ao criar um aplicativo de player holográfico personalizado, você pode criar um aplicativo personalizado capaz de exibir vistas imersivas de uma máquina remota no seu HoloLens 2. Todo o código nesta página e projetos de trabalho podem ser encontrados no repositório github de amostras Holográficas Remotas.

Um player de comunicação remota holográfica permite que seu aplicativo exiba 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 Holographic Remoting player transmite dados de entrada para um aplicativo remoto Holographic Remoting e recebe de volta uma visão imersiva como fluxo de vídeo e áudio. A conexão é feita usando Wi-Fi padrão. Para criar um aplicativo de jogador, use um pacote NuGet para adicionar a comunicação remota holográfica ao seu aplicativo UWP. Em seguida, escreva o código para lidar com a conexão e exibir uma visão imersiva.

Pré-requisitos

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

Importante

Qualquer aplicativo que use comunicação remota holográfica deve ser criado para usar um apartamento multi-threaded. O uso de um apartamento de thread único é suportado, mas levará a um desempenho abaixo do ideal e, possivelmente, gagueira durante a reprodução. Ao usar C++/WinRT winrt::init_apartment um apartamento multi-threaded é o padrão.

Obtenha 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 que aparece, selecione Procurar e, em seguida, procure por "Comunicação Remota Holográfica".
  4. Selecione Microsoft.Holographic.Remoting, certifique-se de escolher a versão 2.x.x mais recente 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 pacote interno do 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 dos Microsoft.Holographic.AppRemoting.dll adicionados pelo pacote NuGet, as seguintes etapas precisam ser executadas no projeto:

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

Como primeiro passo, a aplicação deve criar um contexto de jogador.

// 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 tempo de execução do Windows Mixed Reality fornecido com o Windows. Isto é feito durante a criação do contexto do jogador. Por esse motivo, qualquer chamada em qualquer API do Windows Mixed Reality antes de criar o contexto do player pode resultar em um comportamento inesperado. A abordagem recomendada é criar o contexto do jogador o mais cedo possível antes da interação com qualquer API de Realidade Mista. Nunca misture objetos criados ou recuperados por meio de qualquer API do Windows Mixed Reality antes da chamada com PlayerContext::Create 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

Quando o aplicativo player estiver pronto para renderizar 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 executado 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

Como com qualquer API Connect C++/WinRT pode lançar um winrt::hresult_error que precisa ser manipulado.

A escuta de conexões de entrada no aplicativo player pode ser feita chamando o Listen método. Tanto a porta de handshake quanto a porta de transporte podem ser especificadas durante esta chamada. A porta de handshake é usada para o handshake inicial. Os dados são entã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: acionado quando uma conexão com o aplicativo remoto foi estabelecida com êxito.
m_onConnectedEventToken = m_playerContext.OnConnected([]() 
{
    // Handle connection successfully established
});
  1. OnDisconnected: acionado se uma conexão estabelecida for encerrada ou 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.
    }
}

Nota

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

  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 enquanto renderiza um HolographicFrame.

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

Quando chamado, BlitRemoteFrame copia o último quadro recebido do aplicativo remoto para o BackBuffer do HolographicFrame. Além disso, o conjunto de pontos de foco é 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();

Nota

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

Sobre o sucesso, BlitRemoteFrame retorna BlitResult::Success_Color. Caso contrário, ele retorna o motivo da falha:

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

Importante

A partir da versão 2.1.0 é possível com um leitor personalizado utilizar a reprojeção de profundidade através da comunicação remota holográfica.

BlitResult pode também devolver BlitResult::Success_Color_Depth nas seguintes condições:

Se essas condições forem atendidas, BlitRemoteFrame a profundidade remota será transferida para o buffer de profundidade local atualmente vinculado. 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 via HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer em seu player personalizado para ter reprojeção de profundidade para conteúdo renderizado remoto e local.

Modo de Transformação de Projeção

Um problema, que aparece ao usar a reprojeção de profundidade via 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 seu aplicativo player personalizado. Um caso de uso comum é especificar valores diferentes para o plano próximo e distante (via HolographicCamera::SetNearPlaneDistance e HolographicCamera::SetFarPlaneDistance) no lado do jogador e no lado remoto. Neste caso, não está claro se a transformação de projeção no lado do jogador deve refletir as distâncias planas remotas próximas/distantes ou as distâncias locais.

A partir da versão 2.1.0 , você pode controlar o modo de transformação de projeção via PlayerContext::ProjectionTransformConfig. Os valores suportados 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 seu aplicativo player personalizado na 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 de avião próximas/distantes do seu aplicativo remoto e do seu aplicativo de jogador personalizado são mescladas. Por padrão, isso é feito tomando o mínimo das distâncias de plano próximo e o máximo das distâncias de plano distante. No caso de o lado remoto ou local estar invertido, digamos muito < perto, as distâncias do plano remoto perto/longe são invertidas.

Opcional: Definir BlitRemoteFrameTimeout

Importante

PlayerContext::BlitRemoteFrameTimeout é suportado a partir da versão 2.0.9.

A PlayerContext::BlitRemoteFrameTimeout propriedade especifica a quantidade de tempo 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 para uma duração igual ou maior que 100 ms. Para desativar o tempo limite, defina a propriedade como duração zero. Se o tempo limite estiver ativado e nenhum quadro remoto for recebido para a duração definida, o 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 através 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.idl arquivo.

Opcional: canais de dados personalizados

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

Opcional: Renderização excessiva

A comunicação remota holográfica prevê onde estará a cabeça do utilizador no momento em que as imagens renderizadas aparecerem nos ecrãs. No entanto, esta previsão é uma aproximação. Portanto, a janela de visualização prevista no aplicativo remoto e a janela de visualização real posterior no aplicativo player podem ser diferentes. Desvios mais fortes (por exemplo, devido a um movimento imprevisível) podem causar regiões negras nas bordas do frustum de visualização. A partir da versão 2.6.0 , você pode usar a renderização excessiva para reduzir as regiões pretas e melhorar a qualidade visual, aumentando artificialmente a janela de visualização além do frustum de visualização.

A renderização excessiva pode ser ativada via PlayerContext::ConfigureOverRendering.

O OverRenderingConfig especifica um aumento de tamanho fracionado para o visor real, para que o visor previsto se torne maior e ocorra menos corte. Com um tamanho de visor aumentado, a densidade de pixels diminui, portanto, o OverRenderingConfig permite que você aumente a resolução também. Se o aumento da janela de visualização for igual ao aumento da resolução, a densidade de pixels permanecerá a mesma. OverRenderingConfig define-se 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: Coordenar a sincronização do sistema

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 comunicação remota holográfica.

Consulte Também