Como implementar corretamente a mistura alfa em uma cena 3D complexa?

11

Sei que essa pergunta pode parecer um pouco fácil de responder, mas isso está me deixando louco. Existem muitas situações possíveis que um bom mecanismo de mistura alfa deve lidar e, para cada algoritmo em que consigo pensar, falta algo.

Estes são os métodos que eu pensei até agora:

  • Antes de pensar sobre a classificação dos objetos por profundidade, este simplesmente falha porque os Objetos não são formas simples, podem ter curvas e podem fazer um loop entre si. Portanto, nem sempre posso dizer qual é a mais próxima da câmera.

  • Então pensei em classificar triângulos, mas este também pode falhar. Embora não tenha certeza de como implementá-lo, há um caso raro que pode causar novamente um problema, no qual dois triângulos se cruzam. Mais uma vez, ninguém pode dizer qual deles está mais próximo.

  • A próxima coisa foi usar o buffer de profundidade, pelo menos a principal razão pela qual temos um buffer de profundidade é devido aos problemas de classificação que mencionei, mas agora temos outro problema. Como os objetos podem ser transparentes, em um único pixel, pode haver mais de um objeto visível. Então, para qual objeto devo armazenar a profundidade de pixels?

  • Então pensei que talvez eu possa armazenar apenas a profundidade do objeto mais frontal e, usando isso, determine como devo misturar as próximas chamadas de desenho nesse pixel. Mas, novamente, houve um problema, pense em dois planos semitransparentes com um plano sólido no meio deles. Eu ia renderizar o plano sólido no final, pode-se ver o plano mais distante. Observe que eu iria mesclar a cada dois planos até restar apenas uma cor para esse pixel. Obviamente, também posso usar métodos de classificação por causa dos mesmos motivos que expliquei acima.

  • Finalmente, a única coisa que imagino poder trabalhar é renderizar todos os objetos em diferentes destinos de renderização, classificar essas camadas e exibir a saída final. Mas desta vez não sei como posso implementar esse algoritmo.

Ali1S232
fonte

Respostas:

11

Resposta curta

Olhe em profundidade descascando . Da minha pesquisa, parece ser a melhor alternativa, embora computacionalmente cara, porque exige várias passagens de renderização. Aqui está outra implementação mais recente e mais rápida , também da NVIDIA.

Resposta longa

Essa é uma pergunta difícil . A maioria dos livros que li examinou o assunto e o deixou em:

Comece renderizando todos os objetos opacos e depois misture os objetos transparentes sobre eles na ordem inversa.

Porém, é mais fácil falar do que fazer, porque a abordagem óbvia de classificar objetos por seus centróides não garante a ordem de classificação correta.

É exatamente o mesmo problema porque o algoritmo do pintor não funciona para o caso geral e é necessário um buffer de profundidade .

Com isso dito, um dos livros que tenho menciona algumas soluções:

  • Peeling de profundidade - uma solução de múltiplas passagens que supera a limitação do buffer de profundidade, fornecendo o enésimo fragmento mais próximo, e não apenas o mais próximo. A maior vantagem é que você pode renderizar os objetos transparentes em qualquer ordem e não há necessidade de classificar. Pode ser caro por causa das várias passagens, mas o link que forneci na parte superior parece melhorar o desempenho.

  • Buffer K roteado com estêncil - Use o roteamento com estêncil para capturar várias camadas de fragmentos por pixel por passagem de geometria. A principal desvantagem é que os fragmentos precisam ser classificados em um passe de pós-processamento.

Ele também menciona uma solução de hardware para o problema, mas não acho que esteja realmente disponível:

  • F-Buffer - Um buffer FIFO de ordem de rasterização para renderização multipass. No entanto, uma boa leitura e a introdução também falam um pouco sobre o problema da ordem de classificação por transparência e as soluções atuais.

Outras soluções alternativas que não fornecem resultados perfeitos, mas são melhores que nada:

  • Depois tornando todos os objetos opacos, continue usando Z-tampão teste para objetos transparentes, mas desabilitar a gravação Z-buffer . Você pode obter alguns artefatos da classificação incorreta, mas pelo menos todos os objetos transparentes estarão visíveis.

E citando o whitepaper do buffer F acima:

A solução mais simples é renderizar cada polígono parcialmente transparente completamente independente (ou seja, renderizar todas as suas passagens antes de prosseguir para o próximo polígono). Essa solução geralmente é proibitivamente cara devido ao custo de mudança de estado incorrido. Como alternativa, o aplicativo ou a biblioteca de sombreamento pode agrupar polígonos para garantir que apenas os polígonos não sobrepostos sejam renderizados juntos. Na maioria dos casos, essa solução também não é atraente, porque requer que o software realize análises de polígonos no espaço da tela.

David Gouveia
fonte
11

A resposta correta é # 1: classifique todas as suas coisas por profundidade e processe-as (obviamente desative a gravação em profundidade, mas não teste). O que é uma "coisa"?

Cada "coisa" deve ser um objeto convexo; não pode se sobrepor. Se você tem um objeto côncavo, deve ser dividido em pedaços convexos.

Essa é a maneira padrão de renderizar uma cena transparente. Resolve casos de interpenetração? Não. Ele resolve casos em que você tem 3 objetos em que nenhuma ordem de profundidade pode ser determinada? Não. Ele resolve casos em que você tem um objeto longo que se sobrepõe a um pequeno que está mais próximo em sua profundidade central? Não.

Mas funciona bem o suficiente . Jogos não usam peeling de profundidade. Eles não usam buffers k roteados com estêncil. Eles não usam buffers F. Por quê? Porque essas coisas são incrivelmente lentas.

Você pode obter artefatos com o método padrão. Mas pelo menos o seu jogo corre razoavelmente rápido.

Se você deseja restringir-se ao hardware DX11 ou superior, existem maneiras de implementar a mistura com a classificação adequada. Eles são mais lentos, mas não tão lentos quanto as técnicas anteriores. E, diferentemente do descascamento profundo que pode introduzir artefatos, este é preciso para a amostra. Além disso, o desempenho do algoritmo geralmente é por fragmento (e até certo ponto por sobreposição dentro de cada fragmento). Portanto, se você não desenhou muitas coisas transparentes, o desempenho é mínimo.

Eu não sei se a técnica tem um nome simples , mas uma implementação para o pre-GL4.2 pode ser encontrada aqui. Uma versão do D3D11 pode ser encontrada aqui (Powerpoint, PPSX, compatível com Libre).

Nicol Bolas
fonte
Bons pontos nesta resposta. Pessoalmente, eu também aceitaria o suficiente (o que descrevi na minha resposta, como uma solução alternativa), pois a maioria das técnicas que listei são provavelmente mais problemas do que valem. Além disso, técnica interessante no final, acho que não estava listada na renderização em tempo real, na qual pesquisei minha resposta. Eu sou um noob completo quando se trata de recursos de nível DX11.
David Gouveia
"Uma implementação para a pré-GL4.2 pode ser encontrada aqui" 404
Jeroen van Langen