DrakkenRidge: Building an open-world adventure for mobile VR
Simeon Acker and Cyril Guichard - Garage Collective
GUEST BLOG
Made with Unity, DrakkenRidge é um RPG de ação em mundo aberto da Garage Collective, projetado e otimizado para realidade virtual móvel. Neste post de blog para convidados, a equipe compartilha como aproveita diversas técnicas de design e desempenho, utilizando o Sistema de Componentes de Entidade (ECS) da Unity como base para a renderização.

Apresentando o DrakkenRidge VR
Somos a Garage Collective, a equipe por trás de DrakkenRidge , um RPG de ação em mundo aberto desenvolvido para realidade virtual, onde você pode visitar qualquer ponto que avistar no horizonte. Assuma o papel de um poderoso Caçador de Magos e explore seis ilhas belíssimas, criadas à mão – cada uma totalmente única, com seus próprios personagens, missões, masmorras e segredos.
Esta jornada levará você de praias quentes e aconchegantes a picos nevados de tirar o fôlego; de florestas exuberantes e místicas a abismos perigosos nas profundezas da terra. Crie novos itens, enfrente dezenas de criaturas e inimigos artisticamente elaborados e desbloqueie novas escolas de magia que podem transformar cada encontro em uma experiência única.
Construir um jogo desta magnitude com uma equipe de duas pessoas provavelmente não seria possível sem o Sistema de Componentes de Entidade . Neste post, vamos abordar como usamos essas ferramentas para criar nosso extenso jogo de aventura.
Misturando técnicas para um desenvolvimento de jogos mais fluido
Existem diversas vantagens significativas ao usar o ECS para desenvolver um jogo, mas, como um pequeno estúdio independente, tivemos que levar em consideração outros fatores ao decidir como projetar e desenvolver DrakkenRidge para realidade virtual móvel.
Existem dois desafios principais ao usar o ECS:
- A curva de aprendizagem acentuada: O desenvolvimento com ECS exige uma mudança completa de paradigma, abandonando a lógica orientada a objetos típica.
- A separação dos sistemas de entidades dos sistemas tradicionais de objetos de jogos pode tornar suas interações complexas.
Então a questão para nós passou a ser:
Quais objetos e interações devem aproveitar o poder do ECS e quais objetos devem permanecer como GameObjects e MonoBehaviours tradicionais?
Entities em DrakkenRidge
DrakkenRidge consiste em ambientes abertos e vastos, com dezenas de milhares de objetos em um determinado espaço – potencialmente milhares deles visíveis para o jogador a qualquer momento.
Renderizar esses objetos como GameObjects tradicionais exige uma grande sobrecarga de memória, pois o mecanismo precisa avaliar toda a hierarquia da cena e calcular os componentes Transform para cada objeto. Ao renderizar milhares de objetos, especialmente em um dispositivo móvel, a GPU sofrerá um impacto considerável.
E se pegássemos esses objetos e os renderizássemos como Entities ?

Como Entities, elas evitam grande parte da sobrecarga de renderização e memória associada aos GameObjects e, em vez disso, são agrupadas em blocos de memória usando os Entities Graphics.sistema.
Além disso, o pipeline artístico da DrakkenRidge utiliza amplamente a técnica de Atlas de Texturas, permitindo que os ambientes massivos usem menos materiais no geral (veja nossa postagem no blog sobre Atlas de Texturas aqui ).
O Entities Graphics consegue agrupar e manipular todos os objetos que compartilham uma malha e um material em comum, e então o mecanismo pode criar chamadas de desenho compactas e renderizar vários objetos simultaneamente.
O resultado disso pode economizar centenas de lotes e chamadas SetPass.

Renderizando milhares de objetos – com apenas oito chamadas SetPass
Sistemas de Entidades Personalizadas
O DrakkenRidge utiliza o ECS para renderizar milhares de objetos simultaneamente. Mas mesmo com os enormes ganhos de desempenho que isso proporciona, ainda há mais que podemos fazer para melhorar a experiência em plataformas de realidade virtual móvel.
Sistema de autoria à distância
A primeira funcionalidade que criamos para nossas Entities DrakkenRidge é o sistema de autoria por distância. Leva em consideração uma variedade de variáveis para determinar quando um objeto deve ser ocultado ou visível para o jogador.
Como o campo de visão do jogador se estende muito longe no mundo aberto, milhares de objetos distantes podem estar visíveis ao mesmo tempo. Este sistema prioriza quais desses elementos devem permanecer em destaque e quais devem se integrar ao fundo. Efeitos ambientais, como neblina à distância, são usados para disfarçar a transição à medida que objetos distantes desaparecem da vista.

Componente de autoria à distância com valores personalizados para eliminação de entidades em tempo de execução.
Valores de eliminação exclusivos são gerados no Editor para cada Entidade com base em diversos parâmetros. Esses dados são então passados, no momento da criação da entidade , para os sistemas.que utilizam esses dados pré-calculados para tomar decisões em tempo de execução sobre quando as Entities devem ser renderizadas ou descartadas.
Grupos de entidades personalizadas
Utilizando o sistema de autoria por distância DrakkenRidge , as Entities podem ser atribuídas a grupos com tomada de decisão compartilhada, permitindo, por exemplo, que uma seção da cidade seja renderizada ou descartada rapidamente com base em vários fatores do jogo, em vez de cada entidade na cidade decidir individualmente.

Entities agrupadas com tomada de decisão compartilhada
LODs de entidade
A terceira funcionalidade do sistema de autoria por distância DrakkenRidge permite que entidades sejam trocadas dinamicamente por outra entidade que seja ainda mais barata de renderizar. Essa técnica foi originalmente desenvolvida para solucionar o problema de shaders e materiais mais caros.
Embora os modelos de ambiente em DrakkenRidge já sejam altamente otimizados, alguns shaders adicionam um custo perceptível. Este sistema de LOD (Nível de Detalhe) de entidades permite renderizar "versões de entidades com shaders de custo mais elevado" somente quando necessário.
/// If using a simplified LOD object, see if we are in its range
if (inDistanceReturn.useLOD)
{
if (inDistanceReturn.isInDistanceLOD)
{
ecbParallel.SetEnabled(unfilteredChunkIndex, inDistanceReturn.lodEntity, true);
if (ChildLookup.TryGetBuffer(inDistanceReturn.lodEntity, out lodChildBufferData))
{
var newParent = inDistanceReturn.lodEntity;
SetEnableChildren(
entityCanBeReEnabledComponentLookup: entityCanBeReEnabledComponentLookup,
unfilteredChunkIndex: unfilteredChunkIndex,
parentEntity: newParent,
enabled: true,
childBufferData: lodChildBufferData,
ChildLookup: ChildLookup,
ecbParallel: ecbParallel);
}Quando as condições forem atendidas, utilize um LOD) simplificado para a entidade.
Otimizações de CPU
Os cálculos de autoria de distância do DrakkenRidge são executados por meio de Jobs compilados em rajada para obter o máximo desempenho da CPU.
Os Jobs do Unity são funções que podem ser agendadas como tarefas assíncronas para serem executadas em segundo plano, e o compilador BurstAcelera tarefas que exigem muito da CPU, traduzindo-as em código de máquina nativo altamente otimizado.
[BurstCompile]
public partial struct ProcessBufferJob : IJobChunk
{
internal EntityCommandBuffer.ParallelWriter ecbParallel;
public EntityTypeHandle entityTypeHandle;
[ReadOnly] public BufferTypeHandle<Child> childTypeHandle;
[ReadOnly] public ComponentTypeHandle<DistanceCompData> distanceCompDataTypeHandle;
// A BufferLookup for random access to Child buffers.
[ReadOnly] public BufferLookup<Child> childLookup;
[ReadOnly] public ComponentLookup<Disabled> disabledComponentLookup;
public PlayerDesignatorCompData targetDesignator;
public HelperStructToUpdateEnabledEntities addToBufferStruct;
public Entity playerEnt;
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
{
var entities = chunk.GetNativeArray(entityTypeHandle);
var childAccessor = chunk.GetBufferAccessor(ref childTypeHandle);
var distanceCompData = chunk.GetNativeArray(ref distanceCompDataTypeHandle);
bool hasChildBuffer = chunk.Has(ref childTypeHandle);
DynamicBuffer<Child> lodChildBufferData;
for (int i = 0; i < chunk.Count; i++)
{
Entity currentEntity = entities[i];Dica: Uma otimização para DynamicBuffer é convertê-lo para um NativeArray antes da iteração: “var lodChildNativeArray = lodChildBufferData.AsNativeArray();”
GameObjects e física em DrakkenRidge
Em DrakkenRidge , 90% do mundo é renderizado usando ECS, executando suas próprias tarefas em segundo plano para manter o ambiente visível em um estado bonito e otimizado.
Mas, para nossa pequena equipe de desenvolvimento, composta por um programador e um artista, decidimos construir muitas de nossas interações de realidade virtual em close-up usando GameObjects e MonoBehaviors tradicionais. Isso permitiu um tempo de iteração mais rápido em um ambiente de testes rápidos e ciclos de design frequentes.
Interações físicas e combate
As interações de realidade virtual em DrakkenRidge são impulsionadas principalmente por simulações físicas. Isso inclui tudo, desde agarrar e manipular objetos, até escalada e parkour, passando por lançamento de feitiços e combate corpo a corpo.
Os jogadores podem interagir com desafios de escalada baseados em física.
Executando simulações de física em mundo aberto.
O combate em DrakkenRidge é conduzido por um sistema que combina animações únicas com comportamentos físicos específicos para cada articulação. Cada IA decide como fazer com que sua morte pareça uma reação satisfatória e recompensadora, dependendo da situação.
Combinando física por articulação com animações pré-programadas para criar reações únicas.
Em DrakkenRidge, muitos itens e feitiços permitem que o jogador cause dano a vários inimigos ao mesmo tempo, resultando frequentemente em simulações físicas sendo executadas em vários modelos de personagens simultaneamente.
Aplicando a física de explosivos a grupos de IA
Otimizações físicas
Simulações físicas em tempo real podem ser dispendiosas, especialmente em plataformas móveis. Para ajudar a mitigar isso, cada objeto físico no mundo rastreia a localização do jogador e se o jogador está ou não em posição de interagir com a simulação.
Por exemplo, o jogador pode escalar longas correntes construídas com elos controlados pela física, que interagem entre si e com o mundo ao seu redor. Esses colisores físicos, juntas e corpos rígidos são ativados/desativados dinamicamente, dependendo se o jogador está manipulando diretamente a cadeia ou se ela está à vista.
De forma geral, renderizamos objetos a grandes distâncias, mas permitimos interações físicas apenas com objetos próximos. Em um jogo de realidade virtual, onde a ação acontece de perto, isso está de acordo com o que o jogador espera.
Otimizações adicionais
Ao decidir como otimizar nossa renderização para realidade virtual móvel, consideramos como cada ambiente foi construído e escolhemos a solução que melhor se adequava às nossas necessidades.
Além do ECS, consideramos uma variedade de técnicas, incluindo LODs e impostores .
LODs de GameObject
Renderizar GameObjects com LODs consiste em ter múltiplas versões de um determinado objeto para serem renderizadas a diferentes distâncias do jogador. Por exemplo, um modelo de casa altamente detalhado é substituído por uma versão simplificada com poucos polígonos, economizando tempo de renderização quando o jogador está longe do objeto.
Em DrakkenRidge , todos os objetos já estão modelados em um estilo retrô de baixa poligonagem altamente otimizado, e a grande maioria do mundo é gerenciada por meio de ECS, portanto, os LODs 3D tradicionais não ofereceriam nenhuma vantagem real.
No entanto, a autoria à distânciaO sistema que criamos foi desenvolvido para lidar com a renderização de níveis de detalhe (LODs) para Entities distantes, quando necessário.
Impostores
Um sistema de impostores pega objetos 3D do GameObjects e os converte em outdoors 2D quando o jogador está a uma certa distância deles. Isso funciona melhor para objetos de fundo densos e distantes, como florestas. DrakkenRidge utiliza impostores em algumas situações.

Impostores implementados corretamente são indistinguíveis de suas contrapartes em 3D .
Em DrakkenRidge, testamos diversas técnicas de otimização, escolhendo cuidadosamente quais implementar. O Unity ECS proporcionou, de longe, os maiores ganhos de desempenho, renderizando todo o nosso mundo a uma fração do custo do uso do pipeline GameObject tradicional.
Considerações finais
Para DrakkenRidge , nossa combinação de técnicas de design e otimização provou ser a receita perfeita, permitindo-nos construir uma aventura de realidade virtual única. O mundo aberto é alimentado pelo ECS para Unity, e nossas interações de perto são projetadas com o fluxo de trabalho familiar de GameObject e física, permitindo que a equipe projete, teste e itere rapidamente.
Jogos de RPG de mundo aberto para realidade virtual móvel não precisam ser inacessíveis, e estamos ansiosos para ver mais desenvolvedores embarcando nessa aventura!

DrakkenRidge VR já está disponível . Explore mais jogos Made with Unity na nossa página de curadoria do Steam e confira mais histórias de desenvolvedores da Unity no Blog da Unity e no Centro de Recursos .