¿Cómo escribo un sombreador que se ilumina cuando los objetos están cerca de una superficie?

15

En este video de juego de Overwatch , el escudo del personaje se ilumina en blanco en áreas cercanas a la geometría de otros objetos.

El escudo de Reinhart recorta algo de geometría nivelada

Tenga en cuenta los bordes blancos en el escudo azul, cerca del piso, las paredes y el pilar.

Creo que el escudo tiene su propio modelo y el efecto se realiza con un sombreador, pero estoy perdido tratando de imaginar cómo traducir el concepto de "proximidad" a la programación del sombreador.

Bicho azul
fuente
2
Si está utilizando Unity, esta charla puede ser de interés . Consulte la sección sobre "Aspectos destacados de la intersección" que comienza en la diapositiva 26.
DMGregory
Entonces, la respuesta ya se ha cubierto a continuación, pero aquí hay un video que lo explica: youtube.com/watch?v=C6lGEgcHbWc
CobaltHex

Respuestas:

28

Un esquema general:

  1. Crea un mapa de profundidad de tu escena sin el escudo. Puede obtener esto de forma gratuita, ya que los objetos transparentes a menudo se representan en un pase posterior de todos modos. De lo contrario, puede crear el mapa de profundidad al representar la escena sin escudo en un RTT con un sombreador de profundidad.

  2. Renderice su escena normalmente, pase el mapa de profundidad a su sombreador de escudo.

  3. En el sombreador, calcule la diferencia en la profundidad de la escena desde la profundidad del fragmento de escudo y use esa diferencia para modificar el color del fragmento.

Manifestación

Escribí una demostración simple de WebGL de eso.

captura de pantalla de la demo

Linea por linea

Repasemos en detalle el código del sombreador de fragmentos:

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

Muestree el mapa de profundidad en cada fragmento. Recuerde dividir por las dimensiones de su ventana gráfica para convertir su fragmento del espacio de pantalla [0, ancho / alto] a coordenadas normalizadas [0.0, 1.0]. En este punto, si simplemente establece el color del fragmento en el píxel del mapa de profundidad muestreado, se vería así:

captura de pantalla del mapa de profundidad

El mapa de profundidad es en escala de grises, por lo que puede obtener el valor de cualquier canal (que usé raquí).

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

Luego puede usar esa muestra de profundidad para encontrar la diferencia entre la profundidad de la escena y la profundidad del fragmento de escudo. Recuerde normalizar su profundidad también, para tomarla de [zNear, zFar] (los planos cercano y lejano de su cámara) a [0.0, 1.0]. smoothstephace esto muy bien El 1.0 -es invertir el valor tal que solidsDiffsea ​​1.0 cuando la diferencia es máxima (zFar - zNear) y 0.0 como mínimo (0.0).

Tenga en cuenta que supuse que solidsDepthya estaba normalizado en el sombreador de profundidad que creó el mapa de profundidad.

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

Luego puede modificar el canal alfa de su escudo dependiendo de la diferencia de profundidad. Aquí comenzamos con un alfa mínimo de 0.3, luego creamos un agradable aumento agudo en alfa a medida que nos acercamos a la 0.0diferencia.

El - 0.005desplazamiento solo agrega un margen blanco para hacer que la "intersección" sea más gruesa. ¡Intenta modificarlo!

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

Y finalmente, aplique ese alfa a su color de fragmento.


Mejoras

Puede hacer un escudo curvo, agregar plasma para una apariencia de "escudo de energía" (demostración) o explorar efectos con solo las intersecciones que muestran (demostración) .

El cielo ¡ Tu tarjeta gráfica es el límite!

Yousef Amar
fuente
Oh. Mi. Buenas noticias. Ty por el increíble tutorial.
Blue Bug
5

Solo está usando el mapa de profundidad. Representa el mundo y luego representa el escudo y toma una diferencia entre el valor z representado del escudo y el valor z del búfer de profundidad para teñir el píxel más blanco.

Sirio
fuente
3

No sé qué motor, si alguno, está utilizando. O con qué idioma estás trabajando. Aún así, la mayoría de lo que puede encontrar en línea no es difícil de transportar de un entorno a otro para lograr lo que está buscando.

Y ciertamente hay material en línea que puede serle de ayuda. Vea esta discusión relacionada con Unity: http://www.superspacetrooper.com/2012/06/tutorial-force-field-weapon-impact-energy-dispersion/ y esta pregunta relacionada con UE4: https: //answers.unrealengine. com / preguntas / 74858 / dynamic-forcefield-shader.html . Para un ejemplo completo de sombreador, implementando ese efecto de escudo, desde un debate bastante reciente en Reddit, puede ver: https://www.reddit.com/r/Unity3D/comments/3edi0n/does_any_one_knows_how_to_make_this_shield_effect/ Y para un tutorial que no es exactamente en eso, pero está lo suficientemente relacionado como para interesar: http://www.nightbox-studios.com/2015/09/05/assets-shield-effect-scripts-for-texture3d-perlin-noise-shader/

Además, aquí están los enlaces para 3 preguntas relacionadas hechas previamente en este mismo sitio, que probablemente serán de gran ayuda para comprender los conceptos detrás de lo que desea lograr:

Flama de escudo de nave espacial

Cómo implementar un escudo de energía de guerra de las galaxias en el juego

Efecto escudo XNA con un problema de esfera primitiva

Por último, hay bastantes implementaciones agradables de sombreadores de escudo tanto en Unity como en Unreal Engine en su tienda virtual respectiva, si está usando alguno de esos motores. Por lo general, son activos pagados, pero casi siempre son de código abierto después de la compra, y con frecuencia son baratos. Incluso si no usa estos motores, esos activos pueden ser de ayuda para jugar y aprender.

Espero eso ayude.

Mand
fuente
Aunque esos enlaces son útiles, esta respuesta es básicamente solo enlaces y en realidad no aborda la pregunta directamente. Sería mejor extraer el contenido relevante de los enlaces en una explicación real.
Anko
Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden volverse inválidas si la página vinculada cambia. - De la opinión
Vaillancourt
@ Anko Claro, mi mal. Normalmente incluyo una explicación y una colección de enlaces, pero esta vez tienes razón, faltaba la explicación real. Probablemente borre la respuesta, entonces.
2015
@AlexandreVaillancourt No me gusta la idea de copiar y pegar desde otro enlace en lugar de redirigir el OP a la fuente original. Entonces, lo que creo que es mejor es dar enlaces en los comentarios a la pregunta. El problema con esto es cuando conoces mucho material que puede ser de ayuda pero es demasiado grande para comentarios. Pero aún así, dado que una buena respuesta explicativa ya se publicó aquí, simplemente borraré esta
2015