Unreal Engine4 - efeito de verificação pós-processo



Neste fim de semana, tive um tempo livre entre as aulas (o autor estava recebendo um Master of Science no momento do artigo) e decidi voltar a criar shaders inventando esse efeito de digitalização pós-processo. Imaginei que ele fosse usado no jogo como uma espécie de efeito de varredura à distância. Também usamos algumas distorções simples de ruído para tornar o efeito um pouco mais interessante.

Neste artigo, mostrarei como implementar esse efeito no UE4. Existem várias maneiras pelas quais você pode criar esse efeito. Um desses métodos foi escolhido por mim.

Você pode abrir imagens em uma nova guia para visualizá-las em alta resolução.

Componentes principais


A idéia principal desse efeito é criar uma versão da renderização da cena usando o operador Sobel e depois misturá-la com a renderização de cena habitual baseada no SphereMask, que animaremos para criar um efeito de varredura.

Este efeito consiste em 3 componentes principais:

  • Campo escalável SphereMask
  • Função Sobel-Edge (não explicarei como essa função funciona, pois é um tópico separado, mas vou me referir ao código que usei)
  • Sobrepor a textura projetada na grade mundial

Campo escalável SphereMask


Esta parte é sobre como criamos o SphereMask escalável. Para fazer isso, transferimos a posição do blueprint para o conjunto de parâmetros do material, após o que o usamos da seguinte maneira



Conecte o resultado do nó Clamp à saída emissiva do seu material e você verá algo parecido com isto



"TexLoc" é o vetor3 , que determina a localização da fonte da esfera; no meu caso, é lido a partir de um conjunto de parâmetros materiais, para que também possa ser lido no próprio jogo, por exemplo, para determinar a posição do jogador.

O conjunto de parâmetros do nó especificado acima cria um campo com um raio de esfera de 1024 unidades. Eu usei apenas para mostrar o resultado na janela de visualização. Se você quiser saber mais sobre como trabalhar com funções remotas e entender como usá-las, recomendo consultar o site da Inigo Quilez .

Agora usaremos o Tempo para dimensionar a esfera com um intervalo de tempo definido.



Isso nos dará o seguinte resultado



Frac (time) basicamente nos dá um período constante que continua indo 0-1.0-1.0-1. Multiplicamos o tempo por 0,25 para controlar a velocidade da escala e, em seguida, multiplicamos o resultado pelo raio da esfera, o que leva a uma mudança no raio de 0 a 1024 e nos fornece uma máscara animada.

Este é um bom resultado, mas não é isso que queremos do efeito. Precisamos de um anel de escala. Isso pode ser feito facilmente usando cálculos simples.



Isso nos dará o que queremos, um anel crescente, com um bom desbotamento gradiente que pode ser controlado.



As operações matemáticas no bloco Edge_Mask basicamente selecionam a posição na máscara de gradiente; nesse caso, o valor é 0,5 e determina a borda da máscara a partir da posição atual com uma determinada largura, o que nos permite obter um anel. Não vou entrar em detalhes técnicos sobre como obter as bordas da máscara, provavelmente vou falar sobre isso em um dos seguintes posts.

Como você pode ver, você tem controle total sobre a largura do anel sem um parâmetro escalar e, se quiséssemos, poderíamos controlar a atenuação das arestas, mas não precisamos disso nesse efeito.

O próximo passo é usar o ruído para criar uma versão visualmente interessante do anel.

Para isso, usaremos o nó Vector Noise , que faz parte do UE4. Você pode ler sobre isso aqui ou pode usar uma textura de ruído que contém coordenadas UV alinhadas ao mundo.

No meu sombreador, defino o parâmetro Function como Cellnoise no Vector Noise , fique à vontade para experimentar outros tipos desse parâmetro para obter seu próprio efeito exclusivo.



O resultado terá a seguinte aparência



Este é o primeiro estágio do nosso sombreador, então consideraremos a implementação da função Sobel-Edge.

Função Sobel-Edge


Existem muitas opções diferentes para esse recurso, algumas das quais são mais otimizadas que outras. Não explicarei sua essência, pois esse é um tópico separado, mas uma pesquisa regular no Google com as palavras-chave “Sobel Edge” ou “Sobel Operator” oferecerá muitas opções . Ou use o artigo no hub do Gepard_vvk - Algorithms para selecionar contornos de imagens .

A idéia principal do operador Sobel é a seguinte: pegamos o RenderTarget da cena (imagine que seja uma textura que contém o que você está vendo atualmente na sua janela de exibição) e comparamos cada pixel com todos os pixels vizinhos ao seu redor. Em seguida, comparamos a diferença de brilho e, se a diferença estiver acima de um determinado limite, marcamos como uma aresta e, nesse processo, obtemos uma máscara de textura RenderTarget em preto e branco, na qual uma máscara é ajustada nas arestas.

O código abaixo é um exemplo simples da função do operador Sobel que o RebelMoogle criou no site Shadertoy (provavelmente essa opção não está totalmente otimizada para que você possa tentar outra implementação); nós a recriaremos no UE4 em nosso material.

void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord.xy / iResolution.xy; vec3 TL = texture(iChannel0, uv + vec2(-1, 1)/ iResolution.xy).rgb; vec3 TM = texture(iChannel0, uv + vec2(0, 1)/ iResolution.xy).rgb; vec3 TR = texture(iChannel0, uv + vec2(1, 1)/ iResolution.xy).rgb; vec3 ML = texture(iChannel0, uv + vec2(-1, 0)/ iResolution.xy).rgb; vec3 MR = texture(iChannel0, uv + vec2(1, 0)/ iResolution.xy).rgb; vec3 BL = texture(iChannel0, uv + vec2(-1, -1)/ iResolution.xy).rgb; vec3 BM = texture(iChannel0, uv + vec2(0, -1)/ iResolution.xy).rgb; vec3 BR = texture(iChannel0, uv + vec2(1, -1)/ iResolution.xy).rgb; vec3 GradX = -TL + TR - 2.0 * ML + 2.0 * MR - BL + BR; vec3 GradY = TL + 2.0 * TM + TR - BL - 2.0 * BM - BR; fragColor.r = length(vec2(GradX.r, GradY.r)); fragColor.g = length(vec2(GradX.g, GradY.g)); fragColor.b = length(vec2(GradX.b, GradY.b)); } 


No UE4, parece com isso



Uma observação rápida sobre a implementação da função - verifique se os nós do SceneTexture estão configurados para usar PostProcessInput0



Dois nós personalizados GradX e GradY , configuram-nos de maneira semelhante



GradX :

 return -TL + TR - 2.0 * ML + 2.0 * MR - BL + BR; 

GradY :

 return TL + 2.0 * TM + TR - BL - 2.0 * BM - BR; 

Isso não precisa ser feito no Custom , usei-o apenas por conveniência, pois, caso contrário, haveria muitos nós e espaguete se formariam.

Se você conectar o resultado da função a uma saída de material emissivo , verá o seguinte



Também multiplicamos o resultado pelo vetor regular3 para criar as bordas de qualquer cor que desejarmos.



Como resultado, a cor da aresta muda.



Mundo de sobreposição de textura de grade


A parte mais simples: nós apenas usamos a textura da grade e a projetamos em todo o mundo, e então a combinamos com a função Sobel-Edge para obter um efeito interessante.



Se você conectar o resultado da função à saída emissiva , verá



Juntando tudo


Agora vamos juntar as três partes para o nosso efeito pós!

Primeiro, combinamos os recursos Sobel-Edge e World-Aligned-Grid, reunindo-os



Em seguida, criamos um nó SceneTexture e adicionamos o resultado de Sobel-Edge e World-Aligned-Grid a ele.

Depois, interpolamos entre a cena normal e a cena adicionada, usando o resultado da máscara de anel que criamos na primeira parte



E pronto, nós fizemos. O resultado final será mais ou menos assim. Obviamente, você pode ajustar os parâmetros e tentar alterar seus valores para obter opções mais interessantes.



Espero que você ache essas informações úteis, tudo de bom :)

Um exemplo de projeto com esse shader pode ser encontrado no github .

Source: https://habr.com/ru/post/pt435240/


All Articles