Desempenho — MRTK2

Introdução

A forma mais fácil de racionalizar o desempenho é através do framerate ou do número de vezes que a sua aplicação pode compor uma imagem por segundo. É importante cumprir a taxa de fotogramas de destino, conforme descrito pela plataforma que está a ser direcionada (ou seja, Windows Mixed Reality, Oculus, etc.). Por exemplo, no HoloLens, a taxa de fotogramas de destino é de 60 FPS. As aplicações de baixa taxa de framerate podem resultar numa deterioração das experiências dos utilizadores, como o agravamento da estabilização do holograma, o controlo do mundo, o controlo manual e muito mais. Para ajudar os programadores a controlar e a alcançar uma taxa de fotogramas de qualidade, o Mixed Reality Toolkit fornece uma variedade de ferramentas e scripts.

Gerador de perfis visuais

Para controlar continuamente o desempenho ao longo da duração do desenvolvimento, é altamente recomendado mostrar sempre um elemento visual de taxa de fotogramas durante a execução & depuração de uma aplicação. Mixed Reality Toolkit fornece a ferramenta de diagnóstico do Visual Profiler que fornece informações em tempo real sobre o FPS atual e a utilização da memória na vista de aplicação. O Visual Profiler pode ser configurado através das Definições do Sistema de Diagnóstico noInspetor de Perfis do MRTK.

Além disso, é particularmente importante utilizar o Visual Profiler para controlar a taxa de frames quando está em execução no dispositivo em vez de ser executado no editor do Unity ou num emulador. Os resultados de desempenho mais precisos serão representados ao executar no dispositivo com compilações de configuração de versão.

Nota

Se criar para Windows Mixed Reality, implemente com compilações de configuração MASTER.

Visual Profiler Interface

Janela Otimizar

A Janela de Otimização do MRTK oferece ferramentas de informação e automatização para ajudar os programadores de realidade mista a configurar o seu ambiente para obter os melhores resultados de desempenho e identificar potenciais estrangulamentos na sua cena & recursos. Determinadas configurações principais no Unity podem ajudar a fornecer resultados substancialmente mais otimizados para projetos de realidade mista.

Geralmente, estas definições envolvem a composição de configurações ideais para a realidade mista. As aplicações de realidade mista são exclusivas em comparação com o desenvolvimento de gráficos 3D tradicional, na qual existem dois ecrãs (ou seja, dois olhos) para compor para toda a cena.

As definições recomendadas referenciadas abaixo podem ser configuradas automaticamente num projeto do Unity ao tirar partido da Janela de Otimização do MRTK.

Definições da Janela de Otimização do MRTK

Unity Profiler

O Unity Profiler é uma ferramenta útil para investigar detalhes do desempenho da aplicação ao nível da moldura.

Tempo gasto na CPU

Exemplo do Unity Profiler Graph

Para manter taxas de fotogramas confortáveis (normalmente 60 fotogramas por segundo), as aplicações têm de atingir um período máximo de 16,6 milissegundos de tempo de CPU. Para ajudar a identificar o custo da funcionalidade MRTK, o Microsoft Mixed Reality Toolkit contém marcadores para caminhos de código de ciclo interno (por frame). Estes marcadores utilizam o seguinte formato para ajudar a compreender a funcionalidade específica que está a ser utilizada:

[MRTK] className.methodName

Nota

Podem existir dados adicionais a seguir ao nome do método. Isto é utilizado para identificar funcionalidades potencialmente dispendiosas executadas condicionalmente que podem ser evitadas por pequenas alterações ao código da aplicação.

Hierarquia do Unity Profiler de exemplo

Neste exemplo, a hierarquia foi expandida para mostrar que o método UpdateHandData da classe WindowsMixedRealityArticulatedHand está a consumir 0,44 ms de tempo de CPU durante a análise do fotograma. Estes dados podem ser utilizados para ajudar a determinar se um problema de desempenho está relacionado com o código da aplicação ou noutros locais do sistema.

É altamente recomendado que os programadores instrumentem o código da aplicação de forma semelhante. As principais áreas de foco para a instrumentação do código da aplicação estão dentro dos processadores de eventos, uma vez que estes métodos são cobrados ao ciclo de atualização do MRTK à medida que os eventos são gerados. Os tempos de fotograma elevados no ciclo de atualização do MRTK podem ser indicativos de código dispendioso em métodos de processador de eventos.

Single-Pass Composição de Instâncias

A configuração de composição predefinida para XR no Unity é Multi-pass. Esta definição instrui o Unity a executar todo o pipeline de composição duas vezes, uma para cada olho. Isto pode ser otimizado ao selecionar composição de Instâncias de Passagem Única . Esta configuração tira partido das matrizes de destino de composição para poder efetuar uma única chamada de desenho que as instâncias no destino de composição adequado para cada olho. Além disso, este modo permite que todas as composiçãos sejam efetuadas numa única execução do pipeline de composição. Assim, selecionar a composição de Instâncias de Passagem Única como o caminho de composição de uma aplicação de realidade mista pode poupar tempo substancial tanto na CPU & GPU como na configuração de composição recomendada.

No entanto, para emitir uma única chamada de desenho para cada malha para cada olho, o instancing de GPU tem de ser suportado por todos os sombreados. O instancing permite que a GPU desenhe chamadas multiplex em ambos os olhos. Por predefinição, os sombreados incorporados do Unity, bem como o sombreado Padrão do MRTK , contêm as instruções de instancagem necessárias no código shader. No entanto, se escrever sombreados personalizados para o Unity, estes sombreados poderão ter de ser atualizados para suportar a composição de Instâncias de Passagem Única.

Código de Exemplo para o Shader 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;
}

Definições de qualidade

O Unity fornece predefinições para controlar a qualidade da composição para cada ponto final da plataforma. Estas predefinições controlam que funcionalidades gráficas podem ser ativadas, como sombras, antialiasing, iluminação global e muito mais. Recomenda-se reduzir estas definições e otimizar o número de cálculos efetuados durante a composição.

Passo 1: Atualizar projetos do Unity de realidade mista para utilizar a definição de nível de Baixa Qualidade
Editar>Definições do Projeto e, em seguida, selecione a categoria >Qualidade Selecionar Baixa Qualidade para a Plataforma UWP

Passo 2: Para cada ficheiro de cena do Unity, desative a Iluminação Global em tempo real
Janela>> ComposiçãoDefinições> de IluminaçãoDesmarcar a Iluminação Global em Tempo Real

Partilha de memória intermédia de profundidade (HoloLens)

Se desenvolver para a plataforma Windows Mixed Reality e, em particular, para o HoloLens, ativar a Partilha de Memória Intermédia de Profundidade em Definições XR pode ajudar na estabilização do holograma. No entanto, o processamento da memória intermédia de profundidade pode incorrer num custo de desempenho, especialmente se utilizar o formato de profundidade de 24 bits. Assim, é altamente recomendado configurar a memória intermédia de profundidade para uma precisão de 16 bits.

Se o z-fighting ocorrer devido ao formato de bit inferior, confirme se o plano de recortação mais distante de todas as câmaras está definido para o valor mais baixo possível para a aplicação. Por predefinição, o Unity define um plano de transferência de 1000 m. No HoloLens, um plano de transferência de 50 m é geralmente mais do que suficiente para a maioria dos cenários de aplicações.

Nota

Se utilizar o formato de profundidade de 16 bits, os efeitos necessários para a memória intermédia de stencil não funcionarão porque o Unity não cria uma memória intermédia de stencil nesta definição. Selecionar o formato de profundidade de 24 bits inversamente irá geralmente criar uma memória intermédia de stencil de 8 bits, se aplicável na plataforma de gráficos de ponto final.

Se utilizar um componente mask que requer a memória intermédia do stencil, considere utilizar RectMask2D , o que não requer a memória intermédia do stencil e, portanto, pode ser utilizado em conjunto com um formato de profundidade de 16 bits.

Nota

Para determinar rapidamente que objetos numa cena não escrevem na memória intermédia de profundidade visualmente, pode-se utilizar o utilitário Memória Intermédia de Profundidade de Composição nas Definições do Editor no perfil de Configuração do MRTK.

Otimizar Dados do Mesh

As definições Otimizar Dados do Mesh tentam remover atributos de vértice não utilizados na sua aplicação. A definição efetua esta ação ao executar todos os passos de sombreador em todos os materiais que estão em todas as malhas da compilação. Isto é bom para o tamanho dos dados dos jogos e o desempenho do runtime, mas pode dificultar drasticamente os tempos de compilação.

É recomendado desativar esta definição durante o desenvolvimento e reativar durante a criação da compilação "Master". A definição pode ser encontrada em Editar>Definições> doProjeto Leitor>Outras Definições>Otimizar Dados de Malha.

Recomendações gerais

O desempenho pode ser um desafio ambíguo e em constante mudança para os programadores de realidade mista e o espectro de conhecimento para racionalizar o desempenho é vasto. No entanto, existem algumas recomendações gerais para compreender como abordar o desempenho de uma aplicação.

É útil simplificar a execução de uma aplicação nas partes que são executadas na CPU ou na GPU e, assim, identificar se uma aplicação está vinculada por qualquer um dos componentes. Podem existir estrangulamentos que abrangem unidades de processamento e alguns cenários exclusivos que têm de ser cuidadosamente investigados. No entanto, para começar, é bom perceber onde é que uma aplicação está a ser executada durante a maior parte do tempo.

GPU delimitada

Uma vez que a maioria das plataformas para aplicações de realidade mista está a utilizar composição estereoscópica, é muito comum estar vinculada à GPU devido à natureza de compor um ecrã "de duas larguras". Futhermore, as plataformas de realidade mista móvel, como o HoloLens ou o Oculus Quest, serão limitadas pela CPU de classe móvel & poder de processamento da GPU.

Ao concentrar-se na GPU, geralmente existem duas fases importantes em que uma aplicação tem de concluir cada frame.

  1. Executar o sombreado de vértice
  2. Execute o sombreado de píxeis (também conhecido como o sombreado de fragmento)

Sem mergulhar profundamente no campo complexo de gráficos de computador & pipelines de composição, cada fase de sombreador é um programa que é executado na GPU para produzir o seguinte.

  1. Os sombreados de vértices transformam vértices de malha em coordenadas no espaço no ecrã (ou seja, código executado por vértice)
  2. Os sombreados de píxeis calculam a cor a desenhar para um determinado fragmento de pixel e malha (ou seja, execução de código por pixel)

No que diz respeito à otimização do desempenho, é geralmente mais frutífero concentrar-se na otimização das operações no sombreado de pixels. Uma aplicação só poderá ter de desenhar um cubo que terá apenas 8 vértices. No entanto, o espaço no ecrã que o cubo ocupa é provavelmente na ordem de milhões de píxeis. Desta forma, a redução do código de sombreado, por exemplo, 10 operações pode poupar significativamente mais trabalho se for reduzida no tom de pixel do que o sombreado de vértice.

Esta é uma das principais razões para tirar partido do tom padrão do MRTK, uma vez que este sombreador geralmente executa muito menos instruções por pixel & vértice do que o tom do Unity Standard, ao mesmo tempo que alcança resultados estéticos comparáveis.

Otimizações da CPU Otimizações da GPU
Lógica de simulação de aplicações Operações de composição
Simplificar a Física Reduzir os cálculos de iluminação
Simplificar Animações Reduzir a contagem de polígonos & n.º de objetos graváveis
Gerir a Libertação de Lixo Reduzir o número de objetos transparentes
Referências da Cache Evitar efeitos pós-processamento/ecrã inteiro

Desenhar instancing de chamadas

Um dos erros mais comuns no Unity que reduz o desempenho é clonar materiais no runtime. Se os GameObjects partilharem o mesmo material e/ou forem a mesma malha, podem ser otimizados para chamadas de desenho único através de técnicas como lotes estáticos, criação de lotes dinâmicos e Instancing de GPU. No entanto, se o programador modificar as propriedades do material de um Renderer no runtime, o Unity criará uma cópia clone do material atribuído.

Por exemplo, se existirem 100 cubos numa cena, um programador poderá querer atribuir uma cor exclusiva a cada um no runtime. O acesso de renderer.material.color em C# fará com que o Unity crie um novo material na memória para este compositor/GameObject específico. Cada um dos 100 cubos terá o seu próprio material e, portanto, não podem ser intercalados numa única chamada de sorteio, mas tornar-se-ão 100 pedidos de chamada de desenho da CPU para a GPU.

Para ultrapassar este obstáculo e ainda atribuir uma cor exclusiva por cubo, os programadores devem tirar partido de 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 excelentes ferramentas de desempenho incorporadas no editor.

Se estimar a troca de desempenho aproximada entre um sombreado e outro, é útil compilar cada sombreado e ver o número de operações por fase de sombreador. Isto pode ser feito ao selecionar um recurso de sombreado e clicar no botão Compilar e mostrar código . Isto irá compilar todas as variantes do shader e abrir o Visual Studio com os resultados. Nota: os resultados estatísticos produzidos podem variar consoante as funcionalidades que foram ativadas nos materiais que utilizam o sombreado especificado. O Unity compilará apenas as variantes de sombreado que estão a ser utilizadas diretamente no projeto atual.

Exemplo de estatísticas de sombreado do Unity Standard

Estatísticas de Sombreado Padrão do Unity 1

Exemplo de estatísticas de sombreado Padrão do MRTK

Estatísticas de Sombreado Padrão do MRTK 2

Ver também

Unity

Windows Mixed Reality

Oculus

Otimização da malha