Os shaders podem pintar pixels da tela além daqueles ocupados pela malha sombreada?

8

Tenho alguma experiência em programação de geometria e computação de sombreadores - mas nunca me aventurei em realmente brincar com os sombreadores de fragmento. Atualmente, estou tentando entender melhor como eles funcionam e seu potencial. Uma das coisas que li em vários lugares é que um fragmento (isto é, um pixel da tela) não pode se estender além de si mesmo dentro do sombreador de fragmentos. O que significa que um determinado fragmento sendo iterado só pode afetar a si mesmo.

Portanto, e para o aprendizado, eu gostaria de saber se o seguinte é possível (e se é, como, em linhas gerais, ele pode ser alcançado). Suponha que tenhamos, por uma questão de simplicidade, uma malha de pontos que consiste em apenas dois vértices (localizados no espaço do mundo 3D). Podemos programar um sombreador de forma que cada um desses dois vértices seja pintado na tela na posição exata do WorldToViewport, mas também que um círculo ao redor de cada um deles de raio = R também seja pintado nos pixels adjacentes, mesmo que eles se estendam além da malha original à qual o shader está conectado? Como na figura abaixo (onde o quadrado vermelho no centro dos círculos representa os vértices pintados na tela):

insira a descrição da imagem aqui

Se isso for possível, um sombreador também pode ser programado de tal forma que esses círculos que se estendem além dos vértices influenciam a cor (RGBA) um do outro? Como na figura abaixo:

insira a descrição da imagem aqui

Como eu disse, se essas são possíveis, eu gostaria de ouvir um pouco de como conseguir isso - em termos conceituais ou práticos. Isso é feito no shader de fragmento ou precisa ser calculado antes no shader de vértice ou geometria? Como calcular e passar "fragmentos adicionais" que se estendem além dos fragmentos ocupados pelo corpo da malha?

AndrewSteer
fonte
Um sombreador de geometria pode adicionar mais primitivas do que as encontradas na malha original. Isso faz isso por você?
Andreas

Respostas:

6

Quando você usa largura de linha ou antialiasing de linha ou largura de ponto ou pontos, o OpenGL cria para você um pequeno retângulo em vez da linha ou ponto, com coordenadas de textura. Atualmente, você pode programar você mesmo usando sombreadores de geometria ou até mesmo o mosaico.

Uma abordagem totalmente diferente é usar sombreamento adiado, usando uma passagem geométrica apenas para armazenar informações no buffer RGBAZ e, em seguida, uma segunda passagem que você executa em todos os pixels da tela para realizar algum processo. (para atuar em todos os pixels, basta desenhar um retângulo em tela cheia). Hoje em dia você pode até fazer a primeira passagem como uma ou várias "renderizar para textura" e depois mapear MIP essas texturas, para que a passagem final possa acessar facilmente valores menos locais.

Fabrice NEYRET
fonte
Obrigado! Fiz o que você disse no começo, usando sombreadores de geometria para criar geometria em torno dos pontos e, assim, permitir desenhar pixels em torno do ponto. Funciona, é claro, mas é uma solução mais complicada. Fiquei particularmente interessado nos últimos trechos do que você disse: se eu entendi direito, o que você menciona é que pode renderizar toda a cena e, em seguida, usar um sombreador de tela voltado para a área de interesse e fazer uma passagem pelo quadro renderizado para trabalhar com quantos pixels se deseja em torno dos pontos no centro?
AndrewSteer
Você pode renderizar a primeira passagem em uma textura. Em seguida, na segunda passagem na tela cheia, em cada pixel você pode inspecionar o conteúdo da textura em um disco ao redor do pixel e fazer o que quiser (por exemplo, cor de acordo com o pixel mais próximo preenchido ou pintar de branco apenas se a distância estiver abaixo de algum limite) . É claro que para discos apenas desenhar, este está longe de ser a forma mais eficiente ;-)
Fabrice Neyret
Claro, acabei de dar o exemplo simples em que pude pensar. Mas sim, acho que o que você diz está alinhado com o que eu estava pensando, ou seja, renderizando uma textura em uma passagem e depois temos as informações para, em outras passagens, alterar pixels em relação ao que está localizado nos pixels adjacentes . Muito Obrigado.
AndrewSteer
3

Uma boa maneira de organizar um círculo (ou outra forma) a ser desenhado para cada vértice de uma malha é usar instâncias geométricas . Esse é um recurso da GPU que permite desenhar várias instâncias (cópias) de uma malha de uma só vez, com os vértices / índices da malha fornecidos por um conjunto de buffers e outro buffer de vértice que pode fornecer dados adicionais por instância. O sombreador de vértice pode ser usado para combinar os dados de ambos os buffers da maneira que você escolher.

Para ser concreto, no seu caso, você pode criar uma malha representando um círculo do raio desejado, com seus vértices especificados diretamente nas coordenadas do espaço da tela e centralizados na origem. Em seguida, você usaria instanciamento para fazer a GPU renderizar uma nova cópia da malha circular para cada vértice da malha pontual original. No sombreador de vértice, você calcula a posição no espaço da tela do ponto (usando as transformações de projeção de visão de mundo como de costume) e depois traduz a malha do círculo para centralizar nessa posição.

Quanto à segunda parte da sua pergunta, sobre como os círculos influenciam a cor um do outro: depende especificamente do que você deseja fazer. A mistura de hardware pode ser usada para lidar com casos simples, como adicionar ou multiplicar as cores ou mistura alfa. Se você quiser algo mais complicado que isso, talvez seja possível fazer isso com um algoritmo de várias passagens ou (nas GPUs mais recentes) mistura programável.

Nathan Reed
fonte