Iluminação de jogos para dispositivos móveis com o Unity

A iluminação é um dos aspectos mais importantes de um jogo. Ela pode definir o clima, conduzir o jogador, identificar ameaças ou objetivos e muito mais. A iluminação pode ser decisiva para o visual de um jogo. Por exemplo, uma boa iluminação pode fazer um modelo ruim parecer melhor no jogo, enquanto uma luz inadequada pode deixar ruim um modelo excelente.

Este guia fornece informações para melhorar o desempenho da iluminação em um jogo para dispositivos móveis. O modo como você decide usar a iluminação afeta o desempenho do seu jogo para dispositivos móveis. É importante usar a iluminação de maneira eficiente para garantir que o jogo funcione da melhor forma possível.

Partes deste artigo são baseadas em trabalhos disponibilizados pela Arm Limited e protegidos por direitos autorais.

Opções de pipeline de renderização

O Legacy Render Pipeline do Unity inclui os seguintes caminhos de renderização:

  • Renderização forward
  • Deferred shading

Renderização forward

Com a renderização forward, as luzes em tempo real são muito caras. Se você reduzir o número de luzes presentes por pixel, poderá compensar o custo.

Deferred shading

O deferred shading requer compatibilidade com a GPU. Em hardware compatível, o deferred shading pode renderizar um grande número de luzes em tempo real com um alto nível de fidelidade de iluminação. Infelizmente, o deferred shading não funciona bem em GPUs móveis porque elas têm largura de banda menor.

Quando você cria um título para dispositivos móveis, é importante que seu jogo funcione perfeitamente no maior número de dispositivos possível.

Pipeline de Renderização Universal

O Unity desenvolveu o Pipeline de Renderização Universal (URP, na sigla em inglês). Recomendamos que você use o URP nos jogos para dispositivos móveis.

Modos de iluminação

Diferentes modos de iluminação são usados de acordo com a forma como a luz se move ou é usada em uma cena. Os tipos de modo de iluminação têm características de desempenho diferentes. Ao implementar luzes, considere o seguinte:

  • Use baked para iluminação estática. Essa opção é melhor para objetos que não mudam a iluminação durante o tempo de execução. Baking lights é o processo de pré-computação e armazenamento de dados de iluminação em mapas de textura chamados de lightmaps.
    • A baked lighting não pode ser modificada no tempo de execução. A luz e as sombras nos lightmaps são estáticas. Como toda a iluminação foi pré-processada no Unity, não há cálculos de iluminação em tempo de execução que afetam o desempenho.
    • Sombras dinâmicas não podem ser criadas com baked light. Isso pode parecer estranho com objetos dinâmicos ou em movimento.
  • Use mista para luzes fixas que você pretende interagir com objetos em movimento. Por exemplo, uma lanterna que ilumina um jogador e gera uma sombra conforme ele se move.
    • A iluminação mista cria luzes e sombras diretas e dinâmicas.
    • É possível incluir iluminação mista em cálculos de lightmap para objetos estáticos.
    • Você pode mudar a intensidade no tempo de execução. Somente a luz direta é atualizada.
    • Caro.
  • Use tempo real para luzes dinâmicas ou móveis, como a luz gerada por uma bola de fogo que sobe do solo e explode.
    • As propriedades dinâmicas de luz e sombra podem ser modificadas no tempo de execução.
    • As luzes em tempo real não são incorporadas a lightmaps.
    • Muito caro.

Para ver mais informações, leia Pipeline de iluminação do Unity.

Quando possível, use iluminação estática e evite a iluminação dinâmica

A iluminação dinâmica, ou em tempo real, é calculada e atualizada a cada frame. Isso é ótimo para mover objetos, gerar interatividade e criar emoção.

Por outro lado, as informações de iluminação estática são incorporadas a lightmaps. O uso de textura do lightmap permite que um objeto evite cálculos caros de iluminação por vértice ou pixel. O custo da renderização de uma textura de lightmap é sempre muito menor do que da iluminação dinâmica. Recomendamos que a baked lighting seja sua primeira opção na implementação de jogos para dispositivos móveis.

Lightmap baking

O pré-cálculo dos efeitos de luz é conhecido como lightmap baking. O efeito da luz é armazenado em uma textura separada, chamada de lightmap. O lightmap pode ser usado para ampliar a aparência dos objetos. O lightmap baking só precisa ser feito uma vez por iteração da cena. Se você mudar a geometria da cena ou os parâmetros das baked lights, será necessário refazer os lightmaps. Exceto pelas despesas gerais da textura do lightmap, não há custos extras de desempenho no tempo de execução. Essa é a melhor abordagem inicial para iluminação em uma plataforma móvel.

A baked light não é afetada por aspectos dinâmicos ou em movimento da cena. Ela inclui a Baked Global illumination para todos os elementos estáticos. Isso significa que os cálculos de lightmap incluem luz indireta que foi refletida de outros objetos estáticos, bem como as baked lights que atingem diretamente o objeto.

Figura 1. Configuração de baked lighting usada na demonstração tecnológica da Armies.

Para fazer o bake de suas luzes, siga estas três etapas:

Etapa 1: definir as luzes como "Mixed" ou "Baked"

Em Mode, defina o modo das luzes como "Mixed" ou "Baked". Para títulos de dispositivos móveis, é melhor usar Baked. Essa é a maneira mais barata de renderizar a iluminação.

Figura 2. Configuração Mode da iluminação no Unity.

Etapa 2. Tornar os objetos estáticos

Faça com que os objetos afetados pelas baked lights fiquem estáticos. Existem muitas otimizações para um objeto marcado como estático, mas geralmente é melhor selecionar Everything na lista suspensa Static. Com o objeto marcado como Static, o Unity sabe que precisa incluí-lo no light baking.

Figura 3. Um exemplo de menu estático.

Etapa 3. Fazer bake das luzes

Você pode fazer bake das luzes com o menu Lighting encontrado em Window > Rendering > Lighting Settings.

Durante esse processo, os dados salvos são baseados na cena que estava ativa quando você iniciou o bake. Uma pasta é gerada com o mesmo nome da cena baked. Essa pasta armazena todos os componentes dos dados de iluminação. Se o seu projeto carregar várias cenas ao mesmo tempo, você precisará fazer o bake das luzes de cada uma delas. Se você ajustar a cena, precisará refazer o bake da luz.

Figura 4. Um exemplo de lightmaps com bake.

Otimizar lightmaps

Depois que as luzes estiverem configuradas para o processo de baking, certifique-se de que os mapas resultantes sejam otimizados. Os lightmaps variam em tamanho com base nas configurações durante o bake. É preciso manter o uso da memória baixo em dispositivos móveis, portanto, o lightmap de luz precisa ser monitorado.

No exemplo a seguir da demonstração da Armies, há sete lightmaps de 1.024 x 1.024 pixels. Na visualização do mapa, você pode ver as malhas dispostas no lightmap. As malhas selecionadas estão destacadas.

Figura 5. Este é um exemplo de lightmap As seções azuis são malhas selecionadas.

Há muitas configurações em Lightmapping Settings, junto com o tamanho dos mapas, que determinam a quantidade de memória e espaço de armazenamento que cada mapa usa. As seções a seguir destacam algumas configurações importantes.

Lightmappers

O Unity oferece os três métodos para fazer o bake das luzes na cena:

  • Enlighten: só é compatível até a versão de suporte de longo prazo (LTS, na sigla em inglês) de 2020. Não use esse recurso para novos projetos.
  • Progressive CPU: economiza muito tempo porque cria lightmaps incrementais. Se a opção Prioritize View estiver selecionada, as áreas na visualização de cena serão priorizadas. Isso pode diminuir o tempo de iteração para configurar a luz da cena.
  • Progressive GPU: funciona da mesma forma que Progressive CPU, mas gera o lightmap na GPU, não na CPU. Em hardware compatível, esse método pode reduzir significativamente o tempo de baking em comparação com o uso da CPU. Há outros requisitos para configurar a Progressive GPU. Saiba mais sobre os requisitos na página The Progressive GPU Lightmapper.

Figura 6. Em Lightmapper Settings, você pode mudar o método de bake da cena.

Texels

Um texel, ou pixel de textura, é um pixel individual em um mapa de textura. Os texels armazenam informações de iluminação em um lightmap para cada ponto de luz que atinge um objeto. Quanto mais texels forem utilizados por unidade de espaço, maior será a influência na qualidade da sua iluminação, no tempo de computação necessário para o bake, nos custos de armazenamento em disco e no custo de VRAM dos seus lightmaps.

Para reduzir a quantidade de dados necessários para o lightmap, ajuste o número de texels por unidade de bake em Lighthouse Settings.

Figura 7. Configurações disponíveis para lightmaps.

Em Lightweight Settings, o parâmetro Lightmap Resolution controla a quantidade de texels que podem ser usados por unidade no lightmap. Veja a seguir um exemplo de cubo com diferentes configurações de Lightmap Resolution. Você pode ver como uma resolução mais alta aumenta rapidamente o trabalho necessário.

Figura 8. O primeiro cubo tem uma Lightmap Resolution de 1. O segundo cubo tem uma Lightmap Resolution de 2. O terceiro cubo tem uma Lightmap Resolution de 5.

Para ver como os texels são apresentados na sua cena, selecione a lista suspensa Draw Mode na visualização de cena e escolha Baked Lightmap.

Os objetos baked são cobertos em uma sobreposição de tabuleiro de xadrez. O padrão de tabuleiro mostra como os texels são distribuídos quando você faz o bake das luzes.

No exemplo a seguir, uma redução do Lightmap Resolution de 15 para 12 na demonstração da Armies reduz o número de lightmaps necessários de sete para quatro.

Figura 9. Demonstração da Armies com um Lightmap Resolution de 12.

Uso de texels

Embora você possa definir o número de texels por unidade em uma cena inteira, há alguns objetos que não precisam de tantos texels.

Com o Unity, você controla quantos texels serão usados em cada objeto. Em Inspector > Mesh Renderer de um objeto, o valor do parâmetro Scale In Lightmap controla o número de texels que o objeto usa no lightmap.

No exemplo a seguir, o cubo à esquerda tem cinco texels de informação de luz por unidade de baking. A caixa à direita tem a escala no lightmap definida como 0,5. Essa configuração dimensiona os texels para 2,5, exigindo menos espaço no lightmap do que a caixa à esquerda.

Figura 10. Dois cubos com resoluções de lightmap diferentes.

Figura 11. Mude a configuração de Scale in Lightmap para que um objeto tenha menos texels.

Tente evitar o uso de muitos texels nas situações a seguir:

  • Superfícies e objetos que o jogador não verá. Isso evita desperdício de memória em lightmaps com detalhes que não estão na tela.
  • Superfícies com pouca variação de luz. Por exemplo, objetos em uma sombra ou atingidos por uma única fonte de luz.
  • Objetos pequenos ou finos. A quantidade de iluminação recebida não adiciona muito à renderização final da cena.

Simular a iluminação o máximo possível

Para reduzir os requisitos de processamento, você pode simular alguns elementos. Isso pode fazer com que o conteúdo pareça usar iluminação, quando, na verdade, usa métodos mais eficientes.

Sombras falsas

Sombras em tempo real são caras. Elas são geradas com uma técnica chamada shadow mapping. O custo para renderizar a geometria de uma cena no shadow map é proporcional ao número de vértices desenhados com as sombras ativadas. Recomendamos limitar a quantidade de geometria de projeção de sombras e o número de luzes com projeção de sombra em tempo real.

É possível implementar sombras falsas em objetos dinâmicos sem luzes dinâmicas. Isso mantém os custos de renderização baixos e pode alcançar um efeito semelhante às sombras dinâmicas. Veja algumas maneiras de implementar sombras falsas:

  • Use uma malha 3D, como uma superfície plana ou um quadrado, colocada sob o personagem e aplique uma textura borrada.
  • Você pode criar seu sombreador personalizado para ter sombras de blob mais sofisticadas.

O exemplo a seguir mostra o resultado do uso de uma malha 3D para uma sombra:

Figura 12. Implementação de sombra na demonstração tecnológica da Armies.

Pintar informações de luz diretamente nas texturas

Ao pintar parte da sombra em texturas, você reduz a computação necessária para a iluminação extra. Isso economiza memória ao fazer o bake as luzes da cena, porque requer menos dados de lightmap.

Light Probes

Os objetos dinâmicos com baked lighting não serão afetados pelos lightmaps, o que pode dar a impressão de que eles não fazem parte da cena.

Isso pode ser resolvido com os Light Probes. Os Light Probes têm benefícios semelhantes aos lightmaps. Eles armazenam dados de luz que podem ser calculados antecipadamente e salvos para uso no tempo de execução. Isso transfere boa parte dos custos computacionais para a edição de tempo.

Enquanto um lightmap codifica a iluminação recebida em um texel para superfícies, um Light Probe armazena a luz que atravessa um espaço vazio. Use esses dados para iluminar objetos que se movem. Os Light Probes ajudam a integrar objetos dinâmicos visualmente com objetos mapeados por toda a cena.

Os Light Probes são melhor utilizados para iluminar objetos que se movem na cena. Os Probes aproveitam as "baked lights", o que permite que os objetos em movimento tenham a mesma luz da cena. A iluminação de objetos dinâmicos com os Light Probes é mais econômica que as luzes em tempo real.

Saiba mais acessando as páginas Static Lighting with Light Probes e Light Probes.

Figura 13. Light Probes posicionados para iluminar o grupo dinâmico na demonstração tecnológica da Armies.

Configurações do Mesh Renderer

Independentemente do tipo de iluminação usada na cena, é importante que as configurações do Mesh Renderer estejam corretas.

Desative tudo o que você não usa. Configurações como Cast Shadows adicionam custo ao renderizar a cena, mesmo que o objeto não esteja iluminado. O seguinte exemplo de configurações do Mesh Renderer é para um personagem mostrado na Figura 13. O personagem usa dados do Light Probe, mas não de reflexos.

A configuração Blend Probes para os Light Probes mescla as informações de iluminação dos Light Probes mais próximos do personagem. À medida que o personagem se move em torno da cena, os Light Probes que o afetam mudam. A opção Cast Shadows é desativada porque a renderização usa o método blob. O recurso Receive Shadows também é desativado porque é feito o bake da cena e não há sombras em tempo real.

Figura 14. Configurações do Mesh Renderer para a renderização da Figura 13.

Iluminação em tempo real e tipos de luzes

Recomendamos usar baked lighting, Light Probes e técnicas de iluminação falsa, como texturas de iluminação pintada ou efeitos de sombreador. No entanto, se você precisar de iluminação em tempo real, considere o tipo de luz a ser usado.

Cada tipo de luz tem um custo diferente para calcular a iluminação. A lista a seguir detalha cada tipo de luz:

  • Directional: essa luz tem uma direção uniforme e nenhuma diminuição. A luz direcional é a mais econômica em tempo real. Muitas vezes, você só precisa de uma luz direcional por cena. Com a renderização forward, o caminho de renderização sugerido para dispositivos móveis, o Unity incluirá uma luz direcional padrão se não houver luzes direcionais na cena.
  • Spot: as luzes spot selecionam objetos fora do cone e não os iluminam. Isso torna as luzes spot mais econômicas do que as luzes de ponto esférico. Para conseguir o melhor desempenho, mantenha a largura do cone precisa e atinja apenas os objetos pretendidos.
  • Point: elas lançam luz em todas as direções. Esse tipo de iluminação é útil, mas muito caro. As luzes point são caras quando aplicadas a uma área ampla. Além disso, o cálculo da sombra pode ser a parte mais cara da iluminação. Se você lançar luz em todas as direções, haverá mais sombras e mais cálculos.