Estou no processo de descobrir como empacotar todas as informações de que preciso para um Renderizador adiado fisicamente baseado em um G-Buffer sem usar um obsceno quantidade de alvos de renderização.
O que eu tenho até agora são 4 vetores de 3 partes:
- Albedo / Diffuse
- Normal
- Tangente
- Posição
E 4 componentes individuais
- Metálico
- Rugosidade
- Altura
- Oclusão de ambiente
Uma abordagem ingênua é agrupar um dos componentes únicos no canal alfa (quarto) com um dos vetores de 3 partes, que é minha linha de investigação atual. No entanto, dado que quatro alvos de renderização de ponto flutuante de precisão total de 4 canais não são pequenos, entendo que seja comum usar meia precisão e representações ainda menores para ter mais consciência da memória.
O que estou perguntando é: quais componentes posso reduzir com segurança a precisão sem perder qualidade e em quanto?
Resposta
Em primeiro lugar, você não precisa de nenhuma posição no G-buffer. A posição de um pixel pode ser reconstruída a partir do buffer de profundidade , conhecendo a configuração da câmera e a posição xy do espaço da tela do pixel. Assim, você pode se livrar todo o buffer.
Além disso, normalmente você não precisa de vetores tangentes no G-buffer. Eles são necessários apenas para converter mapas normais do espaço tangente e para mapeamento de paralaxe; isso seria feito durante a passagem de preenchimento do G-buffer (quando você tem tangentes da malha que está renderizando), e o G-buffer só armazenar normais no mundo ou visualizar o espaço.
Propriedades de materiais como cores, rugosidade e metálico são geralmente apenas valores de 8 bits no G-buffer, uma vez que “se originam de texturas de 8 bits. O mesmo para AO.
A altura também não é necessária no G-buffer, a menos que você vá fazer algum tipo de combinação multi-passagem que dependa disso, mas se você precisar, provavelmente 8 bits é o suficiente para isso também.
Os normais podem se beneficiar ao serem armazenados como valores de 16 bits em vez de 8 bits. Meia-flutuação está bem, mas o ponto fixo de 16 bits é ainda melhor, pois oferece uma precisão mais uniforme em todas as orientações (meia-flutuação é mais preciso perto dos eixos e perde alguma precisão fora deles). Além disso, você pode cortá-los de 3 componentes para 2 usando o mapeamento octaédrico .
Então, no final do dia, um mínimo G-buffer pode ser semelhante a:
- Cor do material + metálico: RGBA8
- Espaço-mundo octaédrico normal + rugosidade + AO: RGBA16
e isso é tudo! Apenas 12 bytes por pixel.
Alternativamente, você poderia usar um buffer RG16 para os normais e mover rugosidade + AO para um buffer separado de 8 bits. Isso lhe daria algum espaço para crescer, caso você precise de mais componentes G-buffer de tamanhos de 8 ou 16 bits.
Comentários
- Além disso, metalicidade costuma ser um valor binário e, supondo que você não usará gradientes de rugosidade (para ver o impacto da precisão reduzida), poderá armazenar metalicidade e rugosidade em um único canal de 8 bits (1 bit para metalosidade e 7 para rugosidade).