Como a Zugalu Entertainment reduziu o uso de RAM de 20 GB para 500 MB para Prosperar: Heavy Lies the Crown

Esta página da Web foi automaticamente traduzida para sua conveniência. Não podemos garantir a precisão ou a confiabilidade do conteúdo traduzido. Se tiver dúvidas sobre a precisão do conteúdo traduzido, consulte a versão oficial em inglês da página da Web.
Prosperar: Heavy Lies the Crown é um construtor de cidades medievais com elementos de estratégia em tempo real. O jogo, onde o destino do reino depende de cada decisão que um jogador toma, possui funcionalidade tanto para um jogador quanto para multiplayer cooperativo. Os jogadores podem expandir estrategicamente seu território e seu reino, e então construir ao longo de um grande mapa.
À medida que a equipe começou a desenvolver o título, eles encontraram obstáculos ao tentar melhorar o desempenho. Após testes extensivos, eles aprenderam onde estavam os gargalos e o que precisavam fazer – construir um sistema de pré-processamento de animação e um sistema de vegetação personalizado. Aqui está como eles melhoraram a animação de personagens no jogo.
O DESAFIO:
Superando gargalos de desempenho causados pela animação de personagens
PLATFORM:
PC
LOCALIZAÇÃO:
Alberta, Canada
EQUIPE DO PROJETO:
16
Prosperar: Heavy Lies the Crown: Um estudo de caso da Unity
Como um estúdio otimiza o desempenho enquanto anima centenas de personagens?
À medida que o jogo tomava forma, ficou claro para a equipe da Zugalu Entertainment que o desempenho seria seu maior desafio. Eles estavam visando um requisito de sistema bastante baixo – uma placa de vídeo NVIDIA GeForce GTX 750 Ti para a GPU e um processador quad-core, que é um chip com quatro unidades independentes chamadas núcleos que leem e executam instruções da CPU.
“Sempre que você quiser direcionar um sistema, a taxa de quadros preferível é 60 fps. Havia partes do nosso sistema que não podíamos realmente mudar e que estavam consumindo uma grande parte do desempenho, então tivemos que encontrar ganhos de qualquer lugar que pudéssemos,” diz Jackie Li, artista conceitual líder e artista técnico da Zugalu Entertainment.
Enquanto procuravam áreas para aumentar o desempenho, decidiram que a grande quantidade de animações de personagens era uma correção obrigatória, pois usavam uma grande quantidade de RAM e causavam muitos sistemas de jogadores a travar.

Os resultados
- Reduziram o uso de RAM de 20 GB para 500 MB
- Animaram milhares de personagens na tela ao mesmo tempo
- Reduziram o número de chamadas de desenho de personagens de 1.000 para 20 chamadas de desenho instanciadas
- Aumentaram o desempenho de aproximadamente 3,5 milissegundos na placa de vídeo GTX 750 Ti para 0,35 milissegundos na placa de vídeo 2080 Ti
Migrando de baking de vértice para baking de osso
Para otimizar o processo de animação de personagens, a equipe construiu um sistema de baking de animação. Eles precisavam ter centenas de personagens animados na tela ao mesmo tempo e inicialmente olharam para soluções de ativos de animação de vértice. Isso foi um grande problema para o uso de VRAM e RAM deles. Eles não conseguiram encontrar outra solução, então decidiram construir a própria.
Para o sistema de animação, a equipe começou a usar baking de vértice, que envolve pegar todos os quadros-chave de sua animação e assar esses dados por vértice. “Uma textura conteria uma animação, mas o tamanho da textura para essa uma animação é bastante grande. O custo de memória é um fator do número de vértices multiplicado pelo número de quadros assados. Então, 5000 vértices vezes 100 quadros seriam uma textura de 6 MB no formato RGB float de 32 bits,” diz Li. “Quando você precisa de muitas animações diferentes multiplicadas por um grande número de personagens diversos, o custo de memória começa a ficar extremo.”
Eles precisavam reduzir isso drasticamente, mas ainda manter a capacidade de usar a GPU para acelerar as animações. Decidiram migrar para baking de osso, que forneceu uma maneira direta de usar menos dados, uma vez que o renderizador de malha do Unity usa ossos para transformar o vértice.

Prosperar: Pesada é a Coroa | Zugalu Entertainment | PlaySide Studios
“Tudo o que precisávamos fazer era pegar o processo de skinning de malha, vinculando uma malha 3D a um esqueleto ou rig, permitindo que a malha se deformasse e se movesse realisticamente quando o esqueleto fosse animado, e transferi-lo para a GPU,” diz Garrett Hau, CTO da Zugalu Entertainment.
Eles então pegaram as transformações dos ossos por quadro e as assaram como texturas. Assar esse tipo de informação economizou muita memória. “Com a assadura de ossos, diferentes personagens com a mesma estrutura óssea podem compartilhar os dados de animação assados. Tínhamos personagens como um fazendeiro e um operário, cuja estrutura óssea era a mesma. Reutilizamos os mesmos dados assados em vários personagens para obter ainda mais economia,” explica Li.
No final, mesmo que o jogo tenha uma tonelada de personagens e animações, eles reduziram o uso de RAM de 20 GB para 500 MB.

Pré-visualização no Editor de animações assadas
Beneficiando-se da instância de GPU
Quando se tratou de animação, a equipe se concentrou na renderização de pele, aplicando materiais, shaders e texturas à malha para simular a cor da pele, sombreamento e texturas. Li explica que, “um benefício de fazer renderização de pele baseada em computação de GPU é que tivemos acesso à instância de GPU. Em vez de renderizar cada personagem um de cada vez, cada um sendo uma única chamada de desenho, renderizamos vários personagens com animações diferentes usando uma única chamada de desenho.”
Isso foi possível uma vez que pegaram os dados de animação, texturas e os empacotaram em um único array de texturas. Isso parece uma única textura para a GPU. “É possível renderizar cada personagem usando uma única chamada de desenho, mas para ser mais flexível, tínhamos apenas quatro personagens que compartilhavam ossos.”

Capturando uma chamada de desenho instanciada
Ao migrar de assadura de vértice para assadura de osso, a equipe reduziu o número de chamadas de desenho de personagens de 1.000 para 20 chamadas de desenho instanciadas. “A assadura de vértice era difícil, pois cada submalha individual era considerada diferente. Um personagem pode ter várias partes e cada uma teria uma chamada de desenho,” diz Hau.
Com a baking de ossos, varia com base em quantos tipos diferentes de personagens um jogo tem. Cada personagem seria no máximo uma chamada de desenho, pois combina todas as submalhas em uma malha. “Por exemplo,” explica Hau, “mesmo que haja 10 tipos diferentes de personagens na tela e cada um tenha várias submalhas, haverá apenas 10 chamadas de desenho.”

Prosperar: Pesada é a Coroa | Zugalu Entertainment | PlaySide Studios
““Unity tem muitas APIs que fazem exatamente o que você quer. Isso inclui pegar informações específicas de um FBX importado, alternar facilmente palavras-chave de Shader e criar ferramentas de Editor personalizadas com APIs de Inspector fáceis de usar.””
Jackie Li - Zugalu Entertainment
Lead Concept Artist and Technical ArtistConstruindo uma transformação de matriz
Aprender a skinning de malha ajudou a equipe a superar seus grandes obstáculos de animação. Eles usaram APIs do Unity para ajudá-los ao longo do caminho.
Para pegar transformações de ossos, eles acessaram a propriedade pública de SkinnedMeshRenderer.bones. Esta API retorna um array de transformações que contém informações como qualquer outra transformação de GameObject. Para medição de desempenho, eles usaram a detecção automática de builds de desenvolvimento do Unity Profiler rodando em outros computadores na rede local. Isso permitiu que eles fizessem o perfil do jogo em seu sistema de requisitos mínimos enquanto trabalhavam em seus computadores principais.
A equipe de teste de desempenho também aplicou ProfilerMarker.Begin() e ProfilerMarker.End() APIs para amostrar o desempenho por quadro. Esses podem ser usados criando um ProfileMarket.struct, inserindo então as duas chamadas de método anteriores no lugar onde queriam testar o tempo de CPU. Esse resultado então apareceu no Unity Profiler.

Prosperar: Pesada é a Coroa | Zugalu Entertainment | PlaySide Studios
Li diz, “As APIs do Unity têm sido ótimas. Elas ajudaram a tornar certas partes do desenvolvimento sem costura.” O único bug que a equipe experimentou foi com o espaço de coordenadas na GPU. “Estávamos obtendo o espaço do mundo, mas precisávamos do espaço do osso.”
Enquanto amostravam um quadro da transformação do osso durante a cocção, precisavam de uma transformação relativa à posição inicial do osso, conhecida como bindpose. Para conseguir isso, construíram uma transformação de matriz. Primeiro, pegaram a matriz de bindpose de SkinnedMeshRenderer.sharedMesh.bindposes. Em seguida, multiplicaram a matriz de transformação do mundo do osso pela matriz de transformação de bindpose (por exemplo, boneTransform.localToWorldMatrix * bindpose).

Captura no Editor de um shader de personagem no Shader Graph
““Shader Graph é a resposta da Unity para criar shaders sem ter um entendimento profundo do código do shader em si. Foi realmente conveniente, já que não precisávamos reescrever todo o shader nós mesmos.””
Garrett Hau - Zugalu Entertainment
CTOCriando shaders com facilidade
Quando se tratou de produzir shaders para animação, a equipe escolheu o Shader Graph. “É a resposta da Unity para criar shaders sem ter um entendimento profundo do código do shader em si. Foi realmente conveniente, já que não precisávamos reescrever todo o shader nós mesmos,” diz Hau.
Para skinning de malha, eles tiveram que fazer muita matemática de shader, e os nós que o Shader Graph fornece permitiram que eles completassem isso. Li explica que, “é amostragem de textura e matemática de matriz. Se você quisesse, também poderia usar o nó de função personalizada da Unity para escrever o código em si.”
Para as ferramentas do Editor, o diretor de animação tinha requisitos específicos para assar animações, já que ele as criou todas sozinho. “Com C# e as APIs da Unity, foi bastante fácil ativar e desativar a interpolação para shaders. Eles também nos ajudaram a mudar o número de ossos a serem assados e o número de quadros para assá-los,” diz Li. “As APIs do Inspector amigáveis ao usuário permitiram que esses recursos do Editor fossem facilmente adicionados à ferramenta de cocção.”

Amostrando texturas de matriz no Shader Graph
Mantendo-se otimista e consciente
No final do dia, embora o desenvolvimento do jogo tenha sido repleto de altos e baixos, a equipe melhorou o desempenho da GPU de aproximadamente 3,5 milissegundos na placa de vídeo GTX 750 Ti para 0,3 milissegundos na placa de vídeo 2080 Ti.
Como Li diz: “Estamos empolgados com a economia de desempenho e com o resultado do jogo.”

Prosperar: Pesada é a Coroa | Zugalu Entertainment | PlaySide Studios
Baixe agora o Unity Pro
Comece a criar jogos que competem e superam a qualidade e o sucesso dos lançamentos de grandes estúdios com a ajuda de ferramentas poderosas, suporte, parceiros verificados e uma comunidade vibrante.