Usando vários shaders

53

Atualmente, estou estudando shaders opengl, mas não consigo descobrir algo: como aplicar shaders diferentes aos objetos, por exemplo, um bule processado usando toon shader e outro na mesma cena usando uma superfície muito reflexiva e outra distorcida de uma função de ruído, como neste vídeo

http://www.youtube.com/watch?v=1ogg4ZfdBqU

Outro está aplicando um shader de bloom em uma cena e um shader de motion blur depois. Como obter esses efeitos quando você pode ter apenas um shader de vértice e um shader de fragmento? Existe algum truque, como usar mais de um programa shader?

ibrabeicker
fonte
Com as boas respostas de Nathan e David, é por isso que você vê o termo render pass ou shader pass ; são necessárias várias passagens para compor a imagem / quadro final. Um dos motivos pelos quais o processamento da GPU se tornou tão paralelo e, portanto, tão rápido é a necessidade de várias passagens por quadro. Volte para os renderizadores de software Quake II ou Half Life para se lembrar de quanto passe de shader de amor acrescenta toda a experiência gráfica em 3D.
Engenheiro

Respostas:

59

A resposta simples é que você as altera entre cada chamada de empate. Defina um shader, desenhe um bule, coloque outro shader, desenhe outro bule.

Para coisas mais complexas, nas quais você precisa aplicar vários shaders a apenas um objeto, como desfoque, brilho e assim por diante. Você basicamente tem tudo renderizado para textura (s). Em seguida, você renderiza um quad em toda a tela com a textura aplicada ao usar outro sombreador.

Por exemplo, se você deseja renderizar um efeito de brilho, primeiro precisa renderizar sua cena regular e não brilhante, depois renderize apenas a silhueta colorida do material que deseja brilhar em uma textura, depois mude para um sombreamento de desfoque e renderize seu quad com essa textura anexada à sua cena não brilhante.

Há outra técnica chamada sombreamento adiado onde você renderiza a cena sem iluminação e a aplica posteriormente no espaço da tela. O objetivo principal é reduzir as despesas de iluminação por pixel.

Normalmente você renderiza um buffer de cores que é colocado na tela. Com o sombreamento diferido, você processa um buffer de cores e um buffer normal e de profundidade em uma passagem do shader (você pode armazenar os vetores normais e a profundidade em uma textura como no mapeamento normal e de altura).

Isso significa que, para cada pixel, você sabe a posição da peça mais próxima da geometria não transparente (profundidade ou distância do olho), a cor e o normal. Por esse motivo, você pode aplicar iluminação a cada pixel da tela em vez de a cada pixel visível de cada objeto que renderizar. Lembre-se de que algum objeto será desenhado por cima de outros objetos se a cena não for perfeitamente renderizada na ordem inversa ou inversa.

Para as sombras, você realmente renderiza apenas o buffer de profundidade do ponto de vista da sua luz e, em seguida, usa essas informações de profundidade para descobrir onde a luz atinge. Isso é chamado de mapeamento de sombra (também existe outra abordagem chamada volumes de sombra que elabora uma silhueta da geometria e a expulsa, mas você ainda usará sombreadores).

Com o OpenGL mais moderno (3.0+), você usa um Objeto Framebuffer com Objetos Renderbuffers anexados. Como os renderbuffers podem ser tratados como uma textura. Você pode fazer coisas como renderizar 1 shader para vários buffers de renderização diferentes (para que você não precise renderizar sua textura, suas normais e componentes de brilho), mas a prática subjacente ainda é a mesma.

Também é desejável minimizar o número de comutadores de sombreador, tanto quanto possível, para economizar em sobrecarga. Assim, alguns motores agrupam tudo com o mesmo material para que tudo possa ser desenhado de uma só vez.

David C. Bishop
fonte
16

Você apenas liga um shader, renderiza todos os objetos usando esse shader, depois vincula o próximo shader, processa os objetos usando aquele, etc.

Você pode ter quantos objetos shader (shaders carregados na memória e compilados) quiser; somente um pode ser vinculado (ativo) por vez.

Nathan Reed
fonte
5
Em termos de implementação, em todos os quadros eu uso glUseProgram (1) e glUseProgram (2) para alterar os shaders? Qual é o custo do desempenho?
Ibrabeicker 11/01/12
4
É um custo não trivial (embora seja menor nas GPUs recentes que nas anteriores). É por isso que a maioria das pessoas classifica seus objetos por material, renderizando todos os objetos com o mesmo material. Mas você certamente pode mudar de programa dezenas a centenas de vezes por quadro, se não mais.
Nathan Reed
9

Usar mais de um sombreador em uma cena é bastante simples; altere o sombreador, defina os valores para ele e renderize o objeto.

Cuidado, no entanto, os comutadores de sombreamento podem ser caros, portanto, a troca de sombreadores deve ser mantida no mínimo. Existem algumas maneiras de reduzir esse impacto enquanto obtém todos os efeitos desejados.

O primeiro método, e geralmente o mais desejável, é adicionar a funcionalidade de todas as suas técnicas de sombreador a apenas um sombreador e usar as condições definidas para renderizar cada objeto de uma maneira diferente com o mesmo sombreador. Não sei sobre os shaders OpenGL e GLSL, mas com os shaders HLSL e o DirectX, eles podem ser agrupados como uma "técnica" e você pode definir a técnica em vez de alterar o shader. Isso permite que você tenha vários shaders de pixel e vértice diferentes no mesmo arquivo.

A segunda maneira de reduzir o impacto no desempenho é definir o sombreador, renderizar todos os objetos que usam esse sombreador e repetir. Em outras palavras, agrupando sua renderização.

Se você deseja aplicar dois efeitos diferentes ao mesmo objeto (ou seja, aplicar um toon shader e alguma iluminação), é possível fazê-lo de duas maneiras diferentes. O primeiro é escrever um sombreador que aplique múltiplos efeitos na mesma função. A segunda maneira é renderizar o modelo uma vez com cada sombreador e mesclar os resultados definindo diferentes opções de mesclagem. No entanto, isso é muito mais trabalhoso e inviável em todas as circunstâncias. Portanto, a melhor opção é combinar todos os seus efeitos em um shader.

OriginalDaemon
fonte
7

Outra maneira de descobrir isso é através de algo chamado sub-rotinas glsl, em que cada tipo de sombreador é definido em uma função e, no aplicativo OpenGL, podemos definir a sub-rotina atual, desenhar o vértice de um buffer, alterar a sub-rotina e renderizando outro buffer

ibrabeicker
fonte
4
Isso requer hardware compatível com GL 4.x, que é do tipo DX11.
Nicol Bolas