Pesquisar em Unity

Uso de prefabs light-baked em dispositivos móveis

e outros truques simples para alcançar 60fps em telefones mais básicos

Last updated: January 2019

What you will get from this page: Michelle Martin, software engineer at MetalPop Games explains how they optimized their new mobile strategy game, Galactic Colonies, for a range of mobile devices, so they could reach as many potential players as possible.

MetalPop Games faced the challenge of making a game in which players could build huge cities on their low-end devices, without their framerate dropping or their device overheating. See how they found a balance between good-looking visuals and solid performance.

Construção de cidades em dispositivos mais básicos

As powerful as mobile devices are today, it is still very difficult to run large and good looking game environments at a solid frame rate. Achieving solid 60fps in a large scale 3d environment on an older mobile device can be quite a challenge.

As developers we could just target high-end phones and assume that most players will have good enough hardware to run our game smoothly. But this will result in locking out a huge amount of potential players, as there are still many older devices in use. Those are all potential customers you don’t want to exclude if it can be avoided.

In our game Galactic Colonies, the players colonize alien planets and can build huge colonies made up from a large number of individual buildings. While smaller colonies might only have a dozen buildings, larger ones can easily have hundreds of them.

This is what our goal list looked like when we started building our pipeline:

  • We want huge maps with a high amount of buildings
  • We want to fast run on cheaper and/or older mobile devices
  • We want nice looking lights and shadows
  • We want an easy and maintainable production pipeline
Iluminação em jogos móveis: os desafios habituais

Boa iluminação no jogo é a chave para tornar os modelos 3D impressionantes. Claro, no Unity isso é realmente fácil: Configure o nível, coloque a iluminação dinâmica e já está! E se você precisa ficar de olho no desempenho, basta usar light-baking e adicionar um pouco de SSAO e outras pequenas fantasias gráficas atrativas através da pilha de pós-processamento. E é tudo!

A configuração de iluminação em jogos para dispositivos móveis geralmente requer muitos truques e soluções alternativas. Por exemplo,a menos que você esteja segmentando dispositivos de última geração, é melhor não usar efeitos de pós-processamento. Mesmo cenas grandes com iluminação dinâmica reduzem drasticamente ao framerate.

A iluminação em tempo real pode consumir muito tempo, mesmo em um PC desktop. Em dispositivos móveis, as limitações de recursos são ainda maiores e você não poderá fazer todas as coisas maravilhosas que gostaria.

Light baking ao resgate

Em dispositivos móveis, os recursos são bastante limitados e você não quer sobrecarregar as baterias dos usuários mais do necessário usando muita iluminação em sua cena.

Se você leva constantemente um dispositivo aos limites do hardware, o telefone ficará quente e, consequentemente, será desativado automaticamente para se proteger. Neste ponto, você normalmente faria light-baking em qualquer lugar onde não são necessárias sombras em tempo real.

Unity light baked prefabs for mobile MetalPopGames Galactic Colonies

(Um nível típico em colônias galácticas com um elevado número de edifícios)

Para nós, isso não era uma opção, já que nosso mundo de jogo é construído em tempo real pelo jogador. A descoberta constante de novas regiões, a construção de novos edifícios ou a melhoria dos edifícios existentes impedem qualquer tipo de light baking eficiente.

Simule até você conseguir

O processo de light baking é o pré-cálculo de pontos luminosos e sombras para uma cena (estática) e o armazenamento das informações em um lightmap.

O processo está dizendo ao renderizador onde tornar um modelo mais claro ou mais escuro, criando a ilusão de luz.

Renderizar as coisas dessa maneira é muito rápido, porque todos os cálculos de luz lenta e custosos foram feitos offline. Em tempo de execução, o renderizador (shader) só precisa ler o resultado em uma textura.

A desvantagem aqui é que você terá que adicionar algumas texturas de lightmap extra, que aumentam o tamanho da compilação e exigem espaço de textura adicional no tempo de execução.

Você também está perdendo algum espaço porque seus meshes precisam de UVs lightmap, o que os torna um pouco maiores.

Mas no geral você vai ganhar um tremendo aumento de velocidade.

Unity light baked prefabs for mobile MetalPopGames

(Um edifício com e sem lightmap)

Mas, clicar simplesmente no botão Bake não funcionará se você tiver um mundo dinâmico que possa ser constantemente alterado pelo jogador.

Somos confrontados com uma série de problemas que surgem no processo baking lights para cenas altamente modulares.

Light baking não é tão fácil com prefabs

Em primeiro lugar, os dados de light-baking em Unity são armazenados e diretamente associados aos dados da cena. Isso não é um problema se você tiver níveis individuais e cenas pré-compiladas e tiver apenas alguns objetos dinâmicos. Você pode pré-processar a iluminação, e já está!

Obviamente, isso não funciona quando você cria seus níveis dinamicamente. Em um jogo de construção de cidades, o mundo não é pré-criado. Em vez disso, ele é montado dinâmica e espontaneamente pelo jogador que decide o que construir e onde construí-lo. Isso geralmente é feito instanciando prefabs onde quer que o jogador decida construir algo.

A única solução para esse problema é armazenar todos os dados relevantes de light-baking dentro da prefab em vez da cena.

Infelizmente não existe uma maneira fácil de copiar os dados do lightmap, e as suas coordenadas a usar e escalá-lo para um prefab.

Criação de um pipeline para prefabs light-baked

A melhor abordagem para conseguir um pipeline sólido lidando com prefabs light baked é criar as prefabs em uma cena separada diferente (várias cenas, na verdade) e, em seguida, carregá-las no jogo principal quando necessário.

Cada área modular passa pelo processo light-bake e depois é carregada no jogo quando necessário.

Quando você dá uma olhada de perto como o light-baking funciona no Unity, você pode ver que renderizar um light baked mesh é realmente aplicar outra textura e clarear, escurecer (ou às vezes colorir) um pouco o mesh. Tudo o que você precisa é da textura lightmap e das coordenadas UV - ambas criadas pela Unity durante o processo light baking.

Durante o processo light baking, Unity cria um novo conjunto de coordenadas UV (que apontam para a textura do lightmap) e um deslocamento e escala para o mesh individual. A reintrodução de luzes muda essas coordenadas todas as vezes.

Como utilizar os canais UV

Para desenvolver uma solução para esse problema, é útil entender como os canais UV funcionam e como melhor utilizá-los.

Cada mesh pode ter vários conjuntos de coordenadas UV (chamados de canais UV no Unity). Na maioria dos casos, um conjunto de UVs é suficiente, pois as diferentes texturas (Diffuse, Spec, Bump, etc) armazenam todas as informações no mesmo local da imagem.

Mas quando os objetos compartilham uma textura, como um lightmap, e precisam pesquisar as informações de um lugar muito específico em uma textura grande, geralmente não há como adicionar outro conjunto de UVs para uso com essa textura compartilhada.

A desvantagem de usar várias coordenadas UV é que elas consomem memória adicional. Se você estiver usando dois conjuntos de UVs em vez de apenas um conjunto, CADA um dos vértices do mesh agora tem o dobro da quantidade de coordenadas UV. Para cada vértice, você está armazenando dois números adicionais de ponto flutuante e também fazendo o upload deles para a GPU durante a renderização.

Criação de prefabs

O Unity é usado para gerar as coordenadas e o lightmap, usando a funcionalidade regular de light baking. A engine grava as coordenadas UV do lightmap no segundo canal UV do modelo. É importante observar que o conjunto principal de coordenadas de UV não pode ser usado para isso, porque o modelo precisa ser descompactado.

Imagine uma caixa usando a mesma textura para cada um dos seus lados: Todos os lados da caixa têm as mesmas coordenadas UV, porque reutilizam a mesma textura. Mas isso não funcionará para um objeto lightmap, pois cada lado da caixa é atingido por luzes e sombras individualmente. Cada lado precisa de seu próprio espaço no lightmap com seus dados individuais de iluminação. Daí a necessidade de um novo conjunto de UVs.

Então, para montar uma nova prefab light baked, tudo o que precisamos fazer é armazenar a textura e as coordenadas para que não sejam perdidas e copiá-las na prefab.

Após o light baking, executamos um script que percorre todos os meshes da cena e grava as coordenadas UV no canal UV2 real da malha, usando os valores para deslocamento e dimensionamento.

O código para modificar os meshes é relativamente direto:

Mesh meshToModify = GetComponent().sharedMesh;
Vector4 lightmapOffsetAndScale = GetComponent().lightmapScaleOffset;

Vector2[] modifiedUV2s = meshToModify.uv2;
for (int i = 0; i < meshToModify.uv2.Length; i++)
{
    modifiedUV2s[i] = new Vector2(meshToModify.uv2[i].x * lightmapOffsetAndScale.x +
    lightmapOffsetAndScale.z, meshToModify.uv2[i].y * lightmapOffsetAndScale.y +
    lightmapOffsetAndScale.w);
}
meshToModify.uv2 = modifiedUV2s;

Para ser um pouco mais específico: isso é feito com uma cópia dos meshes, e não com o original, porque estamos fazendo otimizações adicionais em nossos meshes durante o processo de baking.

As cópias são geradas automaticamente, salvas em uma prefab e atribuídas a um novo material com um shader personalizado e o lightmap recém-criado. Isso deixa nossos meshes originais intocados, e os prefabs light baked estão imediatamente prontos para serem usados.

Um shader de lightmap personalizado

Isso simplifica o fluxo de trabalho. Para atualizar o estilo e a aparência do gráfico, basta abrir a cena correspondente, fazer as alterações desejadas e clicar em "start" para iniciar o processo automatizado "Bake and Copy". Quando esse processo terminar, tudo estará pronto e o jogo começará a usar os prefabs e os meshes atualizados com a iluminação atualizada.

A textura real do lightmap é adicionada por um shader personalizado, que aplica o lightmap como uma segunda textura ao modelo durante a renderização.

O shader é muito simples e curto, e além de aplicar a cor e o lightmap, calcula um simples efeito especular/brilho falso.

Shader "Custom/LightmappedPrefabWithSpec"
{
  Properties
  {
    _MainTex("Base (RGB)", 2D) = "white" {}
    _Lightmap("Lightmap", 2D) = "white" {}
    _Specmap("Specmap", 2D) = "white" {}
    _SpecularAtt("Glossiness", Range(0.1, 2)) = 0.5
    _SpecularAmt("Specular", Range(0, 1)) = 0.5
  }

  SubShader
  {
    Tags{ "Queue" = "Geometry+1" }
    Pass
    {
      CGPROGRAM

      // Defining the name of the vertex shader
      #pragma vertex vert

      // Defining the name of the fragment shader
      #pragma fragment frag


      // Include some common helper functions,
      // specifically UnityObjectToClipPos and DecodeLightmap.
      #include "UnityCG.cginc"

      // Color Diffuse Map
      sampler2D _MainTex;
      // Tiling/Offset for _MainTex, used by TRANSFORM_TEX in vertex shader
      float4 _MainTex_ST;


      // Lightmap (created via Unity Lightbaking)
      sampler2D _Lightmap;
      // Tiling/Offset for _Lightmap, used by TRANSFORM_TEX in vertex shader
      float4 _Lightmap_ST;

      // Grayscale Map indicating which parts of the models have specular
      // Note: _Specmap_ST is not needed, as this map is using the same
      // UVs as for the _MainTex.
      sampler2D _Specmap;

      // This is the vertex shader input: position, UV0, UV1, normal
      // UV1 (= second UV channel) needed for the lightmap texture coordinates
      struct appdata
      {
        float4 vertex   : POSITION;
        float2 texcoord : TEXCOORD0;
        float2 texcoord1: TEXCOORD1;
        float3 normal: NORMAL;
      };

      // This is the data passed from the vertex to fragment shader
      struct v2f
      {
        float4 pos  : SV_POSITION; // position of the pixel
        float2 txuv : TEXCOORD0; // for accessing the diffuse color map
        float2 lmuv : TEXCOORD1; // for accessing the light map
        float3 normalDir : TEXCOORD2; // for fake specular
      };

      // This is the vertext shader, doing nothing special at all.
      // Most notably it is calculating the surface normal, because that
      // is needed for the fake specular lighting in the fragment shader.
      v2f vert(appdata v)
      {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.txuv = TRANSFORM_TEX(v.texcoord.xy, _MainTex); // using _MainTex_ST
        o.lmuv = TRANSFORM_TEX(v.texcoord1.xy, _Lightmap); // using _Lightmap_ST

        // Calculating the normal of the vertex for the fragment shader
        float4x4 modelMatrixInverse = unity_WorldToObject;
        o.normalDir = normalize(mul(float4(v.normal, 0.0), modelMatrixInverse).xyz);

        return o;
      }

      uniform float _SpecularAtt;
      uniform float _SpecularAmt;

      // Fragment Shader
      half4 frag(v2f i) : COLOR
      {
        // Reading color directly from the diffuse texture, using first UV channel
        half4 col = tex2D(_MainTex, i.txuv.xy);
        // Reading specular (on/off) value from spec map texture
        half4 specVal = tex2D(_Specmap, i.txuv.xy);
        // Reading lightmap value from the lightmap texture
        half4 lm = tex2D(_Lightmap, i.lmuv.xy);

        // Fake specular light angle calculation with a hard-coded light direction
        half3 th = normalize(half3(0, 1, -0.25));
        float spec = max(0, dot(i.normalDir, th));

        // Adjusting by overall specular amount and glossyness (material parameters)
        spec = _SpecularAmt * pow(spec, 40.0 * _SpecularAtt);
        // We're just using red value of the specular texture, like a grayscale map,
        // although technically spec could be colored.
        // Example: float3 specCol = specVal * spec;
        spec = spec * specVal.r;

        // Calculating the final color of the pixel by bringing it all together
        col.rgb = min(half4(1,1,1,1), col.rgb * DecodeLightmap(lm) + col.rgb * spec);
        return col;
      }
      ENDCG
    }
  }
  Fallback "Diffuse"
}

Aqui está uma imagem de uma configuração de material usando o shader acima:

Unity light baked prefabs for mobile Material setup MetalPopGames

(Configuração de material usando um shader personalizado)

Configuração e Batching Estático

No nosso caso, temos quatro cenas diferentes com todos os prefabs configurados. Nosso jogo apresenta diferentes biomas, como trópico, gelo, deserto, etc. e dividimos nossas cenas de acordo. Para o seu jogo, o número de cenas pode variar, dependendo das suas necessidades.

Todos os prefabs usados em uma determinada cena compartilham um único lightmap. Isso significa que, além dos prefabs, que compartilham apenas um material, apenas é necessária uma textura extra.

Como resultado, conseguimos renderizar todos os modelos como estáticos e renderizar em lote quase todo o nosso mundo com apenas um draw call.

Unity light baked prefabs for mobile bake level MetalPopGames

(O nível de baking no editor Unity)

As cenas light baking, nas quais todos os nossos tiles/edifícios estão configurados, possuem fontes de luz adicionais para definir pontos de luz fixos. Você pode colocar tantas fontes de luz nas cenas de configuração quanto quiser, já que elas já estão simplificadas no processo de baking.

O processo de baking é controlado por meio de uma caixa de diálogo personalizada da interface do usuário, que suporta todas as etapas necessárias. Isso garante que:

  • The correct material is assigned to all meshes
  • Hides everything that doesn’t need to be baked during the process
  • Combines/bakes the meshes
  • Copies the UVs and creates prefabs
  • Names everything correctly and checks out the necessary files from the version control system

Unity light baked prefabs for mobile custom inspector MetalPopGames

(Inspetor personalizado para um fluxo de trabalho fácil)

Prefabs com o nome correto são criados a partir desses meshes para que o código do jogo possa carregá-los e usá-los diretamente. Os metarquivos também são alterados durante esse processo, de modo que as referências aos meshes de prefabs não se percam.

Este fluxo de trabalho nos permite otimizar nossos edifícios tanto quanto queremos, iluminá-los como quisermos e deixar o restante do trabalho para o script.

Quando voltamos à nossa cena principal e executamos o jogo, ele simplesmente funciona - intervenção manual ou atualizações adicionais não são necessárias.

Luz falsa e bits dinâmicos

Uma das desvantagens óbvias de uma cena em que 100% da iluminação é pre-baked é a dificuldade de ter objetos ou movimentos dinâmicos. Qualquer coisa que crie uma sombra exigiria um cálculo de luz e sombra em tempo real, o que naturalmente queremos evitar. Mas sem nenhum objeto em movimento, o ambiente 3D pareceria estático e morto.

É claro que estávamos dispostos a aceitar algumas limitações, pois nossos principais objetivos eram bons recursos visuais e renderização rápida. Para dar a impressão de uma colônia espacial ou cidade viva, não era necessário que muitos objetos fossem realmente móveis. E a maioria dos objetos em movimento não precisava necessariamente projetar sombras, ou pelo menos a falta de sombras não era perceptível.

No nosso caso, começamos dividindo todos os blocos de construção da cidade em dois prefabs separados. Uma parte estática, que continha a maioria dos vértices, todos os bits complexos de nossos meshes - e uma dinâmica, contendo o menor número possível de vértices.

As partes dinâmicas de um prefab são bits animados colocados sobre os estáticos. Eles não são light baked, e usamos um shader de iluminação falso muito rápido e simples para criar a ilusão de que o objeto estava iluminado dinamicamente.

Shader "Custom/FakeLighting"
{
  Properties
  {
    _Color ("Color", Color) = (1,1,1,1)
    _Brightness ("Brightness", Range(0,1)) = 0.4
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
  }

  SubShader
  {
    Tags { "RenderType" = "Opaque" }
    LOD 200
    Pass
    {

      CGPROGRAM

      // Define name of vertex shader
      #pragma vertex vert
      // Define name of fragment shader
      #pragma fragment frag

      // Include some common helper functions, such as UnityObjectToClipPos
      #include "UnityCG.cginc"

      float4 _Color;
      float _Brightness;

      // Color Diffuse Map
      sampler2D _MainTex;
      // Tiling/Offset for _MainTex, used by TRANSFORM_TEX in vertex shader
      float4 _MainTex_ST;

      // This is the vertex shader input: position, UV0, UV1, normal
      struct appdata
      {
        float4 vertex   : POSITION;
        float2 texcoord : TEXCOORD0;
        float3 normal: NORMAL;
      };

      // This is the data passed from the vertex to fragment shader
      struct v2f
      {
        float4 pos  : SV_POSITION;
        float2 txuv : TEXCOORD0;
        float3 normalDir : TEXCOORD2;
      };

      // This is the vertex shader
      v2f vert(appdata v)
      {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.txuv = TRANSFORM_TEX(v.texcoord.xy,_MainTex);

        // Calculating normal so it can be used for fake lighting
        // in the fragment shader
        float4x4 modelMatrixInverse = unity_WorldToObject;
        o.normalDir = normalize(mul(float4(v.normal, 0.0), modelMatrixInverse).xyz);

        return o;
      }

      // This is the fragment shader
      half4 frag(v2f i) : COLOR
      {
        // Reading color from diffuse texture
        half4 col = tex2D(_MainTex, i.txuv.xy);

        // Using hard-coded light direction for fake lighting
        half3 th = normalize(half3(0.25, 1, -0.25));
        // Using hard-coded light direction for fake specular
        // This matches the value inside the LightmappedPrefabWithSpec shader
        half3 sth = normalize(half3(0, 1, -0.25));

        // Fake lighting
        float lightVal = max(0, dot (i.normalDir, th));
        float lightScale = 0.75;
        lightVal = lightVal * lightScale;

        // Fake spec
        float spec = max(0, dot(i.normalDir, sth));
        float specScale = 0.65;
        float specAtt = 0.65;
        spec = specScale * pow (spec, 40.0 * specAtt);

        // Add in a general brightness (similar to ambient/gamma) and then
        // calculate the final color of the pixel
        col.rgb = min(half4(1,1,1,1), col.rgb * _Brightness +
                      col.rgb * lightVal * _Color + col.rgb * spec);
        return col;
      }

      ENDCG
    }
  }
  FallBack "Diffuse"
}

Os objetos também não têm sombra ou criamos uma sombra falsa como parte do bit dinâmico. A maioria de nossas superfícies é plana, então, no nosso caso, isso não foi um grande obstáculo.

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Edifícios usando objetos dinâmicos adicionais)

Não há sombras nos bits dinâmicos, mas é quase imperceptível, a menos que você saiba procurá-lo. A iluminação dos prefabs dinâmicos também é completamente falsa - não há iluminação em tempo real.

O primeiro atalho barato que pegamos foi para codificar a posição da nossa fonte de luz (sol) no shader de iluminação falso. É uma variável a menos que o shader precisa procurar e preencher dinamicamente do mundo.

É sempre mais rápido trabalhar com um valor constante do que dinâmico. Isso nos deu iluminação básica, lados claros e escuros dos meshes.

Especular/Brilho

Para tornar as coisas um pouco mais brilhantes, adicionamos um cálculo especular/brilho falso aos shaders para os objetos dinâmicos e estáticos. Reflexos especulares ajudam na criação de uma aparência metálica, mas também ajudam a transmitir a curvatura de uma superfície.

Como os pontos de luz especulares são uma forma de reflexo, o ângulo da câmera e da fonte de luz em relação ao outro deve ser calculado corretamente. Quando a câmera se move ou gira, a parte especular muda. Qualquer cálculo de shader exigiria acesso à posição da câmera e a todas as fontes de luz na cena.

No nosso jogo, no entanto, só temos uma fonte de luz que deve ser usada para reflexo: o sol. No nosso caso, o sol é imóvel e pode ser considerado como luz direcionada. Podemos simplificar muito o shader usando apenas uma única fonte de luz e assumindo simplesmente uma posição fixa e um ângulo fixo.

Melhor ainda, nossa câmera nas Colônias Galácticas está mostrando a cena de cima para baixo, como a maioria dos jogos de construção de cidades. A câmera pode ser inclinada um pouco e ampliada, mas não pode girar em torno do eixo superior.

Geralmente, a vista da câmara para o ambiente é sempre de cima. Para fingir uma aparência especular simples, fingimos que a câmera estava completamente fixa, e o ângulo entre a câmera e a luz era sempre o mesmo.

Isso nos permitiu codificar um valor constante no shader e obter um efeito especular/brilho simples.

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Efeito falso especular/brilho)

É claro que usar um ângulo fixo para o especular não é tecnicamente correto - mas é praticamente impossível dizer a diferença, desde que o ângulo da câmera não mude muito. Para o jogador, a cena ainda parece correta, que é o ponto principal da iluminação em tempo real.

A iluminação de um ambiente em um jogo de vídeo em tempo real é e sempre foi mais uma questão de parecer visualmente correta, do que realmente ser uma simulação fisicamente correta.

Como quase todas os nossos meshes compartilham um material, com muitos detalhes provenientes do lightmap e dos vértices, adicionamos um mapa de textura especular, para informar ao shader quando e onde aplicar o valor da especificação e com que intensidade. A textura é acessada usando o canal UV primário, por isso não requer um conjunto adicional de coordenadas. E como muitos detalhes não estão incluídos, a resolução é baixa e ocupa pouco espaço.

Para alguns de nossos bits dinâmicos menores com menos vértices, poderíamos até mesmo usar os lotes dinâmicos automáticos Unity, agilizando ainda mais a renderização.

Prefabs Light baked em prefabs light baked

Todas as sombras podem, por vezes, criar novos problemas, especialmente quando se trabalha com edifícios relativamente modulares. Em um caso, tínhamos um depósito que o jogador poderia construir, que exibisse o tipo de mercadoria armazenada no edifício real.

Isso causa problemas, uma vez que temos um objeto light baked em cima de um objeto light baked . Lightbake onde quer que você olhe!!

Abordamos o problema usando outro truque simples:

  • The surface where the additional object was to be added had to be flat and use a specific gray color matching the base building
  • In return for that trade-off, we could bake the objects on a smaller flat surface and place it on top of the area with just a slight offset
  • Lights, highlights, colored glow and shadows were all baked into the tile

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Os objetos baked usam um brilho azul e projetam uma sombra)

Light baking simples e eficiente - se você pode viver com as restrições

Usar o Light Baking para criar nossas prefabs permite-nos ter enormes mapas de centenas de edifícios, mantendo um número muito pequeno de drawcalls. Todo o nosso mundo de jogo é mais ou menos renderizado com apenas um material, e estamos em um ponto em que a interface do usuário precisa de mais drawcalls do que o nosso mundo de jogo. Quanto menos materiais diferentes o Unity tiver para renderizar, melhor será para o desempenho dos seus jogos.

Isso nos deixa muito espaço para adicionar mais coisas ao nosso mundo, como partículas, efeitos climáticos e outros elementos atrativos.

Desta forma, mesmo os jogadores com dispositivos mais antigos são capazes de construir grandes cidades com centenas de edifícios, mantendo os 60fps estáveis.

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Uma colônia construída por um jogador usando prefabs light baked)

Pegue o que se encaixa no seu jogo

Nossa solução para renderizar grandes planetas com cidades movimentadas é feita sob medida para o nosso jogo. Nós fizemos o que funciona para nós. Usamos nossos limitados ângulos de câmera e a única fonte de luz na cena para simplificar muito a complexidade do shader. Em um ângulo fixo, também conseguimos encurtar processos que afetam a iluminação de objetos dinâmicos e o cálculo de reflexos. Nós reduzimos a quantidade de objetos dinâmicos e tratamos estaticamente o restante como um lote.

E, é claro, nosso estilo visual de baixa poligrafia e colorido também facilita muito, já que nos permite compartilhar materiais entre quase todos os objetos, o que possibilita lotes estáticos e dinâmicos.

Muito provavelmente, você não poderá aplicar todas as soluções aqui descritas ao seu jogo, e não importa, porque não é o objetivo. São pontos de partida que você pode usar para encontrar as melhores maneiras de otimizar seu próprio jogo. Descubra as restrições e limitações com as quais seu jogo pode funcionar e use-as para acelerar seu jogo.

Mais recursos

Queremos saber! Você gostou deste conteúdo?

Sim, continue. Bem. Poderia ser melhor
Eu entendi

Usamos cookies para garantir a melhor experiência no nosso site. Visite nossa página da política de cookies para obter mais informações.