Como engines modernas vencem o overdraw da vegetação
Por Oleg Sidorkin, CTO e cofundador da Cinevva

Uma floresta é uma das piores coisas que você pode pedir para uma GPU renderizar. Cada folha é um quad texturizado recortado por uma máscara alfa. Dezenas desses quads se empilham uns sobre os outros ao longo de cada raio de visão. O rasterizador não tem como saber antecipadamente quais fragmentos passarão no teste alfa, então a otimização padrão de early-Z que beneficia cenas opacas fica praticamente desativada. Como resultado, um único pixel da tela pode executar o shader completo das folhas 10 ou 15 vezes antes de o quadro ficar pronto. Isso é o overdraw da vegetação, e ele é a parte mais cara de um quadro de mundo aberto em qualquer jogo lançado na última década.
A boa notícia é que esse é um problema resolvido. Não no sentido de que alguém o corrigiu com um único truque, mas no sentido de que existe um conjunto de sete ou oito técnicas que, combinadas, reduzem o overdraw efetivo de 8-15x em uma floresta densa para 1-2x. Toda engine moderna inclui alguma versão desse conjunto. Veja quais técnicas fazem parte dele, por que cada uma existe e quais são as referências canônicas de cada uma.
1. Por que o overdraw da vegetação é tão problemático
Em uma cena opaca típica, a GPU faz a rejeição antecipada por profundidade: antes mesmo de executar o pixel shader, o hardware verifica o buffer de profundidade existente e ignora fragmentos que já estejam atrás de alguma coisa. Isso é praticamente gratuito e é o que mantém razoável o custo de geometrias densas.
A vegetação com teste alfa quebra esse mecanismo. O fragment shader precisa realmente ser executado para avaliar a textura alfa e chamar discard (ou clip) nos pixels removidos pela máscara. O hardware não consegue saber se um fragmento será descartado até que o shader seja executado, portanto, na maioria das GPUs, usar discard em qualquer ponto de um shader desativa totalmente o early-Z para aquela draw call. Em GPUs baseadas em tiles (dispositivos móveis, chips da série M e alguns consoles), isso pode desativar o Hi-Z e a compactação de profundidade do quadro inteiro. O pixel shader é executado uma vez para cada triângulo que cobre um pixel, e a maioria dessas avaliações termina em descarte.
Empilhe 10 quads de folhas diante de um único pixel da tela e o shader das folhas será executado 10 vezes. Multiplique isso por 4 milhões de pixels e o custo será brutal. O artigo de Marco Salvi, Usar early-Z ou não usar early-Z, é a introdução mais acessível aos motivos pelos quais isso acontece no nível do hardware e é o lugar certo para começar caso você nunca tenha pensado no assunto.

2. O pré-passe de profundidade para geometria com máscara
O maior ganho isolado — e a técnica incluída em toda engine moderna — é dividir a renderização da vegetação em dois passes. O primeiro passe grava apenas a profundidade, usando um shader mínimo que faz o teste alfa, descarta os pixels removidos pela máscara e não grava mais nada. O segundo passe renderiza o material completo com o teste de profundidade definido como "igual" e a gravação de profundidade desativada. Agora, cada pixel visível calcula a BRDF completa exatamente uma vez, independentemente de quantos quads de folhas estejam empilhados atrás dele.
Isso parece o dobro do trabalho porque os mesmos triângulos são processados duas vezes, mas o shader do pré-passe é tão barato (uma amostra de textura, um descarte e uma gravação de profundidade) que a economia no passe principal supera em muito o custo adicional. Em uma floresta densa, o passe principal deixa de executar o shader completo das folhas 10-15 vezes por pixel e passa a executá-lo exatamente uma vez.
Unreal, Frostbite, Decima e as ramificações modernas de Rage e Dunia fazem isso. Esse também é o principal motivo pelo qual materiais com máscara continuam sendo mais baratos do que materiais translúcidos em qualquer uma dessas engines.
Análises detalhadas:
- Pettineo, Usar early-Z ou não usar early-Z (o artigo canônico sobre como
discardinterage com Hi-Z e early-Z). - Wihlidal, Otimizando o pipeline gráfico com computação (GDC 2016, o pré-passe de profundidade da Frostbite e sua arquitetura de descarte controlada pelo pré-passe).
- Sanders, Entre tecnologia e arte: a vegetação de Horizon Zero Dawn (GDC 2018, incluindo a renderização de vegetação em dois passes da Decima).
- Persson, Algumas observações sobre Z (ainda uma das explicações mais claras sobre testes de profundidade por igualdade e a relação custo-benefício dos pré-passes).
3. LODs agressivos e impostores octaédricos
O segundo maior ganho é não renderizar as folhas quando isso não for necessário. Os assets de vegetação incluem vários níveis de LOD. O mais próximo usa a malha completa, com cartões individuais para as folhas. A uma distância média, as folhas são combinadas em cartões compostos mais densos (um grupo de 30 folhas se transforma em 1 cartão texturizado com a mesma silhueta). Além de um limite de distância, a árvore inteira se torna um impostor: uma pequena geometria texturizada com vistas pré-renderizadas da árvore a partir de vários ângulos.
O formato moderno é o impostor octaédrico: uma geometria de 8 faces texturizada com um atlas de vistas capturadas a partir de pontos em uma esfera por meio de mapeamento octaédrico. Em tempo de execução, o shader escolhe as duas ou três vistas pré-renderizadas mais próximas com base na direção da câmera e faz a transição entre elas. O resultado é um substituto composto por poucos triângulos, que parece tridimensional de qualquer ângulo e pode ter iluminação adequada, mapas de normais e até animação pelo vento. A implementação de Ryan Brucks, originalmente um plugin da comunidade e agora parte da Unreal, é a referência. As florestas com bilhões de árvores do Microsoft Flight Simulator são compostas essencialmente por impostores octaédricos em todos os lugares, exceto nas proximidades da câmera.
O maior ganho estrutural é que os impostores são opacos ou quase opacos à distância. O cartão composto de 30 folhas é um único quad com máscara em vez de 30 quads. O impostor da árvore inteira tem poucas faces, não milhares. O overdraw ao longe cai para quase zero.
Análises detalhadas:
- Brucks, Impostores octaédricos (a referência canônica, com a matemática e a implementação na UE).
- Halen, Impostores octaédricos na Unreal Engine (o fluxo de trabalho integrado à UE).
- Häggström, Renderização de vegetação em tempo real (uma tese clara que aborda cadeias de LOD, impostores e a matemática por trás deles).
- Crytek, Integração do SpeedTree à CryEngine 3 (GPU Gems 3, ainda a melhor introdução às cadeias de LOD para árvores).
4. Descarte de clusters controlado pela GPU
Mesmo com um pré-passe de profundidade, o próprio pré-passe tem um custo: ele ainda precisa processar cada triângulo de cada árvore visível (ou potencialmente visível). Engines modernas reduzem esse custo com o descarte de clusters controlado pela GPU, que elimina grupos inteiros de triângulos antes mesmo que o rasterizador os veja.
O pipeline funciona assim: cada malha é previamente dividida em clusters de 64 ou 128 triângulos, com uma caixa delimitadora justa e um cone de normais. Durante a renderização, um compute shader percorre a lista de instâncias, testa cada instância contra o frustum, depois testa cada cluster de cada instância visível contra o frustum e então faz um teste de oclusão Hi-Z de cada cluster restante contra a pirâmide de profundidade do quadro anterior. Galhos inteiros ocultos atrás de uma colina ou de outra árvore são descartados antes da execução de qualquer vertex shader. A saída é uma lista compacta de argumentos indicando "renderize estes clusters", enviada diretamente para uma única chamada DrawIndirect.
É isso que permite renderizar uma floresta de 10.000 árvores em milissegundos, em vez de segundos. A palestra da Ubisoft sobre Assassin's Creed Unity apresentou esse pipeline em uma implementação de produção (20-40% dos triângulos descartados, 30-80% dos triângulos de sombras descartados e 10x mais instâncias na tela do que na geração anterior), e a palestra de Wihlidal sobre a Frostbite levou a técnica ainda mais longe. O Nanite da UE5 é o estágio final visível dessa trajetória: descarte de clusters até o nível dos pixels.
Análises detalhadas:
- Haar e Aaltonen, Pipelines de renderização controlados pela GPU (SIGGRAPH 2015, a palestra fundamental sobre Assassin's Creed Unity).
- Wihlidal, Otimizando o pipeline gráfico com computação (GDC 2016, o pré-passe controlado pela GPU da Frostbite).
- Karis, Stubbe, Wihlidal, Uma análise detalhada da geometria virtualizada do Nanite (SIGGRAPH 2021, descarte de clusters com granularidade de meshlets).
- Liktor, Arquitetura do pipeline de renderização de geometria na Activision (a versão do descarte de clusters usada em Call of Duty, 2021).
5. Ordenação de instâncias e clusters da frente para trás
Quando o pré-passe começa a cumprir seu papel, a ordem passa a importar. O pré-passe grava a profundidade, mas apenas para os fragmentos que passam no teste alfa. Se você renderizar primeiro o fundo da floresta e deixar a frente por último, cada fragmento da frente sobrescreverá um fragmento de trás, e o shader do pré-passe ainda será executado para o fragmento de trás. Se você renderizar da frente para trás, cada draw call sucessiva preencherá uma parte maior do buffer de profundidade com valores menores, e o Hi-Z rejeitará cada vez mais fragmentos de trás antes da execução do shader.
É por isso que quase toda engine moderna ordena as instâncias de vegetação pela distância até a câmera antes de executar o pré-passe. A ordenação é barata (algumas centenas de milhares de instâncias na GPU usando radix sort) e transforma o próprio pré-passe em uma operação que reduz progressivamente seu trabalho. O descarte no nível dos clusters faz a ordenação com granularidade de meshlets pelo mesmo motivo. O pré-passe de profundidade e a ordenação da frente para trás formam o tipo de dupla em que cada técnica é boa sozinha, mas a combinação é excelente.
Análises detalhadas:
- Persson, Profundidade em detalhes (observações arquitetônicas sobre a ordenação do buffer de profundidade, a relação custo-benefício dos pré-passes e o comportamento do Hi-Z).
- Giesen, Uma viagem pelo pipeline gráfico (a explicação técnica detalhada de como a taxa de rejeição do Hi-Z depende da ordem de renderização).
- Wihlidal, Otimizando o pipeline gráfico com computação (GDC 2016, incluindo a ordenação de instâncias na GPU da Frostbite).
6. Transições de LOD com dithering e alfa com hash
A outra grande armadilha são as transições graduais. A maneira ingênua de fazer a transição entre dois LODs (ou de fazer uma instância aparecer ou desaparecer gradualmente conforme a câmera se aproxima) é usar mesclagem alfa. Mas geometrias com mesclagem não podem gravar no buffer de profundidade, o que joga toda árvore em transição para o lento caminho translúcido e quebra o pré-passe. A solução é manter a geometria no caminho com máscara e fazer a transição dentro do teste alfa.
Duas técnicas principais:
- Transições de LOD com dithering amostram um padrão Bayer 4x4 ou 8x8 (ou uma textura de ruído azul no espaço da tela) e o usam como modificador do limiar por pixel. Uma árvore com 50% de transição mantém um padrão quadriculado de pixels; os pixels ausentes são preenchidos pelo padrão complementar do LOD seguinte. O TAA resolve o padrão quadriculado e produz uma transição suave ao longo de dois ou três quadros. É barato, estável e combina com todo o restante da engine.
- Teste alfa com hash (Wyman e McGuire, I3D 2017) substitui o limiar alfa fixo de 0,5 por um limiar com hash por pixel no intervalo [0,1). Geometrias alfa distantes que normalmente desapareceriam por completo (porque o alfa com mipmap cai abaixo de 0,5) mantêm uma dispersão estável de pixels sobreviventes. Mais uma vez, o TAA faz o acabamento.
As duas técnicas mantêm a vegetação no caminho opaco/com máscara em que o pré-passe de profundidade funciona, portanto você não paga o custo total da renderização translúcida apenas para fazer algo aparecer ou desaparecer gradualmente. Alfa para cobertura é a técnica equivalente da era do MSAA: ela converte o alfa em uma máscara de cobertura de subpixels, oferecendo transparência parcial sem sair do caminho com máscara. O problema é que o A2C só funciona realmente bem com MSAA, que a maioria dos renderizadores diferidos modernos já não usa.
Análises detalhadas:
- Wyman e McGuire, Teste alfa com hash (I3D 2017, o artigo canônico sobre alfa com hash).
- Castaño, Como calcular mipmaps alfa (blog de The Witness, a maneira correta de gerar mipmaps de texturas com teste alfa para que árvores distantes não desapareçam).
- Yuksel, Distribuição alfa para testes alfa (uma melhoria mais recente para mipmaps alfa).
- NVIDIA, Teste alfa com antisserrilhamento (um panorama sobre A2C, alfa com hash e alternativas com dithering).
7. Redução do custo de sombreamento em pixels com máscara
Mesmo com um pré-passe perfeito e um descarte perfeito, você ainda precisa sombrear uma vez cada pixel visível da vegetação. As engines também reduzem esse custo:
- BRDF mais barata. A folhagem é fosca e não precisa realmente de um caminho especular Cook-Torrance completo. Uma difusa Lambertiana envolvente mais uma aproximação especular de uma linha é mais do que suficiente.
- Mapas de normais com frequência mais baixa. As folhas já têm bastante ruído visual. Um mapa de normais de 256x256 parece igual a um de 1024x1024 nas distâncias de visualização típicas e economiza largura de banda.
- Sem paralaxe, anisotropia ou clearcoat. O conjunto de recursos PBR é desativado para as folhas.
- Transmissão fina de dois lados em vez de espalhamento subsuperficial completo. As folhas transmitem luz por trás, mas é possível simular isso com um único produto escalar com a luz traseira.
- Sombreamento em meia resolução em alguns motores. A folhagem é sombreada a 1/4 ou 1/2 da taxa de pixels e ampliada. O ruído estocástico do TAA oculta a reamostragem.
- Omitir texturas de detalhes e decalques em materiais mascarados por padrão.
Cada uma dessas técnicas gera um pequeno ganho isoladamente. Combinadas, elas permitem que shaders de folhagem mascarada sejam executados de 2 a 3 vezes mais rápido que o material opaco equivalente.
Análises aprofundadas:
- Lagarde e de Rousiers, Migrando a Frostbite para renderização com base física 3.0, seções sobre folhagem e translucidez (SIGGRAPH 2014, os ajustes PBR canônicos para materiais finos de dois lados).
- Jimenez, Renderização de personagens de última geração (a matemática da Lambertiana envolvente e da translucidez traseira, originalmente criada para pele, mas amplamente adaptada para folhas).
- Sanders, Entre tecnologia e arte: a vegetação de Horizon Zero Dawn (GDC 2018, com as simplificações do shader de folhagem da Decima).
8. Buffers de visibilidade e Nanite para materiais mascarados
A solução mais limpa para o overdraw é desacoplar completamente o sombreamento da rasterização. Um buffer de visibilidade rasteriza a geometria em um buffer compacto (apenas o ID do triângulo e o ID da instância por pixel) e depois executa o material completo como um passe diferido que lê o buffer de visibilidade e sombreia cada pixel exatamente uma vez. Por definição, não há overdraw na etapa de sombreamento. O artigo de Burns e Hunt de 2013 apresentou essa técnica; o Nanite da UE5 é sua implementação com qualidade de produção, inclusive para folhagem mascarada desde a UE 5.5.
A diferença do Nanite é fazer isso com geometria virtualizada no nível de clusters, de modo que o próprio rasterizador use um caminho por software para triângulos menores que um pixel e mantenha o overdraw limitado. Materiais mascarados no Nanite precisam do recurso de "rasterização programável": o teste alfa é executado durante o passe do buffer de visibilidade, mas o sombreamento do material ainda acontece uma vez por pixel visível na resolução diferida. O resultado é que uma folhagem Nanite muito densa, antes notoriamente lenta com materiais mascarados, agora é competitiva com a geometria opaca ou até mais barata, pois o overdraw durante o sombreamento é zero. Há uma contrapartida: muitas vezes é melhor processar geometria de árvores opaca e com muitos polígonos pelo Nanite do que manter árvores de poucos polígonos feitas com cartões mascarados, pois o caminho mascarado adiciona o custo da rasterização programável.
Análises aprofundadas:
- Burns e Hunt, O buffer de visibilidade: uma abordagem de sombreamento diferido eficiente para o cache (JCGT 2013, o artigo original).
- Karis, Stubbe, Wihlidal, Uma análise aprofundada da geometria virtualizada do Nanite (SIGGRAPH 2021, a arquitetura de produção).
- Epic, Materiais do Nanite controlados pela GPU (GDC 2024, com o pipeline de materiais mascarados e rasterização programável).
- Notas sobre "Materiais do Nanite controlados pela GPU" (uma explicação clara feita por terceiros sobre a mesma palestra).
9. Representações de sombras separadas para a folhagem
Mapas de sombras para folhagem com teste alfa são o segundo problema de sombras mais caro em qualquer frame de mundo aberto, atrás apenas das cascatas grandes. Cada cascata precisa do próprio pré-passe de profundidade, cada pré-passe executa o teste alfa e o custo se acumula rapidamente em 4 cascatas e dezenas de frustos de luz. Por isso, a maioria dos motores não renderiza as sombras da folhagem da mesma forma que renderiza sua cor.
Substituições comuns:
- Sombras com campos de distância da malha (UE Lumen, motores personalizados). Cada malha tem um campo de distância com sinal pré-calculado. Um curto traçado de cone pelo SDF produz uma sombra suave sem jamais tocar na malha com teste alfa. Isso funciona particularmente bem para árvores porque o SDF captura a silhueta da copa como um único volume sólido e ignora os detalhes de cada folha.
- Cascatas de resolução mais baixa para a folhagem. As sombras da folhagem são gravadas em uma camada com metade da resolução e ampliadas com filtragem sensível às bordas. O olho não percebe a redução da resolução porque as sombras já são suaves.
- Mapas de sombras com alpha-to-coverage e MSAA. Em motores que ainda usam MSAA no caminho de sombras, o A2C produz sombras de folhagem com bordas suaves sem o custo completo do teste alfa.
- Sombras de cápsula para o tronco e os galhos grandes, campo de distância para a copa e teste alfa completo apenas na cascata mais próxima. Representações diferentes para distâncias diferentes, combinadas no passe de iluminação.
- Distância de desativação do WPO. O World Position Offset controlado pelo vento é desativado além de um limite para que os dados de sombra armazenados em cache continuem válidos entre frames. Os Virtual Shadow Maps da UE dependem muito disso.
Análises aprofundadas:
- Epic, Sombras suaves com campos de distância na Unreal Engine (a referência canônica da UE para sombras com campos de distância de malha).
- Wright, Lumen: iluminação global em tempo real na Unreal Engine 5 (SIGGRAPH 2022, com a integração de SDFs de malha do Lumen para folhagem).
- Epic, Virtual Shadow Maps (a arquitetura moderna de sombras da UE5, com regras específicas para desativação de WPO e cache da folhagem).
- Persson, Mapas de sombras em cascata na prática (a referência ainda canônica sobre CSM, com observações sobre objetos com teste alfa que projetam sombras).
10. Vento, animação e cache de sombras
Um problema sutil relacionado: a maior parte da folhagem se move. A animação de vértices controlada pelo vento (World Position Offset na UE e equivalentes na Frostbite e na Decima) faz com que a geometria da folhagem não permaneça estável entre frames, o que invalida o cache de sombras e a reprojeção. Os motores modernos combatem isso de duas maneiras:
- Limitar o WPO à distância. Além de um limite, a amplitude da animação do vento é reduzida suavemente até zero. De qualquer forma, o olho não consegue perceber o balanço a uma distância tão grande, e os caches de sombras continuam válidos.
- Incorporar o vento aos limites dos clusters. As caixas delimitadoras dos clusters são expandidas pelo deslocamento máximo do WPO, de modo que o culling permaneça conservador sem precisar reenviar dados a cada frame.
- Deslocamentos de fase por instância. Árvores idênticas usam uma semente aleatória por instância para deslocar a fase do vento, evitando que uma floresta inteira balance em sincronia sem pagar por uma animação exclusiva para cada árvore.
Esse é o tipo de detalhe que não aparece em listas de técnicas, mas que, na prática, representa a diferença entre uma floresta de 3 ms e outra de 9 ms.
Análises aprofundadas:
- Sanders, Entre tecnologia e arte: a vegetação de Horizon Zero Dawn (GDC 2018, com o pipeline de animação pelo vento e o cache de sombras da Decima).
- McAuley, Renderizando o mundo de Far Cry 4 (GDC 2015, inclui a amostragem da grade de vento para vegetação).
- Epic, Folhagem e Virtual Shadow Maps (as orientações da comunidade da UE5 sobre a distância de desativação do WPO e o cache de VSM).
11. A matemática combinada
Nenhuma dessas técnicas é uma solução milagrosa. O interessante é o que acontece quando elas são combinadas:
- Um passe ingênuo de folhagem mascarada em uma cena de floresta densa apresenta de 8 a 15 vezes de overdraw efetivo. Cada pixel visível executa o shader de folha de 8 a 15 vezes.
- Adicione um pré-passe de profundidade e o passe principal cai para cerca de 1x de overdraw, mas o próprio pré-passe ainda toca em tudo.
- Adicione ordenação da frente para trás e o pré-passe começa a eliminar trabalho por conta própria.
- Adicione culling na GPU no nível de clusters e o pré-passe toca apenas no que poderia estar visível.
- Adicione cadeias de LODs e impostores, e a quantidade de quads visíveis cai em uma ordem de grandeza além dos 30 m.
- Adicione o caminho de buffer de visibilidade/Nanite e a etapa de sombreamento realmente passa a ser executada uma vez por pixel, mesmo com sobreposição densa.
- Adicione sombras com campos de distância e o custo das sombras deixa de crescer com o teste alfa.
O principal resultado, repetido nas palestras indicadas acima: o overdraw efetivo cai de 8-15x para 1-2x, e o custo total da folhagem por frame diminui de 4 a 6 vezes em uma cena de floresta densa. Esse é o motivo pelo qual jogos modernos de mundo aberto conseguem renderizar florestas a mais de 60 fps em hardware de consumo.

12. O que isso significa para o navegador
A maior parte desse conjunto de técnicas pode ser adaptada diretamente para WebGPU. Já disponibilizamos culling controlado pela GPU, dispatch indireto, oclusão Hi-Z e pré-passes ordenados da frente para trás no motor de mundo aberto para navegadores. O pré-passe de profundidade para geometria mascarada é simples: a WebGPU aceita testes depth-equal e discard em shaders de fragmento, com as mesmas ressalvas sobre early-Z. Impostores octaédricos podem ser portados mecanicamente; a matemática consiste apenas no desdobramento de esfera para octaedro e na indexação do atlas.
As partes mais difíceis são as modernas. Um buffer de visibilidade em WebGPU exige gravar um ID de triângulo de 32 bits em um destino de renderização e resolver os materiais em um passe de computação em tela cheia; os componentes necessários existem, mas sua orquestração é complexa. Sombras com campos de distância da malha exigem uma textura 3D por asset e um curto traçado de cone, ambos ao alcance da WebGPU. Alfa com hash e LODs com dithering exigem apenas uma função de shader cada.
O caminho para a folhagem no navegador é o mesmo de todo o restante desse conjunto: disponibilizar primeiro as partes baratas e robustas (pré-passe, instâncias ordenadas, LODs, impostores, alfa com hash) e adicionar os mecanismos mais pesados (buffer de visibilidade, sombras com SDF de malha) por cima. O patamar mínimo do hardware dos navegadores finalmente está alto o bastante para que não exista nenhum motivo arquitetural pelo qual uma floresta em WebGPU não possa ter a mesma aparência e o mesmo desempenho que uma de console. Restam apenas motivos de engenharia, e motivos de engenharia são do tipo que apreciamos.
Leituras adicionais sobre todo o conjunto
Se você quiser uma única fonte que reúna tudo isso, o arquivo "Advances in Real-Time Rendering in Games" da SIGGRAPH (advances.realtimerendering.com) contém as palestras canônicas sobre folhagem e renderização controlada pela GPU desde 2014. Os artigos sobre análise de desempenho da GPU de Adrian Courrèges incluem decomposições frame a frame de GTA V e Horizon Zero Dawn que mostram, em ordem de produção, cada passe discutido aqui. Especificamente para a matemática do teste alfa, a página de pesquisas de Chris Wyman apresenta os artigos sobre alfa com hash e transparência estocástica, acompanhados de shaders de referência. E os capítulos de Real-Time Rendering, 4ª edição sobre transparência, amostragem e gerenciamento de profundidade continuam sendo o ponto de partida acadêmico.