Partilhar via


Recomendações de desempenho para Unity

Este artigo baseia-se nas recomendações de desempenho para realidade mista, mas se concentra em melhorias específicas do Unity.

Recentemente, lançamos um aplicativo chamado Quality Fundamentals que aborda problemas comuns de desempenho, design e ambiente e soluções para aplicativos HoloLens 2. Este aplicativo é uma ótima demonstração visual para o conteúdo que se segue.

O primeiro passo mais importante ao otimizar o desempenho de aplicativos de realidade mista no Unity é ter certeza de que você está usando as configurações de ambiente recomendadas para o Unity. Esse artigo contém conteúdo com algumas das configurações de cena mais importantes para a criação de aplicativos de Realidade Mista de alto desempenho. Algumas dessas configurações recomendadas também são destacadas abaixo.

Como criar um perfil com Unity

O Unity fornece o Unity Profiler integrado, que é um ótimo recurso para reunir informações valiosas de desempenho para seu aplicativo específico. Embora você possa executar o criador de perfil no editor, essas métricas não representam o verdadeiro ambiente de tempo de execução, portanto, os resultados devem ser usados com cautela. Recomendamos que você crie o perfil do seu aplicativo remotamente enquanto executa no dispositivo para obter informações mais precisas e acionáveis.

Unity fornece excelente documentação para:

  1. Como conectar o criador de perfil Unity a aplicativos UWP remotamente
  2. Como diagnosticar eficazmente problemas de desempenho com o Unity Profiler

Criação de perfil de GPU

Criador de perfil Unity

Com o Unity Profiler conectado e depois de adicionar o criador de perfil GPU (consulte Adicionar criador de perfil no canto superior direito), pode-se ver quanto tempo está sendo gasto na CPU e GPU, respectivamente, no meio do criador de perfil. Isso permite que o desenvolvedor obtenha uma aproximação rápida se seu aplicativo for limitado por CPU ou GPU.

Unidade CPU vs GPU

Nota

Para usar a criação de perfil da GPU, você precisa desativar os trabalhos gráficos nas Configurações do Unity Player. Consulte o módulo GPU Usage Profiler do Unity para obter mais detalhes.

Depurador de quadros Unity

O Depurador de Quadros do Unity também é uma ferramenta poderosa e perspicaz para usar. Ele lhe dará uma boa visão geral do que a GPU está fazendo em cada quadro. Coisas a observar são alvos de renderização adicionais e comandos blit para copiar entre eles, pois estes são muito caros no HoloLens. Idealmente, nenhum alvo de renderização fora da tela deve ser usado no HoloLens. Estes são geralmente adicionados ao habilitar recursos de renderização caros (por exemplo, MSAA, HDR ou efeitos de tela cheia como bloom) que devem ser evitados.

Sobreposição da taxa de quadros HoloLens

A página Device Portal System Performance tem um bom resumo do desempenho da CPU e GPU do dispositivo. Você pode ativar o contador de taxa de quadros de exibição no fone de ouvido e o gráfico de taxa de quadros de exibição no fone de ouvido. Essas opções habilitarão um contador e um gráfico de FPS, respectivamente, que lhe darão feedback imediato em qualquer aplicativo em execução no seu dispositivo.

PIX

O PIX também pode ser usado para criar perfis de aplicativos Unity. Há também instruções detalhadas sobre como usar e instalar o PIX para HoloLens 2. Em uma compilação de desenvolvimento, os mesmos escopos que você vê no Depurador de quadros do Unity também serão mostrados no PIX e podem ser inspecionados e perfilados com mais detalhes.

Nota

Unity fornece a capacidade de modificar facilmente a resolução de destino de renderização de seu aplicativo em tempo de execução por meio da propriedade XRSettings.renderViewportScale. A imagem final apresentada no dispositivo tem uma resolução fixa. A plataforma fará uma amostra da saída de resolução mais baixa para construir uma imagem de resolução mais alta para renderização em displays.

UnityEngine.XR.XRSettings.renderViewportScale = 0.7f;

Recomendações de desempenho da CPU

O conteúdo abaixo aborda práticas de desempenho mais detalhadas, especialmente direcionadas para o desenvolvimento de Unity & C#.

Referências de cache

Recomendamos armazenar em cache referências a todos os componentes relevantes e GameObjects na inicialização porque chamadas de função repetidas como GetComponent<T>() e Camera.main são mais caras em relação ao custo de memória para armazenar um ponteiro. . Camera.main usa apenas FindGameObjectsWithTag() por baixo, que pesquisa caro seu gráfico de cena para um objeto de câmera com a tag "MainCamera".

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    private Camera cam;
    private CustomComponent comp;

    void Start() 
    {
        cam = Camera.main;
        comp = GetComponent<CustomComponent>();
    }

    void Update()
    {
        // Good
        this.transform.position = cam.transform.position + cam.transform.forward * 10.0f;

        // Bad
        this.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 10.0f;

        // Good
        comp.DoSomethingAwesome();

        // Bad
        GetComponent<CustomComponent>().DoSomethingAwesome();
    }
}

Nota

Evite GetComponent(string)
Ao usar GetComponent(), há um punhado de sobrecargas diferentes. É importante sempre usar as implementações baseadas em tipo e nunca a sobrecarga de pesquisa baseada em string. Pesquisar por string em sua cena é significativamente mais caro do que pesquisar por tipo.
(Bom) Componente GetComponent(Tipo de tipo)
(Bom) T GetComponent<T>()
(Ruim) Componente GetComponent(string)>

Evite operações dispendiosas

  1. Evite o uso de LINQ

    Embora o LINQ possa ser limpo e fácil de ler e escrever, geralmente requer mais computação e memória do que se você escrevesse o algoritmo manualmente.

    // Example Code
    using System.Linq;
    
    List<int> data = new List<int>();
    data.Any(x => x > 10);
    
    var result = from x in data
                 where x > 10
                 select x;
    
  2. APIs comuns do Unity

    Certas APIs Unity, embora úteis, podem ser caras de executar. A maioria deles envolve a pesquisa de todo o seu gráfico de cena para alguma lista correspondente de GameObjects. Essas operações geralmente podem ser evitadas armazenando referências em cache ou implementando um componente gerenciador para que o GameObjects rastreie as referências em tempo de execução.

        GameObject.SendMessage()
        GameObject.BroadcastMessage()
        UnityEngine.Object.Find()
        UnityEngine.Object.FindWithTag()
        UnityEngine.Object.FindObjectOfType()
        UnityEngine.Object.FindObjectsOfType()
        UnityEngine.Object.FindGameObjectsWithTag()
        UnityEngine.Object.FindGameObjectsWithTag()
    

Nota

SendMessage() e BroadcastMessage() devem ser eliminados a todo custo. Estas funções podem ser da ordem de 1000x mais lentas do que as chamadas de função diretas.

  1. Cuidado com o boxe

    Boxe é um conceito central da linguagem C# e tempo de execução. É o processo de encapsular variáveis digitadas por valor, como char, int, bool, etc., em variáveis de tipo de referência. Quando uma variável de valor digitado é "encaixotada", ela é encapsulada em um System.Object, que é armazenado no heap gerenciado. A memória é alocada e, eventualmente, quando descartada, deve ser processada pelo coletor de lixo. Essas alocações e deallocations incorrem em um custo de desempenho e, em muitos cenários, são desnecessárias ou podem ser facilmente substituídas por uma alternativa menos dispendiosa.

    Para evitar boxes, certifique-se de que as variáveis, campos e propriedades nas quais você armazena tipos numéricos e estruturas (incluindo Nullable<T>) sejam fortemente tipados como tipos específicos, como int, float? ou MyStruct, em vez de usar objeto. Se colocar esses objetos em uma lista, certifique-se de usar uma lista fortemente tipada, como List<int> em vez de List<object> ou ArrayList.

    Exemplo de boxe em C#

    // boolean value type is boxed into object boxedMyVar on the heap
    bool myVar = true;
    object boxedMyVar = myVar;
    

Repetindo caminhos de código

Qualquer repetição de funções de retorno de chamada Unity (ou seja, Atualização) que são executadas muitas vezes por segundo e/ou quadro deve ser escrita cuidadosamente. Quaisquer operações dispendiosas aqui terão um impacto enorme e consistente no desempenho.

  1. Funções de retorno de chamada vazias

    Embora o código abaixo possa parecer inocente para deixar em seu aplicativo, especialmente porque cada script Unity é inicializado automaticamente com um método Update, esses retornos de chamada vazios podem se tornar caros. Unity opera entre um limite de código não gerenciado e gerenciado, entre o código UnityEngine e o código do seu aplicativo. A mudança de contexto nesta ponte é bastante cara, mesmo que não haja nada para executar. Isso se torna especialmente problemático se seu aplicativo tiver 100s de GameObjects com componentes que têm retornos de chamada Unity repetidos vazios.

    void Update()
    {
    }
    

Nota

Update() é a manifestação mais comum desse problema de desempenho, mas outros retornos de chamada Unity repetidos, como os seguintes, podem ser igualmente ruins, se não piores: FixedUpdate(), LateUpdate(), OnPostRender", OnPreRender(), OnRenderImage(), etc.

  1. Operações para favorecer a execução uma vez por quadro

    As APIs Unity a seguir são operações comuns para muitos aplicativos holográficos. Embora nem sempre seja possível, os resultados dessas funções geralmente podem ser calculados uma vez e os resultados reutilizados em todo o aplicativo para um determinado quadro.

    a) É uma boa prática ter uma classe ou serviço Singleton dedicado para lidar com seu olhar Raycast para a cena e, em seguida, reutilizar esse resultado em todos os outros componentes da cena, em vez de fazer operações Raycast repetidas e idênticas por cada componente. Algumas aplicações podem exigir raycasts de origens diferentes ou contra LayerMasks diferentes.

        UnityEngine.Physics.Raycast()
        UnityEngine.Physics.RaycastAll()
    

    b) Evite operações GetComponent() em retornos de chamada repetidos do Unity, como Update(), armazenando em cache referências em Start() ou Awake()

        UnityEngine.Object.GetComponent()
    

    c) É uma boa prática instanciar todos os objetos, se possível, na inicialização e usar o pool de objetos para reciclar e reutilizar GameObjects durante todo o tempo de execução do seu aplicativo

        UnityEngine.Object.Instantiate()
    
  2. Evite interfaces e construções virtuais

    Invocar chamadas de função através de interfaces vs objetos diretos ou chamar funções virtuais pode muitas vezes ser muito mais caro do que usar construções diretas ou chamadas diretas de função. Se a função virtual ou interface é desnecessária, então ela deve ser removida. No entanto, o impacto no desempenho dessas abordagens vale a pena se usá-las simplificar a colaboração no desenvolvimento, a legibilidade do código e a capacidade de manutenção do código.

    Geralmente, a recomendação é não marcar campos e funções como virtuais, a menos que haja uma expectativa clara de que esse membro precise ser substituído. Deve-se ter um cuidado especial em torno de caminhos de código de alta frequência que são chamados muitas vezes por quadro ou até mesmo uma vez por quadro, como um UpdateUI() método.

  3. Evite passar structs por valor

    Ao contrário das classes, structs são tipos de valor e, quando passados diretamente para uma função, seu conteúdo é copiado para uma instância recém-criada. Esta cópia adiciona o custo da CPU, bem como memória adicional na pilha. Para estruturas pequenas, o efeito é mínimo e, portanto, aceitável. No entanto, para funções invocadas repetidamente cada quadro, bem como funções que tomam grandes estruturas, se possível, modifique a definição de função para passar por referência. Saiba mais aqui

Diversos

  1. Física

    a) Geralmente, a maneira mais fácil de melhorar a física é limitar a quantidade de tempo gasto em Física ou o número de iterações por segundo. Isso reduzirá a precisão da simulação. Veja o TimeManager em Unity

    b) Os tipos de colisores em Unity têm características de desempenho muito diferentes. A ordem abaixo lista os colisores com melhor desempenho para os colisores com menor desempenho da esquerda para a direita. É importante evitar os Colliders de Malha, que são substancialmente mais caros do que os Colliders Primitivos.

    Malha de caixa <<< de cápsula < esférica < (convexa) < Malha (não convexa)

    Consulte Unity Physics Best Practices para obter mais informações

  2. Animações

    Desative animações ociosas desativando o componente Animador (desativar o objeto de jogo não terá o mesmo efeito). Evite padrões de design em que um animador se senta em um loop definindo um valor para a mesma coisa. Há uma sobrecarga considerável para esta técnica, sem efeito na aplicação. Saiba mais aqui.

  3. Algoritmos complexos

    Se o seu aplicativo estiver usando algoritmos complexos, como cinemática inversa, localização de caminhos, etc., procure encontrar uma abordagem mais simples ou ajuste as configurações relevantes para seu desempenho

Recomendações de desempenho de CPU para GPU

Geralmente, o desempenho de CPU para GPU se resume às chamadas de desenho enviadas para a placa gráfica. Para melhorar o desempenho, as chamadas de desenho precisam ser estrategicamente a) reduzidas ou b) reestruturadas para obter os melhores resultados. Uma vez que as chamadas de sorteio em si são intensivas em recursos, reduzi-las reduzirá o trabalho geral necessário. Além disso, as alterações de estado entre as chamadas de desenho exigem etapas dispendiosas de validação e tradução no driver gráfico e, portanto, a reestruturação das chamadas de desenho do seu aplicativo para limitar as alterações de estado (ou seja, materiais diferentes, etc.) pode aumentar o desempenho.

Unity tem um ótimo artigo que dá uma visão geral e mergulha em chamadas de sorteio em lote para sua plataforma.

Renderização com instância de passagem única

A renderização de instância de passagem única no Unity permite que as chamadas de desenho para cada olho sejam reduzidas a uma chamada de sorteio de instância. Devido à coerência do cache entre duas chamadas de desenho, também há alguma melhoria de desempenho na GPU.

Para habilitar esse recurso em seu projeto Unity

  1. Abra Configurações do OpenXR (vá para Editar>Configurações do>Projeto XR Plugin Management>OpenXR).
  2. Selecione Single Pass Instanced no menu suspenso Modo de renderização.

Leia os seguintes artigos do Unity para obter detalhes sobre essa abordagem de renderização.

Nota

Um problema comum com a renderização de instância de passagem única ocorre se os desenvolvedores já tiverem sombreadores personalizados existentes não escritos para substituição. Depois de ativar esse recurso, os desenvolvedores podem notar que alguns GameObjects são renderizados apenas em um olho. Isso ocorre porque os sombreadores personalizados associados não têm as propriedades apropriadas para instancing.

Processamento em lote estático

Unity é capaz de agrupar muitos objetos estáticos para reduzir chamadas de desenho para a GPU. O Processamento em lote estático funciona para a maioria dos objetos do renderizador no Unity que 1) compartilham o mesmo material e 2) são todos marcados como estáticos (Selecione um objeto no Unity e marque a caixa de seleção no canto superior direito do inspetor). Os GameObjects marcados como estáticos não podem ser movidos durante todo o tempo de execução do aplicativo. Assim, o processamento em lote estático pode ser difícil de aproveitar no HoloLens, onde praticamente todos os objetos precisam ser colocados, movidos, dimensionados, etc. Para fones de ouvido imersivos, o processamento em lote estático pode reduzir drasticamente as chamadas de atração e, assim, melhorar o desempenho.

Leia Lote estático em Desenhar lote de chamadas no Unity para obter mais detalhes.

Processamento dinâmico em lote

Como é problemático marcar objetos como estáticos para o desenvolvimento do HoloLens, o processamento dinâmico em lote pode ser uma ótima ferramenta para compensar esse recurso ausente. Também pode ser útil em fones de ouvido imersivos. No entanto, o processamento dinâmico em lote no Unity pode ser difícil de habilitar porque o GameObjects deve a) compartilhar o mesmo Material e b) atender a uma longa lista de outros critérios.

Leia Dynamic Batching em Draw Call Batching in Unity para obter a lista completa. Mais comumente, GameObjects tornam-se inválidos para serem agrupados dinamicamente, porque os dados de malha associados não podem ser mais de 300 vértices.

Outras técnicas

O processamento em lote só pode ocorrer se vários GameObjects puderem compartilhar o mesmo material. Normalmente, isso será bloqueado pela necessidade de GameObjects ter uma textura única para seu respetivo Material. É comum combinar texturas em uma grande textura, um método conhecido como atlas de textura.

Além disso, é preferível combinar malhas em um GameObject sempre que possível e razoável. Cada renderizador no Unity terá sua(s) chamada(s) de desenho associada(s) em vez de enviar uma malha combinada em um renderizador.

Nota

Modificar as propriedades de Renderer.material em tempo de execução criará uma cópia do Material e, portanto, potencialmente quebrará o lote. Use Renderer.sharedMaterial para modificar as propriedades do material compartilhado em GameObjects.

Recomendações de desempenho da GPU

Saiba mais sobre como otimizar a renderização de gráficos no Unity

Largura de banda e taxas de preenchimento

Ao renderizar um quadro na GPU, um aplicativo é vinculado pela largura de banda da memória ou pela taxa de preenchimento.

  • A largura de banda da memória é a taxa de leituras e gravações que a GPU pode fazer a partir da memória
    • No Unity, altere a Qualidade da textura em Editar>configurações do> projeto.
  • A taxa de preenchimento refere-se aos pixels que podem ser desenhados por segundo pela GPU.
    • Em Unity, use a propriedade XRSettings.renderViewportScale.

Otimize o compartilhamento de buffer de profundidade

Recomendamos que você habilite o compartilhamento de buffer de profundidade para otimizar a estabilidade do holograma. Ao habilitar a reprojeção de estágio avançado baseada em profundidade com essa configuração, recomendamos que você selecione o formato de profundidade de 16 bits em vez do formato de profundidade de 24 bits . Os buffers de profundidade de 16 bits reduzirão drasticamente a largura de banda (e, portanto, a energia) associada ao tráfego do buffer de profundidade. Isso pode ser uma grande melhoria tanto na redução de potência quanto no desempenho. No entanto, há dois resultados negativos possíveis usando o formato de profundidade de 16 bits.

Z-Luta

A fidelidade reduzida da faixa de profundidade torna o combate z mais provável de ocorrer com 16 bits do que com 24 bits. Para evitar esses artefatos, modifique os planos de clipe próximo/distante da câmera Unity para levar em conta a menor precisão. Para aplicações baseadas em HoloLens, um plano de clipe distante de 50 m em vez dos 1000 m padrão do Unity geralmente pode eliminar qualquer luta z.

Buffer de estêncil desativado

Quando o Unity cria uma textura de renderização com profundidade de 16 bits, não há nenhum buffer de estêncil criado. Selecionar o formato de profundidade de 24 bits, conforme descrito na documentação do Unity, criará um z-buffer de 24 bits e um buffer de estêncil de 8 bits (se 32 bits for aplicável em um dispositivo (por exemplo, o HoloLens), o que geralmente é o caso).

Evite efeitos de tela cheia

Técnicas que operam em tela cheia podem ser caras, já que sua ordem de grandeza é de milhões de operações a cada quadro. Recomenda-se evitar efeitos pós-processamento, como anti-aliasing, bloom e muito mais.

Ótimas definições de iluminação

A iluminação global em tempo real em Unity pode fornecer excelentes resultados visuais, mas envolve cálculos de iluminação caros. Recomendamos desativar a Iluminação Global em tempo real para cada arquivo de cena Unity por meio das Configurações de Iluminação de Renderização de Janelas>>Desmarque a Iluminação Global em Tempo Real.>

Além disso, recomenda-se desativar toda a transmissão de sombras, pois elas também adicionam GPU cara para uma cena Unity. As sombras podem ser desativadas por luz, mas também podem ser controladas de forma holística através das definições de qualidade.

Edite>as configurações do projeto e selecione a categoria > Qualidade Selecione Baixa qualidade para a plataforma UWP. Também é possível definir a propriedade Shadows como Disable Shadows.

Recomendamos que você use iluminação assada com seus modelos em Unity.

Reduzir a contagem de poli

A contagem de polígonos é reduzida em

  1. Removendo objetos de uma cena
  2. Dizimação de ativos, que reduz o número de polígonos para uma determinada malha
  3. Implementando um sistema de nível de detalhe (LOD) em seu aplicativo, que renderiza objetos distantes com a versão de polígono inferior da mesma geometria

Noções básicas sobre sombreadores no Unity

Uma aproximação fácil para comparar sombreadores no desempenho é identificar o número médio de operações que cada um executa em tempo de execução. Isso pode ser feito facilmente em Unity.

  1. Selecione seu ativo de sombreador ou selecione um material e, em seguida, no canto superior direito da janela do inspetor, selecione o ícone de engrenagem seguido de "Select Shader"

    Selecionar sombreador no Unity

  2. Com o ativo de sombreador selecionado, selecione o botão "Compilar e mostrar código" na janela do inspetor

    Compilar código de sombreador no Unity

  3. Depois de compilar, procure a seção de estatísticas nos resultados com o número de operações diferentes para o sombreador de vértice e pixel (Nota: sombreadores de pixel são muitas vezes também chamados de sombreadores de fragmento)

    Operações de sombreamento padrão Unity

Otimizar sombreadores de pixel

Observando os resultados estatísticos compilados usando o método acima, o sombreador de fragmento geralmente executará mais operações do que o sombreador de vértice, em média. O sombreador de fragmento, também conhecido como sombreador de pixel, é executado por pixel na saída da tela, enquanto o sombreador de vértice é executado apenas por vértice de todas as malhas que estão sendo desenhadas para a tela.

Assim, não só os sombreadores de fragmento têm mais instruções do que os sombreadores de vértice por causa de todos os cálculos de iluminação, os sombreadores de fragmento são quase sempre executados em um conjunto de dados maior. Por exemplo, se a saída da tela for uma imagem de 2k por 2k, o sombreador de fragmento pode ser executado 2.000*2.000 = 4.000.000 vezes. Se renderizar dois olhos, esse número dobra, já que há duas telas. Se um aplicativo de realidade mista tiver várias passagens, efeitos de pós-processamento em tela cheia ou renderização de várias malhas para o mesmo pixel, esse número aumentará drasticamente.

Portanto, reduzir o número de operações no sombreador de fragmento geralmente pode proporcionar ganhos de desempenho muito maiores em relação às otimizações no sombreador de vértice.

Alternativas de sombreador Unity Standard

Em vez de usar uma renderização baseada fisicamente (PBR) ou outro sombreador de alta qualidade, procure utilizar um sombreador mais eficiente e mais barato. O Mixed Reality Toolkit fornece o sombreador padrão MRTK que foi otimizado para projetos de realidade mista.

Unity também fornece um sombreador apagado, iluminado por vértice, difuso e outras opções de sombreador simplificado que são mais rápidas em comparação com o sombreador Unity Standard. Consulte Uso e desempenho de sombreadores integrados para obter informações mais detalhadas.

Pré-carregamento do sombreador

Use o pré-carregamento do sombreador e outros truques para otimizar o tempo de carregamento do sombreador. Em particular, o pré-carregamento do sombreador significa que você não verá nenhum problema devido à compilação do sombreador em tempo de execução.

Limite de extração

No Unity, pode-se exibir o desenho excessivo para sua cena, alternando o menu do modo de desenho no canto superior esquerdo da visualização Cena e selecionando Desenhar.

Geralmente, o overdraw pode ser atenuado pelo abate de objetos com antecedência antes de serem enviados para a GPU. Unity fornece detalhes sobre a implementação do Occlusion Culling para seu motor.

Recomendações de memória

Alocação excessiva de memória e operações de desalocação podem ter efeitos adversos em seu aplicativo holográfico, resultando em desempenho inconsistente, quadros congelados e outros comportamentos prejudiciais. É especialmente importante entender as considerações de memória ao desenvolver no Unity, já que o gerenciamento de memória é controlado pelo coletor de lixo.

Recolha de lixo

Os aplicativos holográficos perderão o tempo de computação de processamento para o coletor de lixo (GC) quando o GC for ativado para analisar objetos que não estão mais no escopo durante a execução e sua memória precisar ser liberada, para que possa ser disponibilizada para reutilização. Alocações e desalocações constantes geralmente exigirão que o coletor de lixo seja executado com mais frequência, prejudicando o desempenho e a experiência do usuário.

Unity forneceu uma excelente página que explica em detalhes como o coletor de lixo funciona e dicas para escrever código mais eficiente em relação ao gerenciamento de memória.

Uma das práticas mais comuns que leva à coleta excessiva de lixo é não armazenar em cache referências a componentes e classes no desenvolvimento do Unity. Quaisquer referências devem ser capturadas durante Start() ou Awake() e reutilizadas em funções posteriores, como Update() ou LateUpdate().

Outras dicas rápidas:

  • Use a classe C# StringBuilder para criar dinamicamente cadeias de caracteres complexas em tempo de execução
  • Remova chamadas para Debug.Log() quando não forem mais necessárias, pois elas ainda são executadas em todas as versões de compilação de um aplicativo
  • Se seu aplicativo holográfico geralmente requer muita memória, considere chamar System.GC.Collect() durante as fases de carregamento, como ao apresentar uma tela de carregamento ou transição

Pool de objetos

O pool de objetos é uma técnica popular para reduzir o custo de alocação contínua de objetos e deallocations. Isso é feito alocando um grande pool de objetos idênticos e reutilizando instâncias inativas e disponíveis desse pool em vez de gerar e destruir objetos constantemente ao longo do tempo. Os pools de objetos são ótimos para componentes reutilizáveis que têm vida útil variável durante um aplicativo.

Desempenho de arranque

Considere iniciar seu aplicativo com uma cena menor e, em seguida, usar SceneManager.LoadSceneAsync para carregar o restante da cena. Isso permite que seu aplicativo chegue a um estado interativo o mais rápido possível. Pode haver um grande pico de CPU enquanto a nova cena está sendo ativada e que qualquer conteúdo renderizado pode gaguejar ou pegar. Uma maneira de contornar isso é definir a propriedade AsyncOperation.allowSceneActivation como "false" na cena que está sendo carregada, esperar que a cena seja carregada, limpar a tela para preto e, em seguida, defini-la de volta como "true" para concluir a ativação da cena.

Lembre-se de que, enquanto a cena de inicialização estiver carregando, a tela inicial holográfica será exibida para o usuário.

Consulte também