Comment puis-je écrire un shader qui s'allume lorsque des objets sont près d'une surface?

15

Dans cette vidéo de jeu Overwatch , le bouclier du personnage s'allume en blanc dans les zones proches de la géométrie d'autres objets.

Le bouclier de Reinhart coupe une géométrie de niveau

Remarquez les bords blancs sur le bouclier bleu, près du sol, des murs et du pilier.

Je crois que le bouclier a son propre modèle et l'effet se fait avec un shader, mais je suis perdu à essayer de comprendre comment traduire le concept de "proximité" en programmation de shader.

Blue Bug
la source
2
Si vous utilisez Unity, cette présentation peut vous intéresser . Consultez la section «Faits saillants des intersections» à partir de la diapositive 26.
DMGregory
La réponse a donc déjà été abordée ci-dessous, mais voici une vidéo qui l'explique maintenant: youtube.com/watch?v=C6lGEgcHbWc
CobaltHex

Réponses:

28

Un aperçu général:

  1. Créez une carte de profondeur de votre scène sans le bouclier. Vous pouvez l'obtenir efficacement gratuitement, car les objets transparents sont souvent rendus dans un passage ultérieur de toute façon. Sinon, vous pouvez créer la carte de profondeur en rendant la scène sans bouclier sur un RTT avec un shader de profondeur.

  2. Rendez votre scène normalement, passez la carte de profondeur à votre shader de bouclier.

  3. Dans le shader, calculez la différence de profondeur de scène à partir de la profondeur du fragment de bouclier et utilisez cette différence pour modifier la couleur du fragment.

Démo

J'ai écrit une simple démonstration WebGL de cela.

capture d'écran de la démo

Ligne par ligne

Passons en revue le code du fragment shader en détail:

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

Échantillonnez la carte de profondeur à chaque fragment. N'oubliez pas de diviser par les dimensions de votre fenêtre pour convertir votre fragment de l'espace d'écran [0, largeur / hauteur] en coordonnées normalisées [0,0, 1,0]. À ce stade, si vous définissez simplement la couleur du fragment sur le pixel de la carte de profondeur échantillonnée, cela ressemblerait à ceci:

capture d'écran de la carte de profondeur

La carte de profondeur est en niveaux de gris, vous pouvez donc obtenir la valeur de n'importe quel canal (j'ai utilisé rici).

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

Vous pouvez ensuite utiliser cet échantillon de profondeur pour trouver la différence entre la profondeur de la scène et la profondeur du fragment de bouclier. N'oubliez pas de normaliser également votre profondeur, pour la faire passer de [zNear, zFar] (les plans proche et éloigné de votre appareil photo) à [0.0, 1.0]. smoothsteple fait bien. Le 1.0 -est d'inverser la valeur telle que solidsDiff1,0 lorsque la différence est le maximum (zFar - zNear) et 0,0 au minimum (0,0).

Notez que j'ai supposé qu'il solidsDepthétait déjà normalisé dans le shader de profondeur qui a créé la carte de profondeur.

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

Vous pouvez ensuite modifier le canal alpha de votre bouclier en fonction de la différence de profondeur. Ici, nous commençons à un alpha minimum de 0.3, puis créons une belle augmentation nette de l'alpha lorsque nous approchons de la 0.0différence.

Le - 0.005décalage ajoute juste une marge blanche pour rendre "l'intersection" plus épaisse. Essayez de le modifier!

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

Et enfin, appliquez cet alpha à la couleur de votre fragment.


Améliorations

Vous pouvez créer un bouclier incurvé, ajouter du plasma pour un look "bouclier d'énergie" (démo) ou explorer les effets avec juste les intersections affichées (démo) .

Le ciel Votre carte graphique est la limite!

Yousef Amar
la source
Oh. Ma. Bonnes nouvelles. Ty pour le super tutoriel.
Blue Bug
5

Il utilise simplement la carte de profondeur. Il rend le monde, puis rend le bouclier et prend une différence entre la valeur z rendue du bouclier et la valeur z du tampon de profondeur pour teinter le pixel plus blanc.

Sirisian
la source
3

Je ne sais pas quel moteur, le cas échéant, vous utilisez. Ou avec quelle langue vous travaillez. Pourtant, la plupart de ce que vous pouvez trouver en ligne n'est pas difficile à transférer d'un environnement à l'autre pour atteindre ce que vous recherchez.

Et il y a certainement du matériel en ligne qui peut vous être utile. Voir cette discussion relative à Unity: http://www.superspacetrooper.com/2012/06/tutorial-force-field-weapon-impact-energy-dispersion/ et cette question relative à UE4: https: //answers.unrealengine. com / questions / 74858 / dynamic-forcefield-shader.html . Pour un exemple de shader complet, mettant en œuvre cet effet de bouclier, à partir d'un débat assez récent dans Reddit, vous pouvez voir: https://www.reddit.com/r/Unity3D/comments/3edi0n/does_any_one_knows_how_to_make_this_shield_effect/ Et pour un tutoriel qui n'est pas exactement à ce sujet mais est suffisamment lié à d'intérêt: http://www.nightbox-studios.com/2015/09/05/assets-shield-effect-scripts-for-texture3d-perlin-noise-shader/

En outre, voici les liens pour 3 questions connexes précédemment faites dans ce site, qui sont susceptibles d'être d'une grande aide pour saisir les concepts derrière ce que vous voulez réaliser:

Bouclier de vaisseau spatial Flare

Comment mettre en œuvre un bouclier d'énergie Starwar dans le jeu

Effet de bouclier XNA avec un problème de sphère primitive

Enfin, il existe quelques implémentations intéressantes de shaders de boucliers dans Unity et dans Unreal Engine dans leur magasin virtuel respectif, si vous utilisez l'un de ces moteurs. Ce sont généralement des actifs payés, mais ils sont presque toujours open source après l'achat - et sont souvent bon marché. Même si vous n'utilisez pas ces moteurs, ces ressources peuvent vous aider à jouer et à apprendre.

J'espère que cela aide.

MAnd
la source
Bien que ces liens soient utiles, cette réponse est simplement des liens et ne répond pas directement à la question. Il serait préférable d'extraire le contenu pertinent des liens dans une explication réelle.
Anko
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien de référence. Les réponses de lien uniquement peuvent devenir invalides si la page liée change. - De l'avis
Vaillancourt
@Anko Bien sûr, ma mauvaise. J'inclus habituellement une explication et une collection de liens, mais cette fois vous avez raison, la vraie explication manquait. Je supprimerai probablement la réponse, alors.
2015
@AlexandreVaillancourt Je n'aime pas l'idée de simplement copier-coller à partir d'un autre lien au lieu de rediriger l'OP vers la source d'origine. Ensuite, je pense que le mieux est de donner des liens dans les commentaires à la question. Le problème avec cela, c'est quand vous connaissez beaucoup de matériel qui peut être utile, mais c'est trop gros pour les commentaires. Mais encore, car une bonne explication réponse était déjà affichée ici, je me contenterai d' effacer celui - ci
Mand