É possível renderização / sombreamento diferido com o OpenGL ES 2.0?

20

Eu perguntei isso no StackOverflow , mas pode fazer mais sentido aqui:

Alguém implementou renderização / sombreamento diferido no OpenGL ES 2.0? Ele não suporta MRTs; portanto, com apenas um buffer de cores, não é algo que possa ser implementado da maneira "usual".

Especificamente, estou explorando no iPad, iPhone4 (iPhone 3GS) e Android. No aplicativo GLESView no iPad / iPhone4 / iPhone3gs, a extensão GL_OES_RGB8_RGBA8 está presente e eu ainda não olhei muito profundamente, mas com 8bits / canal, essa ideia é interessante: http://www.gamedev.net/topic/ 562138-opengl-es-20-e-adiado-sombreado /

Alguma outra ideia? Vale a pena fazer, em termos de desempenho?

Jim Buck
fonte
Sim é possivel.
Quazi Irfan
7
Via quais técnicas?
21711 Jim Buck

Respostas:

15

Sim, é possível. No entanto, não vale particularmente a pena.

Primeiro, a menos que você tenha acesso à extensão NV_draw_buffers (como o nome indica, ela é apenas da NVIDIA. Portanto, a menos que você esteja executando o Tegra, você não o possui), os objetos framebuffer no ES 2.0 podem renderizar apenas uma imagem de uma vez. Portanto, para gerar seus buffers G, você precisará renderizar sua cena várias vezes, tirando assim uma das vantagens da renderização adiada.

Segundo, a largura de banda nas plataformas móveis não é a mesma que você obteria nas GPUs de nível médio. E a largura de banda é fundamental para que a renderização diferida (para muitas luzes) valha a pena. Sem essa largura de banda, as passagens de luz realmente vão doer, em termos de desempenho.

Terceiro, o hardware PowerVR realmente não foi projetado para esse tipo de coisa. Otimiza a renderização com seu hardware de renderização baseado em blocos. Uma renderização tão adiada além disso seria menos útil do que em uma arquitetura tradicional de conversão de varredura.

Nicol Bolas
fonte
6

O principal problema é a taxa de preenchimento. Em GPUs para dispositivos móveis, a taxa de preenchimento é baixa, e você não pode fazer sombreamento adiado em tempo real com resolução nativa.

No iPhone 4 e iPad 1, a taxa de preenchimento é ridícula. O único dispositivo IOS com boa taxa de preenchimento é o iPad 2, mas duvido que seja suficiente ... No Android, apenas os dispositivos Tegra têm o GL_NV_draw_buffers para usar o MRT, mas a taxa de preenchimento também é muito baixa. O Mali 400 parece ter a melhor taxa de preenchimento. Se você quiser chorar, tente preencher um retângulo de cores em resolução de tela cheia 4 vezes ... Muitos dispositivos não conseguem fazer 60 fps.

Nas GPUs de desktop, você tem 10 vezes (ou mais) a taxa de preenchimento como gpus móvel. Não esqueça que as GPUs móveis usam a mesma memória que a CPU e você não tem memória dedicada.

Existem alguns exemplos no WebGL (mesma API), portanto isso não é uma limitação da API.

Ellis
fonte
11
+1 para preencher a fraqueza. Eu não poderia mesmo obter Gaussian Blur para correr em 1536x2048 resolução a 60 fps (-lo imediatamente colidido a taxa de quadros até 30 fps, mesmo com apenas 4 amostras)
bobobobo
11
Acho que isso depende muito das sutilezas da sua implementação e da compreensão do que mais afeta o hardware móvel. Por exemplo, esses caras fizeram um DOF borrão moderadamente performance de volta em 2012.
Engenheiro
1

Você realmente precisa considerar qual é o mínimo absoluto necessário para um renderizador diferido. Se você voltar para a iluminação diferida, reduz a quantidade de dados que precisam ser armazenados no GBuffer, e é realmente muito mais barato do que renderizar metade da cena 3 vezes ou mais para suportar uma quantidade baixa de luzes.

Eu usaria o seguinte formato GBuffer:

  • Reutilize o buffer de profundidade para o passe de iluminação, sem ter certeza de quão amplamente isso é suportado em dispositivos móveis, mas é uma textura de profundidade livre.
  • Uma única textura GBuffer, dentro dela, armazenaria: Normal U, Normal V, Param 0, Param 1. A codificação Lambert-Azimuthal parece realmente boa para normais e as comprime em apenas dois componentes, relativamente baratos para codificar e decodificar também.
  • Dois parâmetros para variáveis ​​de iluminação são muitos, poderiam usar um como uma enumeração para várias funções de iluminação se o hardware se sair bem com ramificação dinâmica.

A iluminação diferida é semelhante à renderização diferida, exceto que você renderiza a cena duas vezes:

  1. Renderize a profundidade da geometria, os normais e os parâmetros de iluminação no GBuffer.
  2. Renderize luzes no buffer de acumulação.
  3. Renderize Geometry com shaders de material, componha sua iluminação aqui também. Se você é bom em trabalhar com operadores reversos de equações de iluminação, pode fazer MUITAS coisas realmente legais com esta etapa.
  4. Faça qualquer pós-processamento que puder, não se esqueça de abusar da profundidade e das texturas normais até a morte aqui por causa da eficiência.

Sobre como armazenar os resultados da iluminação. Apreciei o armazenamento de cores difusas e luminância especular, para que o buffer de acumulação precise apenas ser uma textura de cor padrão de 32 bits. Você pode estimar a cor especular calculando o croma de cor difusa e combinando-o com a luminância especular.

A parte mais importante, porém, será usar o buffer de estêncil de profundidade ao máximo, para garantir que você não processe nenhum código de iluminação onde ele não é necessário. Eu chegaria ao ponto de adicionar algumas declarações de descarte aos sombreadores de fragmentos em termos que reduziriam a visibilidade da luz abaixo do intervalo de exibição do dispositivo (1e-3 é geralmente um corte seguro).

cronógrafo
fonte
discardé muito, muito ruim para pipelines baseados em blocos que muitas / a maioria das GPUs móveis usa.
Engineer
1

Considere iluminação adiada. Em resumo, a iluminação diferida é uma técnica que usa uma versão reduzida do sombreamento diferido para calcular um mapa de luz do espaço na tela. Em uma segunda passagem, a geometria é renderizada novamente usando o mapa de luz do espaço na tela como informações de iluminação.

Essa técnica é usada para reduzir o tamanho do G-Buffer, pois menos atributos são necessários. Também oferece a vantagem de que o G-Buffer e o mapa de luz do espaço na tela podem ter uma resolução mais baixa que a tela.

Eu havia implementado um renderizador estrito baseado em GLES 2.0 (embora experimental) e consegui reduzir o G-Buffer até uma textura RGBA (sim, usei um texture2D em vez de um renderbuffer). Ele continha o mapa normal do espaço na tela + o buffer de profundidade no canal alfa (que foi compactado usando um logaritmo, tanto quanto me lembro).

Os atributos de posição (denominados mundo aqui) podem ser calculados durante o passo de iluminação usando o fato de que, em uma projeção prospectiva , .xy é dividido por .z , de modo que:

xyfrvocêstvocêm=xyWoreud/zWoreud

Aproximei o atributo de posição xy fazendo:

xyWoreud=xyfrvocêstvocêmzWoreud

Nota: tive que fazer mais ajustes, dependendo das configurações da matriz de projeção.

Também digno de nota é que eu era capaz de omitir o componente .z dos vetores normais, pois eu podia reconstruir .z do .xy, pois o vetor normal é normalizado para que:

x2+y2+z2=1 1x2+y2+z2=1 1z2=1 1-(x2+y2)z=1 1-(x2+y2)

Usando essa técnica, fui capaz de liberar outro canal no meu RGBA G-Buffer e usei isso para armazenar o mapa especular do espaço da tela (ou brilho, se desejar).

Simon Schmidt
fonte
BTW: Meu renderizador não foi anexado a nenhum mecanismo de jogo. Foi meramente uma demonstração de olá, renderizando Suzanne.
Simon Schmidt
0

Sim, é absolutamente possível. A taxa de preenchimento não é um problema porque os chips gráficos móveis são projetados para lidar com telas de resolução muito alta. De fato, a renderização adiada ajuda nisso, porque seu cálculo de iluminação é independente da complexidade da cena; portanto, o excesso não causa lentidão. Aqui está minha implementação em um iPad de quarta geração: http://www.youtube.com/watch?v=K4X1oF6b4V8

Se você deseja quatro vezes o desempenho, apenas metade da resolução da textura para a qual você renderiza. Realmente não consigo ver nada diferente com gráficos 3D em uma tela de retina.

Os chips gráficos para dispositivos móveis são extremamente bons na renderização diferida devido à maneira como lidam com a renderização na textura. Diferentemente das placas gráficas de PC, que normalmente sofrem um grande impacto no desempenho quando você começa a renderizar em uma textura em vez de em um contexto de janela, os gráficos móveis são projetados para fazer isso sem impacto no desempenho. Assim, você obtém a escalabilidade de um renderizador diferido, sem a penalidade de desempenho inicial que você experimenta em uma placa gráfica de desktop.

No momento da minha implementação, o OpenGLES estava ausente na renderização para vários destinos, então tive que desenhar a cor da tela e o normal em passagens separadas. Isso pode ser corrigido nas versões mais recentes do OpenGLES, mas não sabemos se as soluções ainda estão disponíveis no hardware móvel do consumidor.

JoshKlint
fonte
3
"Os chips gráficos móveis são extremamente bons na renderização diferida devido à maneira como lidam com a renderização na textura. Ao contrário das placas gráficas para PC, que normalmente sofrem um grande impacto no desempenho quando você começa a renderizar em uma textura em vez de em um contexto de janela, os gráficos móveis são projetado para fazer isso sem afetar o desempenho ". Essa é uma afirmação enorme lá. Você tem alguma referência respeitável para apoiar esta reivindicação?
Panda Pyjama