Um esboço geral:
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.
Renderize sua cena normalmente, passe o mapa de profundidade para seu shader de escudo.
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.
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:
O mapa de profundidade é em escala de cinza, para que você possa obter o valor de qualquer canal (usei r
aqui).
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]. smoothstep
faz isso muito bem. o1.0 -
é inverter o valor tal que solidsDiff
seja 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 solidsDepth
já 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.0
diferença.
O - 0.005
deslocamento 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!