Endereçáveis ​​Unity: sempre com memória suficiente

imagem

Você lidera uma equipe de vários programadores e artistas trabalhando na transferência de um belo jogo de PS4 VR para o Oculus Quest. Você tem seis meses para fazer isso. Qual será o seu primeiro passo? Vamos tentar usar os Endereçáveis ​​Unity.

Você entende que precisa resolver várias tarefas bastante difíceis ao mesmo tempo. Alguns serão mais difíceis para você do que outros, depende da sua experiência em cada uma das áreas. Se você escolher qual deles o privou de sono com mais frequência, então qual será?

Suponho o seguinte: aproximadamente 70% dos leitores dirão que o maior problema ao portar um jogo para o Quest é o desempenho da CPU / GPU. Eu posso responder isso: provavelmente você está certo. Melhorar a produtividade é uma das áreas mais difíceis em um jogo de RV. Otimizações desse tipo requerem um estudo completo do produto, e isso leva tempo. Às vezes, uma otimização adicional é impossível, por causa da qual você geralmente precisa se livrar dos elementos caros da jogabilidade e dos gráficos. E é perigoso decepcionar os jogadores.

Velocidade, velocidade, velocidade ... O que esperar a esse respeito da plataforma Quest? Quão produtivo é? O fato é que, se você já teve experiência no desenvolvimento, sabe que, apesar de sua mobilidade, é surpreendentemente poderoso.

“Vamos, autor, por que você está mentindo? Meu telefone começa a ficar mais lento assim que abro a segunda guia do navegador. Como você pode dizer que as plataformas móveis podem ser produtivas? ”

A grande diferença está no sistema de resfriamento ativo da Quest , que oferece uma enorme vantagem à sua CPU / GPU que não é fornecida por nenhuma outra plataforma móvel. Este é um poderoso ventilador que sopra a poeira do seu cabelo e evita que o processador derreta no seu rosto.

Além disso, um sistema operacional mais especializado é melhor otimizado para renderizar realidade virtual (surpresa) do que o Android padrão. Nos últimos anos, o hardware móvel começou a alcançar rapidamente as plataformas fixas.

Mas, ao mesmo tempo, não negarei que a tarefa de renderização constante com uma frequência de 72 fps seja difícil, especialmente para os portos de jogos de realidade virtual que vêm de plataformas poderosas. Quando falamos sobre o Oculus Quest, você pode imaginar o Snapdragon 835 com uma tela, bateria, quatro câmeras e um ventilador.

O que parece uma falha pode ser considerado uma vantagem. Essa plataforma móvel é um dispositivo bem pesquisado com ferro fraco. Podemos dizer que existem mil truques conhecidos para reduzir rapidamente a carga na CPU e GPU para um nível aceitável. Se você estiver interessado, poderá ler sobre isso nos meus posts subsequentes. E neste artigo, colocaremos o desempenho fora de questão.

Nossa atenção nesse problema pode ser que, em comparação com o PS4, o Quest possui uma característica de hardware que é metade da capacidade: capacidade de RAM . Ou seja, o volume diminuiu de 8 para 4 GB de RAM. Essa é uma aproximação, porque nas duas plataformas o sistema operacional não permite usá-las completamente, para que você possa acompanharvários subsistemas necessários para o funcionamento do ecossistema. No Quest, você pode usar até cerca de 2,2 GB de RAM; se mais, o caos já está começando.

"Mas o que você quer dizer com caos ?" O fato é que, para o jogo, é essencial implementar o gerenciamento de memória correto. Isso aconteceu porque temos duas limitações:

  • Limite de memória : se você exceder um certo limite, o sistema operacional acabará com o jogo
  • Limite de memória suave

Obviamente, não queremos que o primeiro ou o segundo aconteça no jogo. Você consegue imaginar a fúria de um jogador que perdeu as últimas duas horas? Sim, ele definitivamente irá à loja de aplicativos e não dirá nada de agradável lá.

Obviamente, a disponibilidade garantida de 2,2 GB de RAM não é muito. Normalmente, isso não é um problema para novos projetos nos quais as estatísticas são monitoradas constantemente desde o início, mas definitivamente se torna uma dificuldade para uma porta com hardware muito mais fraco.

Se você já lidou com portas semelhantes no passado, perceberá rapidamente como é extremamente difícil reduzir pela metade a quantidade de RAM disponível . Depende muito de quão bem a arquitetura do jogo estava pronta para essa mudança, mas na maioria dos casos isso só leva a lágrimas.

As estratégias mais populares para reduzir os requisitos de memória são alterar os parâmetros de compactação dos ativos, otimizar scripts, reduzir variações de shader etc. Na maioria das vezes, a primeira decisão é alterar as configurações de importação de textura, mas se necessário, você pode usar a compactação de malhas, animações e sons. O problema é que essas técnicas geralmente são complexas e têm seu próprio teto .

Nem todas as plataformas suportam os mesmos parâmetros de importação: ao desenvolver para diferentes dispositivos, os custos do pipeline de montagem aumentam significativamente, sem mencionar a complexidade do controle de qualidade, gráficos de design e programação. Por exemplo, isso oferece suporte ao dispositivo Android ASTC ou apenas ao ETC2 (e geralmente a qualquer um deles)? Ah, e ainda precisamos de versões de 64 bits, mas ao mesmo tempo queremos manter os jogadores com versões de 32 bits. Quantos APKs individuais precisamos criar e testar para cada atualização no jogo? Se você deseja simplificar sua vida, não deve confiar apenas nessas técnicas.

Portanto, precisamos ir mais fundo. Obviamente, queremos que tudo seja o mais simples possível, especialmente ao criar uma porta. Reciclar o jogo inteiramente para o desempenho é uma opção ainda pior do que simplesmente não o transportar. Como parte do tópico do artigo, mostrarei uma das vantagens mais importantes: você aprenderá como reduzir a quantidade de memória necessária pela metade em apenas algumas horas .

isso não é ótimo?

Bem, vamos, vamos me perguntar: isso é realmente possível no seu caso? Eu responderei: depende das condições iniciais, mas, na minha experiência, a resposta é SIM . Os Endereçáveis ​​Unity podem fazer um ótimo serviço aqui. Qual é o truque? Você tem que investir e dominar o processo. Mas esse fluxo de trabalho permitirá que você ganhe o título de funcionário do mês.

Se você estiver interessado, continue lendo.

Nesta publicação, passaremos do gerenciamento tradicional de ativos para o gerenciamento de ativos baseado em endereçáveis . Para ilustrar esse processo, estamos portando um projeto simplificado da velha escola para a nova era dos Endereçáveis ​​da Unidade.

Você pode fazer uma pergunta: por que você simplesmente não mostra o resultado no seu trabalho real?

Em um mundo sem competição, eu apenas mostraria todos os materiais que criei. No entanto, no mundo real, provavelmente serei punido por isso. E então eles me colocam na cadeia.

Então, em vez disso, ofereço minha ajuda: elaboraremos um projeto que apresentará todas as dificuldades que você encontrará amanhã no seu próximo projeto. E, para começar, levaremos o Unity Addressables para a nossa família de pacotes recomendados .

Neste post, apresentarei os Endereçáveis ​​para que você possa implementar seu próprio sistema de Endereçáveis ​​Unity em minutos .


Endereçáveis ​​Unity: por que eles são necessários?


Deve-se prestar atenção a esta seção importante. Nossa tarefa é reconhecer maneiras simples de otimizar o uso da memória e implementá-las rapidamente. Existem várias maneiras de fazer isso, mas uma das mais poderosas e ao mesmo tempo mais simples é carregar a primeira cena e iniciar o criador de perfil. Por quê?

Como a arquitetura não otimizada do jogo pode ser reconhecida a qualquer momento do jogo , a maneira mais rápida de verificar isso é criar um perfil da primeira cena. A razão para isso é que o uso muitas vezes excessivamente ativo de scripts como singleton-s contendo links para todos os ativos, apenas por precaução .

Em outras palavras, muitos jogos geralmente têm um script onipotente que cria muitos links para ativos .Esse componente mantém todos os ativos carregados constantemente, independentemente de estar sendo usado no momento.

Quão ruim é isso?

As situações são diferentes. Se é provável que o seu jogo seja limitado pela memória? essa é uma decisão muito arriscada, porque o jogo não será bem dimensionado com o aumento do número de ativos adicionados (por exemplo, pense em futuros DLCs). Se você estiver desenvolvendo para dispositivos heterogêneos, por exemplo, para Android, não terá uma única quantidade de memória; Cada dispositivo tem sua própria capacidade, então você precisa confiar no pior caso. O sistema operacional pode decidir interromper o aplicativo a qualquer momento, se o usuário mudar repentinamente para responder a uma mensagem no Facebook. Quando ele voltar, uma surpresa estará esperando por ele - o jogo já foi encerrado.

É divertido?

Absolutamente não.

Para complicar a situação, o fato é que, se você decidir mais tarde (ou alguém decidir por você) portar o jogo para outra plataforma menos poderosa enquanto mantém o jogo cruzado, poderá desejar boa sorte. Você definitivamente não vai querer enfrentar um problema tão técnico.

Por outro lado, existem situações em que o gerenciamento tradicional de ativos é apropriado? Sim, claro. Se você está desenvolvendo uma plataforma uniforme, como para o PS4, e a maioria dos requisitos é conhecida desde o início, os benefícios de objetos globais podem potencialmente superar a complexidade adicional de um sistema de gerenciamento de memória aprimorado.

Porque você precisa admitir: o bom e velho objeto global que armazena tudo o que precisamos é uma solução simples, se for o seu caso. Isso simplificará o código e pré-carregará todos os ativos referenciados.

Seja como for, o gerenciamento tradicional de memória é inaceitável para desenvolvedores que procuram maximizar o uso de recursos de ferro . Você está lendo um artigo, o que significa que deseja melhorar suas habilidades. Então chegou a hora de fazê-lo.

Conheça os Endereçáveis ​​da Unidade.

Requisitos de projeto com endereçáveis ​​Unity


Se você planeja apenas ler este post, a tela será suficiente. Se você quer fazer tudo comigo. então você precisará do seguinte:

  • Mãos
  • Mente inteligente
  • Unity 2019.2.0f1 ou superior
  • Projeto de nível 1 com GitHub (faça o download do zip ou via linha de comando)
  • O desejo de mergulhar no interior dos Endereçáveis ​​da Unidade

O repositório git contém três confirmações, uma para cada nível deste post (a menos que eu misture algo e crie uma confirmação com uma correção).

Faça o download do projeto em formato ZIP diretamente do GitHub


Desenvolvedor de nível 1: Gerenciamento tradicional de ativos


Começaremos com o método mais simples de gerenciamento de ativos. No nosso caso, para isso, precisamos fazer uma lista de links diretos para os materiais do skybox no componente.

Se você fizer isso comigo, a preparação tomará três etapas simples:

  1. Faça o download do projeto no git
  2. Abra um projeto no Unity
  3. Clique no botão play!

Bem. Agora você pode clicar nos botões para alterar a caixa do céu. Tão original ... e chata. Pelo que entendi, até agora não há Endereçáveis ​​da Unidade.

Em breve você verá por que enfrentamos esses momentos de tédio.

Primeiramente, como está estruturado o nosso projeto? Baseia-se em dois sistemas principais. Por um lado, temos um objeto Gerenciador de jogos . Este componente é o script principal que armazena links para materiais do skybox e os alterna dependendo dos eventos da interface do usuário. É bem simples.

using UnityEngine;

public class Manager : MonoBehaviour
{
    [SerializeField] private Material[] _skyboxMaterials;

    public void SetSkybox(int skyboxIndex)
    {
        RenderSettings.skybox = _skyboxMaterials[skyboxIndex];
    }
}

O Manager fornece ao sistema de interface do usuário uma função para aplicar material específico à cena através do uso da API RenderSettings .

Em segundo lugar, temos um CanvasSkyboxSelector . Este objeto de jogo contém um componente de tela que renderiza um conjunto de botões distribuídos verticalmente. Cada botão, quando pressionado, chama a função Manager mencionada , que substitui a skybox renderizada, dependendo da identificação do botão. Em outras palavras, o evento OnClick de cada botão chama a função SetSkybox do objeto Manager . É simples, não é?


Endereçáveis ​​Unity - hierarquia de cenas

Agora é hora de começar. Vamos abrir o criador de perfil ( ctrl / cmd + 7 ou Window - Analysis - Profiler ). Suponho que você esteja familiarizado com esta ferramenta, o que significa que você sabe o que fazer com o botão de registro superior . Após alguns segundos de gravação, pare e analise as métricas: CPU, memória, etc. Existe algo interessante?

O desempenho é muito bom, e isso não é surpreendente, dada a escala do projeto. Você pode simplesmente transformar esse projeto em um jogo de realidade virtual e eu garanto que nenhum dos jogadores ficará doente, como costuma acontecer em Eve: Valkyrie .

No nosso caso, vamos nos concentrar na seção de memória. No modo de visualização simples, você verá algo assim:


Gerenciamento de ativos de nível 1 - criação de perfil de memória simples Os

valores de tamanho de textura parecem muito grandes para exibir uma caixa de sky de cada vez, não é? Uma surpresa espera por você: um padrão semelhante pode ser encontrado em muitos jogos não otimizados, cujo desenvolvimento você liderará . Mas, no nosso caso, é apenas um conjunto de caixas de céu. Em outros projetos, serão personagens, planetas, sons, músicas ...

Se a responsabilidade de trabalhar com muitos ativos estiver com você, fico feliz que você esteja lendo este artigo. Ajudarei você a fazer a transição para uma solução que seja bem dimensionada.

Chegou a hora da magia. Mude o perfilador de memória para o modo detalhado. Assista!


Gerenciamento de ativos de nível 1 - perfil detalhado de memória

Droga, o que aconteceu aqui? Todas as texturas do skybox são carregadas na memória, mas apenas uma delas é exibida por vez. Veja o que temos? Essa arquitetura bruta leva até 400 MB .

Definitivamente, isso não nos convém, já que este é apenas um pequeno pedaço do futuro jogo. A solução para esse problema em si se tornará a base da próxima seção.

Resumir:

  • O gerenciamento tradicional de ativos envolve links diretos
  • Portanto, todos os objetos são carregados constantemente
  • O projeto não escala bem


Desenvolvedor de nível 2: processo de endereçamento da unidade


Nos jogos, começamos a partir do nível 1, e isso nos convém, mas assim que descobrimos as regras da jogabilidade, é hora de deixar as muralhas da cidade segura e aumentar o nosso nível. É disso que trata esta seção.

Agora baixe o projeto de nível 2 .

Como vimos anteriormente no criador de perfil, todas as caixas de correio são carregadas na memória, mesmo que apenas uma seja usada ativamente . Essa solução não é escalável, porque em algum momento estaremos limitados pelo número de diferentes variações de ativos que podemos oferecer ao jogador. Que conselho eu posso dar? Não limite o interesse do jogo para os usuários.

Deixe-me ajudá-lo. Pegue uma pá para cavar um túnel de jailbreak do gerenciamento tradicional de ativos. Vamos adicionar uma nova ferramenta interessante à nossa coleção: a API de Endereçáveis ​​da Unidade .

A primeira coisa que precisamos fazer é instalar o pacote Addressables. Para fazer isso, vá para Janela → Gerenciador de Pacotes :


Unity Package Manager - Endereçáveis ​​Unity

Após a instalação, precisamos marcar os materiais como endereçáveis. Selecione-os e ative o sinalizador endereçável na janela do inspetor.


Gerenciamento de ativos de nível 2 (endereçáveis ​​do Unity)

Por isso, pedimos educadamente ao Unity que inclua esses materiais e suas dependências de textura no banco de dados de endereçáveis. Esse banco de dados será usado durante as compilações para empacotar ativos em pedaços, que podem ser facilmente carregados a qualquer momento no jogo.

Agora vou mostrar uma coisa legal. Abra Janela -> Gerenciamento de Ativos -> Endereçáveis . Adivinha o que é isso? Este é o nosso banco de dados que está ansioso para ganhar vida!


Gerenciando Endereçáveis ​​Unity de Nível 2 de Ativos é a janela principal

Caro Leitor, essa foi a parte mais fácil. E agora a diversão começa.

Quero que você visite nosso velho amigo da seção anterior: Sir Manager . Se verificarmos, descobriremos que ele ainda armazena links diretos para ativos! Nós não precisamos disso.

Em vez disso, ensinaremos ao gerente como usar links indiretos, ou seja, AssetReference (no Unreal Engine, eles são chamados de referências suaves).

Vamos deixar nosso componente mais bonito:

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class Manager : MonoBehaviour
{
    [SerializeField] private List<AssetReference> _skyboxMaterials;

    private AsyncOperationHandle  _currentSkyboxMaterialOperationHandle;

    public void SetSkybox(int skyboxIndex)
    {
        StartCoroutine(SetSkyboxInternal(skyboxIndex));
    }

    private IEnumerator SetSkyboxInternal(int skyboxIndex)
    {
        if (_currentSkyboxMaterialOperationHandle.IsValid())
        {
            Addressables.Release(_currentSkyboxMaterialOperationHandle);
        }

        var skyboxMaterialReference = _skyboxMaterials[skyboxIndex];
        _currentSkyboxMaterialOperationHandle = skyboxMaterialReference.LoadAssetAsync();
        yield return _currentSkyboxMaterialOperationHandle;
        RenderSettings.skybox = _currentSkyboxMaterialOperationHandle.Result;
    }
}

Aqui acontece o seguinte:

  • 7, (AssetReference) . , . . .
  • 13: , . ,
  • 18-20 , , , , . , API Addressables, , . — , , addressable-.
  • addressable 23, LoadAssetAsync, yield ( 25), . . !
  • , , , 26. Result, , .


Gerenciamento de ativos de nível 2 (Endereçáveis ​​da unidade) - Lista de referências de ativos

Lembre-se: este código não está pronto para produção. Não o utilize ao programar um avião. Decidi que, por uma questão de simplicidade, sacrifique a confiabilidade.

Mas chega de explicação. É hora de vê-lo em ação.

Por favor, siga estes passos:

  1. Na janela endereçável, prepare o conteúdo ( criar conteúdo do player )
  2. Em seguida, construa para a plataforma selecionada
  3. Execute-o e conecte o criador de perfil (memória) a ele.
  4. Não deixe seu queixo cair de surpresa.


Nível 2 (Endereçáveis ​​da unidade) - Construir conteúdo do jogador


Gerenciamento de memória de nível 2 (Endereçáveis ​​da unidade) - Perfil de memória

Os ativos cozidos não são saborosos?

Eu gosto quando o criador de perfil está satisfeito. E agora vemos o perfil mais feliz do mundo. Um criador de perfil satisfeito significa o seguinte: em primeiro lugar, há jogadores mais satisfeitos que podem jogar seu jogo, mesmo no Nokia 3210 . Em segundo lugar, esses são produtores satisfeitos. E para você, isso significa que sua carteira ficará satisfeita.

Esse é o poder do sistema Endereçáveis.

Mas os Endereçáveis ​​impõem pequenos custos adicionais de mão-de-obra. Por um lado, os programadores precisam fornecer suporte para fluxos de trabalho assíncronos (isso é facilmente implementado usando a rotina). Além disso, os designers terão que estudar os recursos do sistema, por exemplo, grupos endereçáveis, e ganhar experiência para tomar decisões informadas. E, finalmente, o departamento de TI ficará muito feliz em saber que você precisará configurar a infraestrutura para transferir ativos pela rede, se preferir hospedá-los online.

Eu devo parabenizá-lo. Vou explicar o que alcançamos:

  • Gerenciamento de memória adequado.
  • Inicialização mais rápida.
  • Tempo de instalação mais rápido, tamanho reduzido do aplicativo na loja.
  • Maior compatibilidade do dispositivo.
  • Arquitetura assíncrona.
  • Eles abriram a porta para armazenar esse conteúdo on-line → isto é, para separar os dados do código.

Eu ficaria orgulhoso de tais realizações. Este é um bom retorno do nosso investimento em trabalho.

Ah, e não esqueça de mencionar a experiência com os Endereçáveis ​​em uma entrevista.

Materiais de suporte: criando instâncias e contagem de links. Informações sobre este tópico podem ser encontradas no meu post .

Opcional: estratégias alternativas de download. Você pode ler sobre eles no meu post .

Resumir:

  • O gerenciamento de ativos baseado em endereçáveis ​​tem uma escala extraordinária.
  • Endereçáveis ​​adicionam comportamento assíncrono
  • Não se esqueça de preparar o conteúdo para alterações, caso contrário, o jogo terá um tom rosado!


Gerenciamento de ativos de nível 3 (??) - Entrega de conteúdo de rede

Gerenciamento de ativos de nível 3 (??) - Entrega de conteúdo de rede


Na seção anterior, fizemos o avanço mais importante. Aprimorou suas habilidades passando de um sistema tradicional de gerenciamento de ativos para um fluxo de trabalho baseado em endereçável. Esta é uma grande vitória para o projeto, porque, graças ao pequeno investimento de tempo, fornecemos espaço para escalar o volume de ativos, mantendo um baixo nível de consumo de memória. Essa conquista realmente o levou ao nível 2, parabéns! No entanto, ainda temos que responder a outra pergunta:

isso é tudo?

Não . Mal tocamos no tópico Endereçáveis, existem outras maneiras de melhorar o projeto, graças a este pacote poderoso.

É claro que você não precisa se lembrar de todos os detalhes do uso de Endereçáveis, mas eu recomendo que você os leia brevemente, porque no futuro você provavelmente se encontrará com novos testes e ficará agradecido por um estudo mais aprofundado. Por isso preparei outro pequeno guia.

Com isso, você aprenderá sobre os seguintes aspectos:

  • Janela Endereçáveis : detalhes importantes
  • Perfil de endereçáveis : não deixe vazamentos de memória arruinar sua vida
  • Entrega em rede : tempo reduzido da instalação à jogabilidade
  • Integração de pipeline de montagem
  • Estratégias práticas : acelerar o fluxo de trabalho, eliminando a necessidade de intervalos para café de dez minutos

E, mais importante, responderemos às seguintes perguntas:

  • Qual é o significado oculto dos eventos do Send Profiler ?
  • Quão útil é a API AddressableAssetSettings ?
  • Como integrar tudo isso à API BuildPlayerWindow ?
  • Qual é a diferença entre o Modo Virtual e o Pacote ?

Orientação de nível 3 pode ser encontrada em meu post .

All Articles