
Ce week-end, j'ai eu du temps libre entre les cours
(l'auteur recevait un Master of Science au moment de l'article) , et j'ai décidé de revenir à la création de shaders en inventant cet effet de scan post-process. J'ai imaginé qu'il est utilisé dans le jeu comme une sorte d'effet de balayage à distance. Nous utilisons également une simple distorsion du bruit pour rendre l'effet un peu plus intéressant.
Dans cet article, je vais vous expliquer comment implémenter cet effet sur UE4. Il existe plusieurs façons de créer cet effet. Une de ces méthodes a été choisie par moi.
Vous pouvez ouvrir des images dans un nouvel onglet pour les afficher en plus haute résolution.
Composants principaux
L'idée principale de cet effet est de créer une version du rendu de scène en utilisant
l'opérateur Sobel , puis de le mélanger avec un rendu de scène basé sur SphereMask, que nous allons animer pour créer un effet de balayage.
Cet effet se compose de 3 composants principaux:
- Champ évolutif SphereMask
- Fonction Sobel-Edge (je n'expliquerai pas comment cette fonction fonctionne, car il s'agit d'un sujet distinct, mais je ferai référence au code que j'ai utilisé)
- Superposez la texture projetée sur la grille mondiale
Champ évolutif SphereMask
Cette partie explique comment créer un masque de sphère évolutif. Pour ce faire, nous transférons la position du plan dans l'ensemble des paramètres du matériau, après quoi nous l'utilisons comme suit

Connectez le résultat du nœud
Clamp à la sortie
émissive de votre matériel et vous verrez quelque chose comme ça

«TexLoc» est
vector3 , qui détermine l'emplacement de la source de la sphère, dans mon cas, il est lu à partir d'un ensemble de paramètres matériels, de sorte qu'il peut également être lu à partir du jeu lui-même, par exemple, pour déterminer la position du joueur.
L'ensemble des paramètres de nœud spécifié ci-dessus crée un champ avec un rayon de sphère de 1024 unités. Je l'ai utilisé uniquement pour afficher le résultat dans la fenêtre d'aperçu. Si vous souhaitez en savoir plus sur l'utilisation des fonctions à distance et comprendre comment les utiliser, je vous recommande vivement de consulter
le site Web d'Inigo Quilez .
Nous allons maintenant utiliser
Time pour mettre la sphère à l'échelle avec un intervalle de temps défini.

Cela nous donnera le résultat suivant
Frac (temps) nous donne essentiellement une période constante qui continue à aller de 0-1,0-1,0-1. Nous multiplions le temps par 0,25 pour contrôler la vitesse de mise à l'échelle, puis multiplions le résultat par le rayon de la sphère, ce qui conduit à un changement de rayon de 0 à 1024, et nous donne un masque animé.
C'est un bon résultat, mais ce n'est pas ce que nous voulons de l'effet. Nous avons besoin d'un anneau de mise à l'échelle. Cela peut être fait facilement à l'aide de calculs simples.

Cela nous donnera ce que nous voulons, un anneau en croissance, avec un bon dégradé dégradé qui peut être contrôlé.

Les opérations mathématiques dans le bloc Edge_Mask sélectionnent essentiellement la position dans le masque de dégradé, dans ce cas la valeur est 0,5, et détermine le bord du masque à partir de la position actuelle avec une largeur donnée, ce qui nous permet d'obtenir un anneau. Je n'entrerai pas dans les détails techniques pour obtenir les bords du masque, très probablement j'en parlerai dans l'un des articles suivants.
Comme vous pouvez le voir, vous avez un contrôle total sur la largeur de l'anneau sans paramètre scalaire, et si nous le voulions, nous pourrions même contrôler l'atténuation des bords, mais nous n'en avons pas besoin dans cet effet.
L'étape suivante consiste à utiliser le bruit pour créer une version visuellement intéressante de l'anneau.
Pour cela, nous utiliserons le nœud
Vector Noise , qui fait partie de UE4. Vous pouvez lire à ce sujet
ici , ou vous pouvez utiliser une texture de bruit qui contient des coordonnées UV alignées sur le monde.
Dans mon shader, j'ai défini le paramètre
Function dans Cellnoise dans le
nœud Vector Noise , n'hésitez pas à expérimenter avec d'autres types de ce paramètre pour obtenir votre propre effet unique.

Le résultat se présentera comme suit

Ceci est la première étape de notre shader est terminée, puis nous envisagerons la mise en œuvre de la fonction Sobel-Edge.
Fonction Sobel-Edge
Il existe de nombreuses options différentes pour cette fonctionnalité, dont certaines sont plus optimisées que d'autres, je n'expliquerai pas son essence, car il s'agit d'un sujet distinct, mais une recherche Google régulière avec les mots-clés "Sobel Edge" ou "Sobel Operator" vous donnera de nombreuses options . Ou utilisez l'article sur le
hub de
Gepard_vvk -
Algorithms pour sélectionner les contours des images .
L'idée principale de l'opérateur Sobel est la suivante: nous prenons le
RenderTarget de la scène (imaginez que c'est une texture qui contient ce que vous voyez actuellement dans votre fenêtre) et comparons chaque pixel avec tous les pixels voisins qui l'entourent. Ensuite, nous comparons la différence de luminosité, et si la différence est supérieure à un certain seuil, nous la marquons comme un bord, et dans ce processus, nous obtenons un
masque de texture
RenderTarget noir et blanc, dans lequel un masque est ajusté sur les bords.
Le code ci-dessous est un exemple simple de la fonction d'opérateur Sobel que
RebelMoogle a créée sur le site Web de Shadertoy (très probablement, cette option n'est pas entièrement optimisée, vous pouvez donc essayer une autre implémentation), nous la recréerons dans UE4 dans notre matériel.
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)); }
Dans UE4, cela ressemble à ceci

Une note
rapide sur l'implémentation de la fonction - assurez-vous que vos nœuds
SceneTexture sont configurés pour utiliser
PostProcessInput0
Deux nœuds
personnalisés GradX et
GradY , configurez-les de manière similaire
GradX :
return -TL + TR - 2.0 * ML + 2.0 * MR - BL + BR;
GradY :
return TL + 2.0 * TM + TR - BL - 2.0 * BM - BR;
Cela ne doit pas être fait dans
Custom , je l'ai utilisé juste pour plus de commodité, car sinon il y aurait trop de nœuds et des spaghettis se formeraient.
Si vous branchez le résultat de la fonction dans une sortie de matériau
émissif , vous verrez ce qui suit

Nous multiplions également le résultat par le
vecteur régulier3 pour créer les bords de la couleur que nous voulons.

En conséquence, la couleur du bord change.

Monde de superposition de texture de grille
La partie la plus simple: nous utilisons simplement la texture de la grille et la projetons dans le monde entier, puis la combinons avec la fonction Sobel-Edge pour obtenir un effet cool.

Si vous connectez le résultat de la fonction à la sortie
émissive , vous verrez

Tout mettre ensemble
Maintenant, nous allons assembler les trois parties pour notre effet de post!
Tout d'abord, nous combinons les fonctionnalités Sobel-Edge et World-Aligned-Grid, en les regroupant

Ensuite, nous créons un nœud
SceneTexture et nous y ajoutons le résultat de Sobel-Edge et World-Aligned-Grid.
Ensuite, nous interpolons entre la scène normale et la scène ajoutée, en utilisant le résultat du masque d'anneau que nous avons créé dans la première partie

Et le tour est joué, nous l'avons fait. Le résultat final ressemblera à quelque chose comme ça. Vous pouvez bien sûr ajuster les paramètres et essayer de changer leurs valeurs pour obtenir des options plus intéressantes.

J'espère que vous trouverez ces informations utiles, tout le meilleur :)
Un exemple de projet avec ce shader peut être trouvé sur
github .