Partie 1: Dissolution Shader
Le shader de dissolution renvoie un bel effet, de plus, il est facile à créer et à comprendre; Aujourd'hui, nous allons le faire dans 
Unity Shader Graph , et aussi écrire sur 
HLSL .
Voici un exemple de ce que nous allons créer:
Comment ça marche
Pour créer un shader de 
dissolution , nous devrons 
travailler avec la valeur 
AlphaClipThreshold dans le shader «Shader Graph» ou utiliser la fonction HLSL appelée 
clip .
Essentiellement, nous disons au shader de 
ne pas rendre le pixel en fonction de la 
texture et de la 
valeur transmises. Nous devons savoir ce qui suit: les 
parties blanches se dissolvent plus rapidement .
Nous utiliserons la texture suivante:
Vous pouvez créer les vôtres - des lignes droites, des triangles, mais n'importe quoi! N'oubliez pas que les 
parties blanches se dissolvent plus rapidement .
J'ai créé cette texture dans Photoshop en utilisant le filtre Clouds.
Même si vous n'êtes intéressé que par le Shader Graph et que vous ne savez rien de HLSL, je recommande toujours de lire cette partie, car il est utile de comprendre comment fonctionne le Unity Shader Graph à l'intérieur.
Hlsl
En HLSL, nous utilisons la fonction 
clip (x) . La fonction 
clip (x) supprime tous les pixels avec une valeur inférieure à 
zéro . Par conséquent, si nous appelons 
clip (-1) , nous serons sûrs que le shader ne rendra jamais ce pixel. Vous pouvez en savoir plus sur le 
clip dans 
Microsoft Docs .
Les propriétés
Le shader a besoin de deux propriétés, 
Dissoudre la texture et la 
quantité (qui indiqueront le processus d'exécution global). Comme pour les autres propriétés et variables, vous pouvez les appeler comme bon vous semble.
Properties { //Your other properties //[...] //Dissolve shader properties _DissolveTexture("Dissolve Texture", 2D) = "white" {} _Amount("Amount", Range(0,1)) = 0 } 
Assurez-vous d'ajouter ce qui suit après CGPROGRAM SubShader (en d'autres termes, déclarez les variables):
 sampler2D _DissolveTexture; half _Amount; 
N'oubliez pas non plus. que leurs noms doivent correspondre aux noms de la section Propriétés.
Fonction
Nous commençons la fonction 
Surface ou 
Fragment en échantillonnant la 
texture de la dissolution et en obtenant la 
valeur du rouge . PS Notre texture est stockée en 
niveaux de 
gris , c'est-à-dire que ses valeurs de 
R , 
G et 
B sont égales, et vous pouvez 
choisir n'importe laquelle d'entre elles . Par exemple, le 
blanc est 
(1,1,1) , le 
noir est 
(0,0,0) .
Dans mon exemple, j'utilise un shader de surface:
 void surf (Input IN, inout SurfaceOutputStandard o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).r;  
Et c'est tout! Nous pouvons appliquer ce processus à n'importe quel shader existant et le transformer en 
shader de dissolution !
Voici le Surface Shader standard du moteur Unity, transformé en 
shader de dissolution bilatéral : Shader "Custom/DissolveSurface" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 //Dissolve properties _DissolveTexture("Dissolve Texutre", 2D) = "white" {} _Amount("Amount", Range(0,1)) = 0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Cull Off //Fast way to turn your material double-sided CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; half _Glossiness; half _Metallic; fixed4 _Color; //Dissolve properties sampler2D _DissolveTexture; half _Amount; void surf (Input IN, inout SurfaceOutputStandard o) { //Dissolve function half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).r; clip(dissolve_value - _Amount); //Basic shader function fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = ca; } ENDCG } FallBack "Diffuse" } 
Graphique de shader
Si nous devons créer cet effet à l'aide du 
graphe Unity 
Shader , nous devons utiliser la valeur 
AlphaClipThreshold (qui fonctionne différemment du 
clip (x) de HLSL). Dans cet exemple, j'ai créé un shader PBR.
La fonction 
AlphaClipThreshold demande au shader de supprimer tous les pixels dont la valeur est inférieure à sa valeur 
Alpha . Par exemple, s'il est de 
0,3f et que notre valeur alpha est de 
0,2f , le shader 
ne rendra pas ce pixel. La fonction 
AlphaClipThreshold se trouve dans la 
documentation Unity : 
PBR Master Node et 
Unlit Master Node .
Voici notre shader fini:
Nous échantillonnons la 
texture de dissolution et obtenons 
la valeur rouge , puis l'ajoutons à la valeur 
Montant (qui est une propriété que j'ai ajoutée pour indiquer le processus d'exécution global, une valeur de 1 signifie une dissolution complète) et la connectons à 
AlphaClipThreshold . 
C'est fait!Si vous souhaitez l'appliquer à n'importe quel shader existant, 
copiez simplement 
les connexions de noeud vers 
AlphaClipThreshold (ne manquez pas les propriétés nécessaires!). Vous pouvez également le rendre 
recto-verso et obtenir un résultat encore plus beau!
Shader de dissolution de contour
Et si vous essayez d'y ajouter des 
contours ? Faisons-le!
Nous ne pouvons pas travailler avec des pixels déjà dissous, car après les avoir déposés 
, ils disparaissent à jamais . Au lieu de cela, nous pouvons travailler avec des valeurs «presque dissoutes»!
En 
HLSL, c'est très simple, il suffit d'ajouter quelques lignes de code après avoir calculé le 
clip :
 void surf (Input IN, inout SurfaceOutputStandard o) { //[...] //After our clip calculations if (dissolve_value - _Amount < .05f) //outline width = .05f o.Emission = fixed3(1, 1, 1); //emits white color //Your shader body, you can set the Albedo etc. //[...] } 
C'est fait!Lorsque vous travaillez avec 
Shader Graph, la logique est légèrement différente. Voici le shader fini:
Nous pouvons créer 
des effets très 
cool avec un simple 
shader de dissolution ; Vous pouvez expérimenter 
différentes textures et 
valeurs , ainsi que trouver autre chose!
Partie 2: Shader d'exploration du monde
Un shader d' 
exploration du monde (ou un « 
shader de dissolution du monde ou 
dissolution globale ») nous permet de masquer également tous les objets de la scène en fonction de leur distance à la position; maintenant, nous allons créer un tel shader dans le 
graphique Unity Shader et l'écrire en 
HLSL .
Voici un exemple de ce que nous allons créer:
La distance comme paramètre
Supposons que nous devions 
dissoudre un objet dans une scène s'il est 
trop éloigné du joueur . Nous avons déjà annoncé le paramètre 
_Amount , qui contrôle la disparition / dissolution de l'objet, nous devons donc le remplacer par la distance entre l'objet et le lecteur.
Pour ce faire, nous devons prendre les positions de 
joueur et d' 
objet .
Position du joueur
Le processus sera similaire pour 
Unity Shader Graph et 
HLSL : nous devons transférer la position du joueur dans le code.
 private void Update() {  
Graphique de shader
Position et distance de l'objet
En utilisant le Shader Graph, nous pouvons utiliser les nœuds Position et Distance.
PS Pour que ce système fonctionne avec Sprite Renderers, vous devez ajouter la propriété _MainTex, l'échantillonner et la connecter à albedo. Vous pouvez lire mon précédent tutoriel sur les 
shaders diffus Sprites (qui utilise le graphique des shaders).
HLSL (surface)
Position de l'objet
En HLSL, nous pouvons ajouter la variable 
worldPos à notre structure 
Input pour obtenir les positions des sommets des objets.
 struct Input { float2 uv_MainTex; float3 worldPos;  
Sur 
la page de documentation Unity, vous pouvez découvrir quels autres paramètres intégrés il est permis d'ajouter à la structure d'entrée.
Appliquer la distance
Nous devons utiliser la distance entre les objets et le joueur comme quantité de dissolution. Pour ce faire, vous pouvez utiliser la fonction de 
distance intégrée ( 
documentation Microsoft ).
 void surf (Input IN, inout SurfaceOutputStandard o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x; float dist = distance(_PlayerPos, IN.worldPos); clip(dissolve_value - dist/ 6f);  
Résultat (3D)
Résultat (2D)
Comme vous pouvez le voir, les objets se dissolvent «localement», nous n'avons pas obtenu un effet uniforme, car nous obtenons la «valeur de dissolution» de la texture échantillonnée en utilisant les UV de chaque objet. (En 2D, c'est moins visible).
3D LocalUV Dissolve Shader sur HLSL
 Shader "Custom/GlobalDissolveSurface" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness("Smoothness", Range(0,1)) = 0.5 _Metallic("Metallic", Range(0,1)) = 0.0 _DissolveTexture("Dissolve texture", 2D) = "white" {} _Radius("Distance", Float) = 1 //distance where we start to reveal the objects } SubShader{ Tags { "RenderType" = "Opaque" } LOD 200 Cull off //material is two sided CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 sampler2D _MainTex; sampler2D _DissolveTexture; //texture where we get the dissolve value struct Input { float2 uv_MainTex; float3 worldPos; //Built-in world position }; half _Glossiness; half _Metallic; fixed4 _Color; float3 _PlayerPos; //"Global Shader Variable", contains the Player Position float _Radius; void surf (Input IN, inout SurfaceOutputStandard o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x; float dist = distance(_PlayerPos, IN.worldPos); clip(dissolve_value - dist/ _Radius); fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = ca; } ENDCG } FallBack "Diffuse" } 
Sprites Diffuse - Local UV Dissolve Shader sur HLSL
 Shader "Custom/GlobalDissolveSprites" { Properties { [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {} _Color("Tint", Color) = (1,1,1,1) [MaterialToggle] PixelSnap("Pixel snap", Float) = 0 [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1) [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1) [PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {} [PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0 _DissolveTexture("Dissolve texture", 2D) = "white" {} _Radius("Distance", Float) = 1 //distance where we start to reveal the objects } SubShader { Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane" "CanUseSpriteAtlas" = "True" } Cull Off Lighting Off ZWrite Off Blend One OneMinusSrcAlpha CGPROGRAM #pragma surface surf Lambert vertex:vert nofog nolightmap nodynlightmap keepalpha noinstancing #pragma multi_compile _ PIXELSNAP_ON #pragma multi_compile _ ETC1_EXTERNAL_ALPHA #include "UnitySprites.cginc" struct Input { float2 uv_MainTex; fixed4 color; float3 worldPos; //Built-in world position }; sampler2D _DissolveTexture; //texture where we get the dissolve value float3 _PlayerPos; //"Global Shader Variable", contains the Player Position float _Radius; void vert(inout appdata_full v, out Input o) { v.vertex = UnityFlipSprite(v.vertex, _Flip); #if defined(PIXELSNAP_ON) v.vertex = UnityPixelSnap(v.vertex); #endif UNITY_INITIALIZE_OUTPUT(Input, o); o.color = v.color * _Color * _RendererColor; } void surf(Input IN, inout SurfaceOutput o) { half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x; float dist = distance(_PlayerPos, IN.worldPos); clip(dissolve_value - dist / _Radius); fixed4 c = SampleSpriteTexture(IN.uv_MainTex) * IN.color; o.Albedo = c.rgb * ca; o.Alpha = ca; } ENDCG } Fallback "Transparent/VertexLit" } 
PS Pour créer le dernier shader, j'ai copié le shader Unity Sprites-Diffuse standard et ajouté la partie «fondu» décrite plus haut dans cette partie de l'article. Tous les shaders standard peuvent être trouvés 
ici .
Rendre l'effet homogène
Pour rendre l'effet homogène, nous pouvons utiliser les coordonnées globales (position dans le monde) comme coordonnées UV de la texture de dissolution. Il est également important de définir 
Wrap = Repeat dans les paramètres de texture de dissolution afin que nous puissions répéter la texture sans le remarquer (assurez-vous que la texture est transparente et se répète bien!)
HLSL (surface)
 half dissolve_value = tex2D(_DissolveTexture, IN.worldPos / 4).x;  
Graphique de shader
Résultat (2D)
C'est le résultat: on peut remarquer que la texture de la dissolution est désormais uniforme pour le monde entier.
Ce shader est déjà 
idéal pour les jeux 2D , mais pour 
les objets 3D il doit être 
amélioré .
Le problème avec les objets 3D
Comme vous pouvez le voir, le shader ne fonctionne pas pour les faces "non verticales" et déforme considérablement la texture. C’est pourquoi il est que les coordonnées UV ont besoin de la valeur float2, et si nous passons worldPos, alors il ne reçoit que X et Y.
Si nous éliminons ce problème en appliquant des calculs pour afficher la texture sur toutes les faces, nous arriverons à un nouveau problème: lors de l'assombrissement, les objets se croiseront et ne resteront pas homogènes.
Il sera difficile pour les débutants de comprendre la solution: il faut se débarrasser de la texture, générer du bruit tridimensionnel dans le monde et en tirer la «valeur de dissolution». Dans cet article je ne vous expliquerai pas la génération de bruit 3D, mais vous pouvez trouver un tas de fonctions prêtes à l'emploi!
Voici un exemple de shader de bruit: 
https://github.com/keijiro/NoiseShader . Vous pouvez également apprendre à générer du bruit ici: 
https://thebookofshaders.com/11/ et ici: 
https://catlikecoding.com/unity/tutorials/noise/Je définirai ma fonction de surface de cette façon (en supposant que vous avez déjà écrit la partie bruit):
 void surf (Input IN, inout SurfaceOutputStandard o) { float dist = distance(_PlayerPos, IN.worldPos); //"abs" because you have to make sure that the noise is between the range [0,1] //you can remove "abs" if your noise function returns a value between [0,1] //also, replace "NOISE_FUNCTION_HERE" with your 3D noise function. half dissolve_value = abs(NOISE_FUNCTION_HERE(IN.worldPos)); if (dist > _Radius) { float clip_value = dissolve_value - ((dist - _Radius) / _Radius); clip(clip_value); if (clip_value < 0.05f) o.Emission = float3(1, 1, 1); } fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = ca; } 
Un bref rappel de HLSL: avant d'utiliser / d'appeler une fonction, elle doit être écrite / déclarée.
PS Si vous souhaitez créer un shader à l'aide du graphe Unity Shader, vous devez utiliser des nœuds personnalisés (et générer du bruit en y écrivant du code HLSL). Je parlerai des nœuds personnalisés dans un futur tutoriel.
Résultat (3D)
Ajout de contours
Pour ajouter des contours, vous devez répéter le processus de la partie précédente du didacticiel.
Effet inversé
Et si nous voulons inverser cet effet? (Les objets devraient disparaître si un joueur est à proximité)
Il nous suffit de changer une ligne:
 float dist = _Radius - distance(_PlayerPos, IN.worldPos); 
(Le même processus s'applique au Shader Graph).