Otimize o desempenho do seu jogo para dispositivos móveis: Dicas de especialistas sobre gráficos e ativos

Nossa equipe de Sucesso Integrado apoia os clientes da Unity com suas questões técnicas complexas. Sentamos com essa equipe de engenheiros de software sêniores e pedimos que compartilhassem um pouco de sua experiência em otimização de jogos para dispositivos móveis.
Nossa equipe de Produção do Unity Studio conhece o código-fonte como a palma da mão e trabalha com uma infinidade de clientes da Unity para ajudá-los a aproveitar ao máximo o motor. Em seu trabalho, eles mergulham fundo em projetos de criadores para ajudar a identificar pontos onde o desempenho pode ser otimizado para maior velocidade, estabilidade e eficiência. À medida que nossos engenheiros começaram a compartilhar suas percepções sobre otimização de jogos para dispositivos móveis, percebemos rapidamente que havia informações demais para o único post de blog que havíamos planejado. Em vez disso, decidimos transformar sua montanha de conhecimento em um e-book completo (que você pode baixar aqui), além de uma série de posts de blog que destacam algumas dessas mais de 75 dicas práticas.
Na última parte desta série de otimização, focamos em como melhorar o desempenho de seus ativos, configuração de projeto e gráficos. Caso você tenha perdido, confira nossos posts anteriores sobre perfilagem, memória e arquitetura de código, bem como física, UI e áudio, para uma visão mais completa de como otimizar seu jogo – ou, baixe o e-book gratuito para um resumo de todos esses tópicos.
Existem algumas Configurações de Projeto que podem impactar seu desempenho móvel.
Reduzir ou desativar a Frequência do Acelerômetro
A Unity coleta o acelerômetro do seu celular várias vezes por segundo. Desative isso se não estiver sendo usado em sua aplicação, ou reduza sua frequência para melhor desempenho.

Desativar configurações de Player ou Qualidade desnecessárias
Nas configurações de Player, desative API Gráfica Automática para plataformas não suportadas para evitar a geração excessiva de variantes de shader. Desative Arquiteturas Alvo para CPUs mais antigas se sua aplicação não as suportar.
Nas configurações de Qualidade, desative níveis de Qualidade desnecessários.
Desative a física desnecessária
Se o seu jogo não estiver usando física, desmarque Simulação Automática e Sincronização Automática de Transformações. Esses apenas desacelerarão sua aplicação sem benefício discernível.
Escolha a taxa de quadros certa
Projetos móveis devem equilibrar taxas de quadros com a vida útil da bateria e o aquecimento térmico. Em vez de forçar os limites do seu dispositivo a 60 fps, considere rodar a 30 fps como um compromisso. Unity padrão é 30 fps para dispositivos móveis.
Você também pode ajustar a taxa de quadros dinamicamente durante a execução com Application.targetFrameRate. Por exemplo, você poderia cair abaixo de 30 fps para cenas lentas ou relativamente estáticas e reservar configurações de fps mais altas para jogabilidade.
Evite hierarquias grandes
Divida suas hierarquias. Se seus GameObjects não precisam estar aninhados em uma hierarquia, simplifique a hierarquia de pais. Hierarquias menores se beneficiam de multithreading para atualizar as Transformações em sua cena. Hierarquias complexas incurrirão em cálculos desnecessários de Transform e mais custo para coleta de lixo.
Veja Otimizando a Hierarquia e esta palestra Unite para melhores práticas com Transformações.
Transforme uma vez, não duas
Além disso, ao mover Transformações, use Transform.SetPositionAndRotation para atualizar tanto a posição quanto a rotação de uma vez. Isso evita a sobrecarga de modificar uma transformação duas vezes.
Se você precisar Instanciar um GameObject em tempo de execução, uma simples otimização é parentar e reposicionar durante a instância:
GameObject.Instantiate(prefab, parent);
GameObject.Instantiate(prefab, parent, position, rotation);
Para mais detalhes sobre Object.Instantiate, consulte a API de Scripting.
Assuma que o Vsync está habilitado
Plataformas móveis não renderizarão meio-quadros. Mesmo que você desative o Vsync no Editor (Configurações do Projeto > Qualidade), o Vsync está habilitado no nível de hardware. Se a GPU não conseguir atualizar rápido o suficiente, o quadro atual será mantido, reduzindo efetivamente seu fps.
O pipeline de ativos pode impactar dramaticamente o desempenho da sua aplicação. Um artista técnico experiente pode ajudar sua equipe a definir e impor formatos de ativos, especificações e configurações de importação para processos suaves.
Não confie nas configurações padrão. Use a aba de substituição específica da plataforma para otimizar ativos como texturas e geometria de malha. Configurações incorretas podem resultar em tamanhos de build maiores, tempos de build mais longos e uso de memória ruim. Considere usar o recurso Presets para ajudar a personalizar configurações básicas que melhorarão um projeto específico.
Veja este guia sobre melhores práticas para ativos de arte ou confira este curso sobre Otimização de Arte 3D para Aplicações Móveis via Unity Learn para mais detalhes.
Importe texturas corretamente
A maior parte da sua memória provavelmente será destinada a texturas, então as configurações de importação aqui são críticas. Em geral, tente seguir estas diretrizes:
- Reduza o Tamanho Máximo: Use as configurações mínimas que produzem resultados visualmente aceitáveis. Isso é não destrutivo e pode rapidamente reduzir sua memória de textura.
- Use potências de dois (POT): Unity requer dimensões de textura POT para formatos de compressão de textura móvel (PVRCT ou ETC).
- Agrupe suas texturas: Colocar várias texturas em uma única textura pode reduzir chamadas de desenho e acelerar a renderização. Use o Unity Sprite Atlas ou o TexturePacker de terceiros para agrupar suas texturas.
- Desative a opção Read/Write Enabled: Quando ativada, esta opção cria uma cópia na memória acessível pela CPU e GPU, dobrando a pegada de memória da textura. Na maioria dos casos, mantenha isso desativado. Se você estiver gerando texturas em tempo de execução, aplique isso via Texture2D.Apply, passando makeNoLongerReadable definido como true.
- Desative Mip Maps desnecessários: Mip Maps não são necessários para texturas que permanecem em um tamanho consistente na tela, como sprites 2D e gráficos de UI (deixe Mip Maps ativados para modelos 3D que variam sua distância da câmera).

Comprimir texturas
Considere estes dois exemplos usando o mesmo modelo e textura. As configurações à esquerda consomem quase oito vezes a memória das configurações à direita, sem muito benefício na qualidade visual.

Use Compressão de Textura Escalável Adaptativa (ATSC) para iOS e Android. A grande maioria dos jogos em desenvolvimento visa dispositivos de especificação mínima que suportam compressão ATSC.
As únicas exceções são:
- jogos iOS direcionados a dispositivos A7 ou inferiores (por exemplo, iPhone 5, 5S, etc.) – use PVRTC
- jogos Android direcionados a dispositivos anteriores a 2016 – use ETC2 (Compressão de Textura Ericsson)
Se formatos comprimidos como PVRTC e ETC não forem suficientemente de alta qualidade, e se ASTC não for totalmente suportado na sua plataforma de destino, tente usar texturas de 16 bits em vez de texturas de 32 bits.
Consulte o manual para mais informações sobre formato de compressão de textura recomendado por plataforma.
Ajustar configurações de importação de malha
Assim como texturas, malhas podem consumir memória excessiva se não forem importadas com cuidado. Para minimizar o consumo de memória das malhas:
- Comprimir a malha: A compressão agressiva pode reduzir o espaço em disco (a memória em tempo de execução, no entanto, não é afetada). Observe que a quantização da malha pode resultar em imprecisão, então experimente níveis de compressão para ver o que funciona para seus modelos.
- Desativar Leitura/Gravação: Ativar esta opção duplica a malha na memória, mantendo uma cópia da malha na memória do sistema e outra na memória da GPU. Na maioria dos casos, você deve desativá-la (no Unity 2019.2 e versões anteriores, esta opção está marcada por padrão).
- Desativar rigs e BlendShapes: Se sua malha não precisar de animação esquelética ou de blendshape, desative essas opções sempre que possível.
- Desativar normais e tangentes: Se você tiver certeza absoluta de que o material da malha não precisará de normais ou tangentes, desmarque essas opções para economizar ainda mais.

Verifique suas contagens de polígonos
Modelos de maior resolução significam maior uso de memória e potencialmente mais tempo de GPU. Sua geometria de fundo precisa de meio milhão de polígonos? Considere reduzir modelos em seu pacote DCC de escolha. Exclua polígonos não vistos do ponto de vista da câmera e use texturas e mapas normais para detalhes finos em vez de malhas de alta densidade.
Automatize suas configurações de importação usando o AssetPostprocessor
O AssetPostprocessor permite que você execute scripts ao importar ativos. Isso solicita que você personalize as configurações antes e/ou depois de importar modelos, texturas, áudio, etc.
Use o Sistema de Ativos Endereçáveis
O Sistema de Ativos Endereçáveis fornece uma maneira simplificada de gerenciar seu conteúdo. Este sistema unificado carrega AssetBundles por "endereço" ou alias, de forma assíncrona, a partir de um caminho local ou de uma rede de entrega de conteúdo (CDN) remota.

Se você dividir seus ativos não relacionados a código (Modelos, Texturas, Prefabs, Áudio e até mesmo Cenas inteiras) em um AssetBundle, você pode separá-los como conteúdo para download (DLC).
Em seguida, use Addressables para criar uma construção inicial menor para seu aplicativo móvel. Cloud Content Delivery permite que você hospede e entregue o conteúdo do seu jogo aos jogadores à medida que eles progridem no jogo.

Clique aqui para ver como o Sistema de Ativos Endereçáveis pode facilitar a gestão de ativos.
A cada quadro, o Unity determina os objetos que devem ser renderizados e, em seguida, cria chamadas de desenho. Uma chamada de desenho é uma chamada para a API gráfica para desenhar objetos (por exemplo, um triângulo), enquanto um lote é um grupo de chamadas de desenho a serem executadas juntas.
À medida que seus projetos se tornam mais complexos, você precisará de um pipeline que otimize a carga de trabalho em sua GPU. OPipeline de Renderização Universal (URP) atualmente usa um renderizador de passagem única para trazer gráficos de alta qualidade para sua plataforma móvel (renderização adiada estará disponível em lançamentos futuros). A mesma iluminação e materiais baseados fisicamente dos consoles e PCs também podem ser escalados para o seu telefone ou tablet.
As seguintes diretrizes podem ajudá-lo a acelerar seus gráficos.
Agrupe suas chamadas de desenho
Agrupar objetos para serem desenhados juntos minimiza as mudanças de estado necessárias para desenhar cada objeto em um lote. Isso leva a um desempenho melhorado ao reduzir o custo da CPU para renderizar objetos. Unity pode combinar múltiplos objetos em menos lotes usando várias técnicas:
- Agrupamento dinâmico: Para malhas pequenas, Unity pode agrupar e transformar vértices na CPU, e então desenhá-los todos de uma vez. Observação: Use isso apenas se você tiver malhas de baixa poligonagem suficientes (menos de 900 atributos de vértice e não mais de 300 vértices). O Agrupador Dinâmico não irá agrupar malhas maiores que isso, então habilitá-lo desperdiçará tempo da CPU procurando por malhas pequenas para agrupar em cada quadro.
- Agrupamento estático: Para geometria não móvel, Unity pode reduzir chamadas de desenho para malhas que compartilham o mesmo material. Embora seja mais eficiente do que o agrupamento dinâmico, ele usa mais memória.
- Instanciação de GPU: Se você tiver um grande número de objetos idênticos, essa técnica os agrupa de forma mais eficiente através do uso de hardware gráfico.
- Agrupamento SRP: Habilite o Agrupador SRP no seu Ativo do Pipeline de Renderização Universal em Avançado. Isso pode acelerar significativamente seus tempos de renderização da CPU, dependendo da Cena.

Use o Depurador de Quadro
O Depurador de Quadros mostra como cada quadro é construído a partir de chamadas de desenho individuais. Esta é uma ferramenta inestimável para solucionar problemas das propriedades do seu shader que pode ajudá-lo a analisar como o jogo é renderizado.

Novo no Depurador de Quadros? Confira este tutorial introdutório aqui.
Evite muitas luzes dinâmicas
É crucial evitar adicionar muitas luzes dinâmicas ao seu aplicativo móvel. Considere alternativas como efeitos de shader personalizados e sondas de luz para malhas dinâmicas, bem como iluminação pré-processada para malhas estáticas.
Veja esta tabela de comparação de recursos para os limites específicos das luzes em tempo real do URP e do pipeline embutido.
Desative sombras
A projeção de sombras pode ser desativada por MeshRenderer e luz. Desative sombras sempre que possível para reduzir chamadas de desenho.
Você também pode criar sombras falsas usando uma textura desfocada aplicada a uma malha simples ou quad abaixo de seus personagens. Caso contrário, você pode criar sombras em forma de blob com shaders personalizados.

Pré-processar sua iluminação em Lightmaps
Adicione iluminação dramática à sua geometria estática usando Iluminação Global (GI). Marque objetos com Contribuir GI para que você possa armazenar iluminação de alta qualidade na forma de Lightmaps.
Sombras e iluminação pré-processadas podem ser renderizadas sem perda de desempenho em tempo de execução. O Lightmapper Progressivo de CPU e GPU pode acelerar o pré-processamento da Iluminação Global.

Siga o manual guide e este artigo sobre otimização de iluminação para obter ajuda para começar com Lightmapping no Unity.
Use Light Layers
Para cenas complexas com várias luzes, separe seus objetos usando camadas e, em seguida, restrinja a influência de cada luz a uma máscara de culling específica.

Use Light Probes para objetos em movimento
Light Probes armazenam informações de iluminação pré-processadas sobre o espaço vazio na sua Cena, enquanto fornecem iluminação de alta qualidade (tanto direta quanto indireta). Eles usam Harmônicos Esféricos, que calculam muito rapidamente em comparação com luzes dinâmicas.

Use Level of Detail (LOD)
À medida que os objetos se afastam, Level of Detail pode ajustá-los ou alternar para usar malhas mais simples com materiais e shaders mais simples, para ajudar no desempenho da GPU.


Use Occlusion Culling para remover objetos ocultos
Objetos ocultos atrás de outros objetos ainda podem ser renderizados e consumir recursos. Use Occlusion Culling para descartá-los.
Enquanto o culling de frustum fora da visão da câmera é automático, o culling de oclusão é um processo pré-processado. Simplesmente marque seus objetos como Static Occluders ou Occludees, e depois faça o bake através do Window > Rendering > Occlusion Culling diálogo. Embora não seja necessário para cada cena, o culling pode melhorar o desempenho em muitos casos.
Confira o tutorial Working with Occlusion Culling para mais informações.
Evite a resolução nativa móvel
Com os telefones e tablets se tornando cada vez mais avançados, dispositivos mais novos tendem a ter resoluções muito altas.
Use Screen.SetResolution(width, height, false) para reduzir a resolução de saída e recuperar um pouco de desempenho. Profile várias resoluções para encontrar o melhor equilíbrio entre qualidade e velocidade.
Limite o uso de câmeras
Cada câmera gera alguma sobrecarga, esteja ela realizando um trabalho significativo ou não. Use apenas os componentes de Câmera necessários para renderização. Em plataformas móveis de baixo desempenho, cada câmera pode usar até 1 ms de tempo de CPU.
Mantenha os shaders simples
O Pipeline de Renderização Universal inclui vários shaders Lit e Unlit leves que já estão otimizados para plataformas móveis. Tente manter suas variações de shader o mais baixo possível, pois elas podem ter um efeito dramático no uso de memória em tempo de execução. Se os shaders padrão do URP não atenderem às suas necessidades, você pode personalizar a aparência de seus materiais usando o Shader Graph. Descubra como construir seus shaders visualmente usando o Shader Graph aqui.

Minimize o overdraw e a mistura alfa
Evite desenhar imagens transparentes ou semi-transparentes desnecessárias. As plataformas móveis são muito impactadas pelo overdraw e pela mistura alfa resultantes. Não sobreponha imagens ou efeitos quase invisíveis. Você pode verificar o overdraw usando o depurador gráfico RenderDoc.
Limite os efeitos de pós-processamento
Efeitos de pós-processamento Post-processing, como brilhos, podem desacelerar dramaticamente o desempenho. Use-os com cautela na direção de arte do seu título.

Cuidado com Renderer.material
Acessar Renderer.material em scripts duplica o material e retorna uma referência à nova cópia. Isso quebra qualquer lote existente que já inclua o material. Se você deseja acessar o material do objeto em lote, use Renderer.sharedMaterial em vez disso.
Otimize SkinnedMeshRenderers
Renderizar malhas skinadas é caro. Certifique-se de que cada objeto que usa um SkinnedMeshRenderer realmente precise dele. Se um GameObject só precisa de animação algumas vezes, use a função BakeMesh para congelar a malha skinada em uma pose estática, depois troque para um MeshRenderer mais simples em tempo de execução.
Minimize Reflection Probes
Um Reflection Probe pode criar reflexos realistas, mas pode ser muito custoso em termos de lotes. Use cubemaps de baixa resolução, máscaras de culling e compressão de textura para melhorar o desempenho em tempo de execução.
Este foi o último post do blog na série de otimização de desempenho móvel. No entanto, se você quiser acesso à lista completa de dicas e truques da equipe, também publicamos um e-book de 52 páginas disponível aqui.

Se você está interessado em aprender mais sobre os serviços de Suporte Integrado e deseja dar à sua equipe acesso direto a engenheiros, conselhos de especialistas e orientações sobre melhores práticas para seus projetos, então confira os planos de sucesso da Unity aqui.
Não encontrou o que estava procurando?
Queremos ajudar você a tornar suas aplicações Unity o mais performáticas possível. Se houver algum tópico de otimização que você gostaria de saber mais, por favor, nos avise nos comentários.
