Desempenho — MRTK2

Introdução

A maneira mais fácil de racionalizar o desempenho é por meio da taxa de quadros ou quantas vezes seu aplicativo pode renderizar uma imagem por segundo. É importante atender à taxa de quadros de destino, conforme descrito pela plataforma que está sendo direcionada (ou seja, Windows Mixed Reality, Oculus etc. Por exemplo, no HoloLens, a taxa de quadros de destino é de 60 FPS. Aplicativos com baixa taxa de quadros podem resultar em experiências deterioradas do usuário, como estabilização de holograma piorada, acompanhamento mundial, acompanhamento manual e muito mais. Para ajudar os desenvolvedores a acompanhar e obter uma taxa de quadros de qualidade, Realidade Misturada Toolkit fornece uma variedade de ferramentas e scripts.

Criador de perfil visual

Para acompanhar continuamente o desempenho durante o tempo de vida do desenvolvimento, é altamente recomendável sempre mostrar um visual de taxa de quadros durante a execução & depuração de um aplicativo. Realidade Misturada Toolkit fornece a ferramenta de diagnóstico do Visual Profiler que fornece informações em tempo real sobre o FPS atual e o uso de memória no modo de exibição do aplicativo. O Visual Profiler pode ser configurado por meio das Configurações do Sistema de Diagnóstico no Inspetor de Perfis do MRTK.

Além disso, é particularmente importante utilizar o Visual Profiler para controlar a taxa de quadros ao executar no dispositivo em vez de executar no editor do Unity ou em um emulador. Os resultados de desempenho mais precisos serão descritos ao serem executados no dispositivo com builds de configuração de versão.

Observação

Se estiver criando para Windows Mixed Reality, implante com builds de configuração MASTER.

Visual Profiler Interface

Janela de otimização

A Janela de Otimização do MRTK oferece ferramentas de automação e informações para ajudar os desenvolvedores de realidade misturada a configurar seu ambiente para obter os resultados de melhor desempenho e identificar possíveis gargalos em sua cena & ativos. Determinadas configurações importantes no Unity podem ajudar a fornecer resultados substancialmente mais otimizados para projetos de realidade misturada.

Geralmente, essas configurações envolvem configurações de renderização ideais para realidade misturada. Aplicativos de realidade misturada são exclusivos em comparação com o desenvolvimento de elementos gráficos 3D tradicionais, pois há duas telas (ou seja, dois olhos) para renderizar para toda a cena.

As configurações recomendadas referenciadas abaixo podem ser configuradas automaticamente em um projeto do Unity aproveitando a Janela de Otimização do MRTK.

Otimizar configurações de janela do MRTK

Criador de Perfil do Unity

O Unity Profiler é uma ferramenta útil para investigar detalhes do desempenho do aplicativo em um nível quadro a quadro.

Tempo gasto na CPU

Exemplo de Grafo do Criador de Perfil do Unity

Para manter taxas de quadro confortáveis (normalmente 60 quadros por segundo), os aplicativos precisam atingir um tempo de quadro máximo de 16,6 milissegundos de tempo de CPU. Para ajudar a identificar o custo da funcionalidade do MRTK, o Microsoft Realidade Misturada Toolkit contém marcadores para caminhos de código de loop interno (por quadro). Esses marcadores usam o seguinte formato para ajudar a entender a funcionalidade específica que está sendo utilizada:

[MRTK] className.methodName

Observação

Pode haver dados adicionais seguindo o nome do método. Isso é usado para identificar a funcionalidade condicionalmente executada, potencialmente cara, que pode ser evitada por pequenas alterações no código do aplicativo.

Exemplo de hierarquia do Criador de Perfil do Unity

Neste exemplo, a hierarquia foi expandida para mostrar que o método UpdateHandData da classe WindowsMixedRealityArticulatedHand está consumindo 0,44 ms de tempo de CPU durante a análise do quadro. Esses dados podem ser usados para ajudar a determinar se um problema de desempenho está relacionado ao código do aplicativo ou de outro lugar no sistema.

É altamente recomendável que os desenvolvedores instrumentem o código do aplicativo de maneira semelhante. As principais áreas de foco para instrumentação de código do aplicativo estão dentro de manipuladores de eventos, pois esses métodos são cobrados para o loop de atualização do MRTK à medida que os eventos são gerados. Tempos de quadros altos dentro do loop de atualização do MRTK podem ser indicativos de código caro em métodos de manipulador de eventos.

Single-Pass renderização em instâncias

A configuração de renderização padrão para XR no Unity é Multi-pass. Essa configuração instrui o Unity a executar todo o pipeline de renderização duas vezes, uma vez para cada olho. Isso pode ser otimizado selecionando a renderização de Instância de Passe Único . Essa configuração aproveita as matrizes de destino de renderização para poder executar uma única chamada de desenho que as instâncias no destino de renderização apropriado para cada olho. Além disso, esse modo permite que toda a renderização seja feita em uma única execução do pipeline de renderização. Assim, selecionar a renderização de Instância de Passagem Única como o caminho de renderização para um aplicativo de realidade misturada pode economizar tempo substancial na GPU & da CPU e é a configuração de renderização recomendada.

No entanto, para emitir uma única chamada de desenho para cada malha para cada olho, a instanciação de GPU deve ter suporte de todos os sombreadores. A instanciação permite que a GPU multiplexe as chamadas de desenho em ambos os olhos. Os sombreadores internos do Unity, bem como o sombreador padrão do MRTK , por padrão, contêm as instruções de instanciação necessárias no código do sombreador. Se estiver gravando sombreadores personalizados para o Unity, esses sombreadores talvez precisem ser atualizados para dar suporte à renderização de Instância de Passagem Única.

Código de exemplo para sombreador personalizado

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;

    UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
};

struct v2f
{
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;

    UNITY_VERTEX_OUTPUT_STEREO //Insert
};

v2f vert (appdata v)
{
    v2f o;

    UNITY_SETUP_INSTANCE_ID(v); //Insert
    UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert

    o.vertex = UnityObjectToClipPos(v.vertex);

    o.uv = v.uv;

    return o;
}

Configurações de qualidade

O Unity fornece predefinições para controlar a qualidade da renderização para cada ponto de extremidade da plataforma. Essas predefinições controlam quais recursos gráficos podem ser habilitados, como sombras, anti-aliasing, iluminação global e muito mais. É recomendável reduzir essas configurações e otimizar o número de cálculos executados durante a renderização.

Etapa 1: Atualizar projetos do Unity de realidade misturada para usar a configuração de nível de Baixa Qualidade
Editar>Configurações do Projeto e, em seguida, selecione a categoria >Qualidade Selecione Baixa Qualidade para a Plataforma UWP

Etapa 2: Para cada arquivo de cena do Unity, desabilite a Iluminação Global em tempo real
Janela>Renderização>Configurações de> iluminaçãoDesmarcar Iluminação Global em Tempo Real

Compartilhamento de buffer de profundidade (HoloLens)

Se estiver desenvolvendo para a plataforma Windows Mixed Reality e, em particular, o HoloLens, habilitar o Compartilhamento de Buffer de Profundidade em Configurações de XR poderá ajudar na estabilização do holograma. No entanto, o processamento do buffer de profundidade pode incorrer em um custo de desempenho, especialmente se estiver usando o formato de profundidade de 24 bits. Portanto, é altamente recomendável configurar o buffer de profundidade para precisão de 16 bits.

Se z-fighting ocorrer devido ao formato de bit inferior, confirme se o plano de clipe distante de todas as câmeras está definido como o menor valor possível para o aplicativo. O Unity, por padrão, define um plano de clipe distante de 1000m. No HoloLens, um plano de clipe distante de 50m geralmente é mais do que suficiente para a maioria dos cenários de aplicativo.

Observação

Se estiver usando o formato de profundidade de 16 bits, os efeitos necessários do buffer de estêncil não funcionarão porque o Unity não criará um buffer de estêncil nessa configuração. Selecionar o formato de profundidade de 24 bits por outro lado geralmente criará um buffer de estêncil de 8 bits, se aplicável na plataforma de gráficos do ponto de extremidade.

Se estiver usando um componente Mask que exija o buffer de estêncil, considere usar RectMask2D , que não requer o buffer de estêncil e, portanto, pode ser usado em conjunto com um formato de profundidade de 16 bits.

Observação

Para determinar rapidamente quais objetos em uma cena não gravam no buffer de profundidade visualmente, é possível usar o utilitário RenderIzar Buffer de Profundidade nas Configurações do Editor no perfil configuração do MRTK.

Otimizar dados de malha

As configurações Otimizar Dados de Malha tentam remover atributos de vértice não utilizados em seu aplicativo. A configuração executa isso executando cada sombreador que passa em cada material que está em cada malha no build. Isso é bom para o tamanho dos dados do jogo e o desempenho do runtime, mas pode dificultar drasticamente os tempos de build.

É recomendável desabilitar essa configuração durante o desenvolvimento e reabilitar durante a criação do build "Mestre". A configuração pode ser encontrada em Editar>Configurações do ProjetoPlayer> Outras >Configurações>Otimizar Dados de Malha.

Recomendações gerais

O desempenho pode ser um desafio ambíguo e em constante mudança para desenvolvedores de realidade misturada e o espectro de conhecimento para racionalizar o desempenho é vasto. No entanto, há algumas recomendações gerais para entender como abordar o desempenho de um aplicativo.

É útil simplificar a execução de um aplicativo nas partes que são executadas na CPU ou na GPU e, portanto, identificar se um aplicativo é limitado por qualquer um dos componentes. Pode haver gargalos que abrangem unidades de processamento e alguns cenários exclusivos que precisam ser investigados cuidadosamente. No entanto, para começar, é bom entender onde um aplicativo está sendo executado durante a maior parte do tempo.

GPU limitada

Como a maioria das plataformas para aplicativos de realidade misturada está utilizando renderização estereoscópica, é muito comum ser limitado à GPU devido à natureza de renderizar uma tela de "largura dupla". Futhermore, plataformas móveis de realidade misturada, como HoloLens ou Oculus Quest, serão limitadas pela CPU de classe móvel & poder de processamento de GPU.

Ao se concentrar na GPU, geralmente há dois estágios importantes que um aplicativo deve concluir cada quadro.

  1. Executar o sombreador de vértice
  2. Executar o sombreador de pixel (também conhecido como sombreador de fragmento)

Sem mergulhar profundamente no complexo campo de computação gráfica & pipelines de renderização, cada estágio de sombreador é um programa executado na GPU para produzir o seguinte.

  1. Sombreadores de vértice transformam vértices de malha em coordenadas no espaço de tela (ou seja, código executado por vértice)
  2. Sombreadores de pixel calculam a cor a ser desenhada para um determinado fragmento de pixel e malha (ou seja, execução de código por pixel)

Em relação ao ajuste de desempenho, geralmente é mais frutífero se concentrar em otimizar as operações no sombreador de pixel. Um aplicativo pode precisar apenas desenhar um cubo que será apenas 8 vértices. No entanto, o espaço de tela que o cubo ocupa provavelmente está na ordem de milhões de pixels. Portanto, reduzir o código do sombreador por exemplo, 10 operações podem economizar significativamente mais trabalho se reduzidas no sombreador de pixel do que o sombreador de vértice.

Essa é uma das principais razões para aproveitar o sombreador Padrão do MRTK , pois esse sombreador geralmente executa muito menos instruções por pixel & vértice do que o sombreador Padrão do Unity, ao mesmo tempo em que alcança resultados estéticos comparáveis.

Otimizações de CPU Otimizações de GPU
Lógica de simulação de aplicativo Operações de renderização
Simplificar a física Reduzir cálculos de iluminação
Simplificar animações Reduzir a contagem de polígonos & nº de objetos desenháveis
Gerenciar Coleta de Lixo Reduzir nº de objetos transparentes
Referências de cache Evitar efeitos pós-processamento/tela inteira

Instanciação de chamada de desenho

Um dos erros mais comuns no Unity que reduz o desempenho é clonar materiais em runtime. Se Os GameObjects compartilharem o mesmo material e/ou forem da mesma malha, eles poderão ser otimizados em chamadas de desenho único por meio de técnicas como envio em lote estático, envio em lote dinâmico e instanciação de GPU. No entanto, se o desenvolvedor modificar propriedades do material de um Renderizador em runtime, o Unity criará uma cópia de clone do material atribuído.

Por exemplo, se houver 100 cubos em uma cena, um desenvolvedor talvez queira atribuir uma cor exclusiva a cada um em runtime. O acesso de renderer.material.color em C# fará com que o Unity crie um novo material na memória para esse renderizador/GameObject específico. Cada um dos 100 cubos terá seu próprio material e, portanto, eles não podem ser mesclados em uma chamada de desenho, mas, em vez disso, se tornarão 100 solicitações de chamada de desenho da CPU para a GPU.

Para superar esse obstáculo e ainda atribuir uma cor exclusiva por cubo, os desenvolvedores devem aproveitar MaterialPropertyBlock.

private PropertyBlock m_PropertyBlock ;
private Renderer myRenderer;

private void Start()
{
     myRenderer = GetComponent<Renderer>();
     m_PropertyBlock = new MaterialPropertyBlock();
}

private void ChangeColor()
{
    // Creates a copy of the material once for this renderer
    myRenderer.material.color = Color.red;

    // vs.

    // Retains instancing capability for renderer
    m_PropertyBlock.SetColor("_Color", Color.red);
    myRenderer.SetPropertyBlock(m_PropertyBlock);
}

Ferramentas de desempenho do Unity

O Unity fornece ótimas ferramentas de desempenho incorporadas ao editor.

Se estimar a compensação de desempenho aproximada entre um sombreador e outro, será útil compilar cada sombreador e exibir o número de operações por estágio de sombreador. Isso pode ser feito selecionando um ativo de sombreador e clicando no botão Compilar e mostrar código . Isso compilará todas as variantes do sombreador e abrirá o Visual Studio com os resultados. Observação: os resultados da estatística produzidos podem variar dependendo de quais recursos foram habilitados em materiais que utilizam o sombreador especificado. O Unity compilará apenas as variantes de sombreador que estão sendo usadas diretamente no projeto atual.

Exemplo de estatísticas de sombreador Padrão do Unity

Estatísticas de sombreador padrão do Unity 1

Exemplo de estatísticas de sombreador padrão do MRTK

Estatísticas de sombreador padrão do MRTK 2

Confira também

Unity

Windows Mixed Reality

Oculus

Otimização de malha