Iteração rápida de design em Breachers usando AssetPostprocessor e Blender

A Triangle Factory é uma empresa de jogos belga de rápido crescimento que usa o Unity para criar títulos VR multijogador de alta qualidade, como Hyper Dash e seu último jogo, Infratores. A Triangle Factory utiliza ferramentas como Cinemachine, Unity Profiler, Game Server Hosting, Matchmaker, Voice Chat (Vivox)e Friends para criar uma experiência imersiva para os jogadores.
Neste blog, Jel Sadones, líder de design de níveis/arte técnica, e o desenvolvedor líder Pieter Vantorre nos mostram seu pipeline do Blender para o Unity e como eles deram vida ao seu título FPS tático de VR , Breachers .
O Unity tem sido nosso mecanismo e ambiente de desenvolvimento preferidos por mais de uma década, e passamos por muitos fluxos de trabalho ao longo dos anos para modelagem e design de ambientes. Isso inclui o uso de ferramentas de modelagem no mecanismo, como o ProBuilder (que ainda usamos e adoramos para prototipagem rápida) e a montagem de cenas de Prefabs criados em outros pacotes de modelagem. Para nossos projetos atuais, porém, chegamos a um fluxo de trabalho em que modelamos e organizamos nossos níveis no Blender e contamos com o AssetPostprocessor da Unity para integrá-los ao nosso projeto Unity .
Neste artigo, compartilharemos com você como chegamos a esse fluxo de trabalho e como ele oferece suporte ao tipo de iteração de design rápida que precisamos para nossos jogos.
Em 2021, lançamos nosso primeiro grande título de VR , Hyper Dash, um jogo de tiro em arena 5v5 de ritmo acelerado. Quando começamos o desenvolvimento do jogo em 2019, tínhamos um fluxo de trabalho básico do Blender para o Unity que provavelmente parece familiar para muitos: Nós simplesmente modelamos a geometria no Blender, exportamos nossos ativos como arquivos FBX e os integramos manualmente no Unity. A integração manual envolveu várias etapas:
- Configurando objetos dinâmicos na cena, como coleta de armas, portas de spawn, pontos de captura
- Colocar colisores para evitar que os jogadores andem ou se teletransportem em certas áreas
- Configurando guias invisíveis para permitir que os bots se comportem corretamente
- Etc.

Esse processo pode funcionar bem para projetos menores, mas rapidamente se torna complicado à medida que o projeto cresce e evolui. Quando começamos a planejar o desenvolvimento do nosso próximo título, sabíamos que precisaríamos de um fluxo de trabalho drasticamente melhorado.
Breachers é um jogo de tiro competitivo com layouts de níveis complexos, mecânicas de jogo mais sutis, sistemas mais técnicos em jogo e um nível mais alto de polimento gráfico voltado para a mais nova geração de hardware VR autônomo. Em termos de complexidade, ele vai vários passos além do Hyper Dash, e rapidamente sentimos os efeitos disso em nosso fluxo de trabalho.

Na fase de prototipagem, ainda dependemos muito de Prefabs para objetos dinâmicos, como barricadas de janelas, por exemplo. Esses são objetos que colocamos dentro das janelas para bloquear a linha de visão entre o interior e o exterior, evitando que os times se vejam durante a fase de aquecimento do jogo.
Ao testar nosso protótipo, estávamos constantemente movendo as janelas para melhorar a jogabilidade, o que significava alterar a geometria no Blender e reexportar para o Unity e, então, mover manualmente os objetos da barricada para corresponder às nossas alterações. Muitas horas foram gastas voando pela visualização de cena do Unity, verificando e corrigindo manualmente esse tipo de coisa. Ainda assim, tivemos mais de um teste de jogo em que só percebemos durante o jogo que algo havia sido esquecido.


Obviamente, esse fluxo de trabalho não nos daria a capacidade de iterar rapidamente nossos designs de mapas enquanto fazíamos testes, tanto internamente quanto como parte do nosso alfa aberto, onde planejamos disponibilizar um mapa gratuitamente para obter feedback da comunidade. Estávamos ansiosos por todo esse feedback, mas não pelo esforço manual envolvido na aplicação dele aos nossos mapas.
Outra possível desvantagem de um fluxo de trabalho de design baseado em pré-fabricados é o desempenho. Nosso principal objetivo é usar headsets VR independentes e móveis para nossos jogos. Queremos levar os recursos visuais o mais longe possível, então precisamos extrair até a última gota de desempenho do nosso fluxo de trabalho.
Montar níveis a partir de Prefabs pode ser menos eficiente do que criar uma malha estanque em um programa de modelagem. Se você encaixar duas peças de parede modulares, sempre terá um loop geométrico não mesclado entre elas. Com os Prefabs, também é fácil acabar colocando muita geometria na sua cena que não é visível (porque está na parte inferior de um objeto ou encostada em uma parede), mas ainda ocupa um espaço valioso no mapa de luz. Em um nível inteiro, essas pequenas ineficiências podem resultar em desempenho desperdiçado e visuais reduzidos.

O último problema com Prefabs que queremos mencionar é que pode ser fácil quebrar coisas ao aplicar alterações aparentemente inocentes ao modelo de origem no Blender, como renomear um objeto. À medida que um jogo ou nível evolui, muitas vezes você deseja reorganizar seus recursos e dar a eles nomes melhores ou mais consistentes. Mas renomear um objeto no Blender e reexportá-lo pode facilmente (e sem aviso) quebrar as substituições e adições feitas ao objeto no Unity, levando a regressões.
Neste exemplo simplificado, temos uma grelha de ventilação pré-fabricada e queremos que saia fumaça por ela. Depois de importar a malha para o Unity, nosso artista adicionou o sistema de partículas de fumaça como um objeto filho e adicionou um componente de tipo de superfície ao Prefab para marcá-lo como um objeto de metal.
Aqui você pode ver o que acontece se renomearmos nossa malha no Blender:
Ao reimportar a malha com o nome atualizado, o Unity não consegue mais encontrar a malha antiga pelo nome, então ele remove o objeto do modelo Prefab. Os filhos desse objeto removido são movidos para a raiz do Prefab e os scripts existentes são removidos, novamente levando ao trabalho de limpeza manual que preferiríamos evitar.
À medida que a fase de prototipagem de Breachers terminava e nos preparávamos para entrar em modo de produção total no início de 2022, nossas equipes de arte e desenvolvimento se reuniram e investigaram o que poderíamos fazer para resolver esses problemas. Definimos metas claras para nosso pipeline de ativos ideal, um que daria suporte à iteração rápida e flexível necessária para Breachers:
- Toda a criação e modificação da geometria dos níveis deve acontecer no Blender.
- WYSIWYG: O que um designer cria no Blender deve corresponder o máximo possível ao resultado no Unity .
- Quando algo é atualizado no Blender, a importação das alterações para o Unity deve acontecer automaticamente e não exigir nenhum esforço manual.

Como mencionado acima, nosso principal objetivo era ter uma visualização precisa do jogo no Blender – não apenas refletindo adequadamente como o resultado final ficará no Unity , mas também como a mecânica do jogo é configurada. A jogabilidade em Breachers não depende apenas do layout do nível, mas também de objetos dinâmicos (como paredes quebráveis) e elementos invisíveis (como volumes de som e aceleradores). Queremos que todas essas informações sejam visíveis na fase de design e transferidas precisamente para o Unity.
![Figura 5: Imagem de Breachers fornecida pela Triangle Factory [Parte do nosso nível Skyscraper no Blender (somente geometria de nível estático e adereços)]](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Ffuvbjjlp%2Fproduction%2F3d1ec8eaf99391b246965c8a7ac1fafd1b6f121c-3810x2058.png&w=3840&q=75)



Propriedades personalizadas são essenciais para nosso fluxo de trabalho e as atribuímos a objetos no Blender. Eles são então transportados para o Unity pelo formato FBX, para que possamos lê-los e executar lógica personalizada quando nossos ativos são importados para o Unity.

Isso nos dá uma grande flexibilidade e estabilidade. Essas propriedades permanecem conectadas aos objetos por todo o pipeline, para que possamos reorganizar e renomear coisas em nossos níveis o quanto quisermos, sem nos preocupar com coisas quebrando ou ficando fora de sincronia.
O Unity tem uma classe poderosa chamada AssetPostprocessor, que permite modificações de ativos enquanto eles estão sendo importados. É isso que usamos no momento da importação para analisar essas propriedades personalizadas e agir sobre elas.
Links pré-fabricados
Temos uma propriedade personalizada chamada PrefabLink, que informa ao Unity que o objeto importado do Blender deve ser substituído por um Prefab já existente no projeto do Unity , preservando a transformação do modelo importado. Isso nos permite colocar esses objetos dinâmicos no Blender , mantendo as vantagens dos Prefabs quando eles são importados para o Unity. As barricadas de janela na cena do Blender acima são um bom exemplo disso.

Tipos de superfície
A definição de superfície é extremamente importante em Breachers. Andar em uma escada de metal soa diferente de andar em um piso de concreto. A penetração de uma bala na madeira é muito diferente da penetração no aço. E cada tipo de superfície tem seus próprios efeitos de impacto. Analisar cada suporte no Unity e marcá-lo como o tipo de superfície correto levaria muito tempo, então também abordamos isso na fase de design no Blender , definindo propriedades personalizadas em nossos aceleradores de geometria.
Bandeiras estáticas
Outra configuração importante para otimização são os sinalizadores estáticos do Unity. Definir essas configurações corretamente pode ter um impacto profundo em coisas como redução de visibilidade, cozimento leve e dosagem. Usando propriedades personalizadas no Blender, podemos defini-las em qualquer parte do nível, incluindo acessórios reutilizáveis, e fazer com que essas informações sejam transferidas para o Unity em todos os nossos níveis.
Colisores
Por fim, gostaríamos de compartilhar como configuramos os aceleradores. O Unity tem um sistema simples, mas eficaz, que detecta automaticamente variantes de nível de detalhe para modelos quando você adiciona um nome de ativo de modelo com _LOD0, _LOD1, etc. Ficamos inspirados por isso e criamos um sistema semelhante para aceleradores: Ao simplesmente ter geometria com _BoxCollider ou _NoCollision no nome, substituímos as malhas do Blender por colisores no Unity.


Como exemplo concreto, aqui está um trecho do nosso LevelSetupPostprocessor que lê propriedades personalizadas e atribui os sinalizadores estáticos corretos em cada objeto importado:
Para que tudo isso funcionasse bem, tivemos que trabalhar um pouco também no Blender .
As propriedades personalizadas ficam um pouco escondidas na interface do Blender e exigiriam que os artistas digitassem manualmente as propriedades personalizadas toda vez, o que não é uma ótima experiência para o usuário. Depender da entrada manual de texto também seria muito propenso a erros, anulando grande parte da vantagem de configurar as coisas no Blender em primeiro lugar. Mudar de um fluxo de trabalho baseado em Prefabs para o Blender também nos fez perder algumas das vantagens dos Prefabs, como ter uma boa biblioteca de objetos para navegar e escolher. Felizmente, o Blender, assim como o Unity, é muito flexível e facilmente extensível.
A resposta para o problema de organização do Prefab veio no Blender 3.2 com Bibliotecas de Ativos. Este sistema funciona um pouco como o sistema Prefab no Unity: Ele permite que você crie ativos em um arquivo separado e depois os importe para sua cena do Blender , enquanto as alterações no arquivo de ativos são refletidas automaticamente na cena do Blender . Além disso, ele garante que quaisquer propriedades personalizadas ou colisores sejam aplicados corretamente a cada instância deste ativo no Blender.


Para o Blender, escrevemos um complemento interno para ajudar a configurar as propriedades personalizadas em uma interface de usuário mais clara. Isso simplifica a configuração de propriedades personalizadas, bastando selecionar os objetos relevantes do Blender e clicar em um botão, em vez de digitar cada propriedade manualmente.
O complemento Bundle Exporter é um complemento de código aberto que usamos para exportar todos os nossos arquivos FBX com um clique. Nós o modificamos para funcionar também com propriedades personalizadas e atualizamos a interface do usuário para ter exportações mais rápidas para nossas necessidades específicas.

Configurar nosso fluxo de trabalho de design de níveis para Breachers exigiu um grande investimento de tempo inicialmente, mas acreditamos que foi a escolha certa para o projeto. E também foi bem divertido!
À medida que desenvolvemos o jogo desde os blocos iniciais até os testes alfa e os meses que antecederam o lançamento final, a iteração em nossos níveis foi rápida e tranquila. Conseguimos eliminar despesas gerais e trabalho burocrático para nossos designers e artistas, ao mesmo tempo em que transferimos a eles responsabilidades que antes precisariam de um desenvolvedor.
Ficamos impressionados com a capacidade de integração entre Unity e Blender , e acreditamos firmemente que essa integração foi essencial para tornar Breachers um jogo com o qual estamos felizes e orgulhosos de compartilhar com o mundo.
Obrigado pela leitura e aproveite o jogo!

Breachers da Fábrica Triângulo já está disponível. Confira mais blogs de desenvolvedores do Made with Unity aqui.
