Como escrevo um sombreador que acende quando os objetos estão perto de uma superfície?


15

Em deste Overwatch vídeo gameplay , escudo do personagem acende branco em áreas que estão perto de geometria de outros objetos.

Escudo de Reinhart recortando alguma geometria de nível

Observe as bordas brancas no escudo azul, próximo ao chão, paredes e pilar.

Acredito que o escudo tenha seu próprio modelo e o efeito seja feito com um sombreador, mas estou perdido tentando descobrir como traduzir o conceito de "proximidade" para a programação do sombreador.


2
Se você estiver usando o Unity, essa conversa pode ser interessante . Verifique a seção "Destaques da interseção" começando no slide 26.
DMGregory

Portanto, a resposta já foi abordada abaixo, mas aqui está um vídeo que a explica: youtube.com/watch?v=C6lGEgcHbWc
CobaltHex

Respostas:


28

Um esboço geral:

  1. Crie um mapa de profundidade da sua cena sem o escudo. Você pode obtê-lo de forma eficaz e gratuita, pois objetos transparentes geralmente são renderizados em uma passagem posterior de qualquer maneira. Caso contrário, você pode criar o mapa de profundidade renderizando a cena sem proteção em um RTT com um shader de profundidade.

  2. Renderize sua cena normalmente, passe o mapa de profundidade para seu shader de escudo.

  3. No sombreador, calcule a diferença na profundidade da cena da profundidade do fragmento de escudo e use essa diferença para modificar a cor do fragmento.

Demo

Eu escrevi uma demo WebGL simples disso.

captura de tela da demo

Linha por linha

Vamos examinar o código do shader fragment em detalhes:

float solidsDepth = texture2D(depthMap, gl_FragCoord.xy / dims).r;

Prove o mapa de profundidade em cada fragmento. Lembre-se de dividir pelas dimensões da janela de exibição para converter seu fragmento do espaço da tela [0, largura / altura] em coordenadas normalizadas [0,0, 1,0]. Nesse ponto, se você simplesmente definir a cor do fragmento para o pixel do mapa de profundidade amostrado, ele terá a seguinte aparência:

captura de tela do mapa de profundidade

O mapa de profundidade é em escala de cinza, para que você possa obter o valor de qualquer canal (usei raqui).

float solidsDiff = 1.0 - smoothstep(
    zNear,
    zFar,
    gl_FragCoord.z / gl_FragCoord.w
  ) - solidsDepth;

Você pode usar essa amostra de profundidade para encontrar a diferença entre a profundidade da cena e a profundidade do fragmento de escudo. Lembre-se de normalizar sua profundidade também, para passar de [zNear, zFar] (os planos próximos e distantes da sua câmera) para [0,0, 1,0]. smoothstepfaz isso muito bem. o1.0 - é inverter o valor tal que solidsDiffseja 1,0 quando a diferença for o máximo (zFar - zNear) e 0,0 no mínimo (0,0).

Observe que eu assumi que solidsDepthjá estava normalizado no shader de profundidade que criou o mapa de profundidade.

float alpha = 0.3 + max(0.0, 1.0 - log(100.0 * (solidsDiff - 0.005) + 1.0));

Você pode modificar o canal alfa do seu escudo, dependendo da diferença de profundidade. Aqui começamos com um alfa mínimo de 0.3, em seguida, criamos um bom aumento acentuado de alfa à medida que nos aproximamos da 0.0diferença.

O - 0.005deslocamento apenas adiciona uma margem branca para tornar a "interseção" mais espessa. Tente modificá-lo!

gl_FragColor = vec4(vec3(1.0), alpha);

E, finalmente, aplique esse alfa à cor do seu fragmento.


Aprimoramentos

Você pode fazer um escudo curvo, adicionar plasma para uma aparência de "escudo de energia" (demo) ou explorar efeitos apenas com as interseções exibidas (demo) .

O céu Sua placa de vídeo é o limite!


Oh. Minhas. Boas notícias. Ty para o tutorial incrível.
Blue Bug

5

É apenas usando o mapa de profundidade. Renderiza o mundo, renderiza o escudo e faz uma diferença entre o valor z renderizado do escudo e o valor z do buffer de profundidade para colorir o pixel mais branco.


3

Não sei qual mecanismo, se houver, você está usando. Ou com qual idioma você está trabalhando. Ainda assim, a maioria do que você pode encontrar on-line não é difícil de transportar de um ambiente para o outro para alcançar o que você está procurando.

E certamente há material on-line que pode ser útil para você. Veja esta discussão relacionada ao Unity: http://www.superspacetrooper.com/2012/06/tutorial-force-field-weapon-impact-energy-dispersion/ e esta pergunta relacionada ao UE4: https: //answers.unrealengine. com / questions / 74858 / dynamic-forcefield-shader.html . Para um exemplo completo de shader, implementando esse efeito de escudo, de um debate bastante recente no Reddit, você pode ver: https://www.reddit.com/r/Unity3D/comments/3edi0n/does_any_one_knows_how_to_make_this_shield_effect/ E para um tutorial que não é exatamente sobre isso, mas está relacionado o suficiente para ser de interesse: http://www.nightbox-studios.com/2015/09/05/assets-shield-effect-scripts-for-texture3d-perlin-noise-shader/

Além disso, aqui estão os links para três perguntas relacionadas feitas anteriormente neste site, que provavelmente serão de grande ajuda para entender os conceitos por trás do que você deseja alcançar:

Alargamento do escudo da nave espacial

Como implementar um escudo de energia da guerra nas estrelas no jogo

Efeito de escudo XNA com um problema de esfera primitiva

Por fim, existem algumas implementações interessantes de shaders de escudo no Unity e no Unreal Engine em suas respectivas lojas virtuais, se você estiver usando algum desses mecanismos. Eles geralmente são ativos pagos, é claro, mas quase sempre são de código aberto após a compra - e geralmente são baratos. Mesmo que você não use esses mecanismos, esses recursos podem ajudar a brincar e aprender.

Espero que ajude.


Embora esses links sejam úteis, essa resposta é basicamente apenas links e, na verdade, não aborda a questão diretamente. Seria melhor extrair o conteúdo relevante dos links em uma explicação real.
Anko20:

Embora esse link possa responder à pergunta, é melhor incluir aqui as partes essenciais da resposta e fornecer o link para referência. As respostas somente para links podem se tornar inválidas se a página vinculada for alterada. - Da avaliação
Vaillancourt

@ Anko Claro, meu mal. Geralmente incluo uma explicação e uma coleção de links, mas desta vez você está certo, a explicação real estava faltando. Provavelmente vou excluir a resposta, então.
Mand

@AlexandreVaillancourt Não gosto da ideia de copiar e colar de outro link em vez de redirecionar o OP para a fonte original. Então, o que eu acho melhor é fornecer links nos comentários para a pergunta. O problema é que você conhece bastante material que pode ser útil, mas é grande demais para comentários. Mas ainda assim, como uma boa explicação já foi postada aqui,
apagarei
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.