Les fondamentaux à connaître sur le Shader Graph d'Unity3D

Shader Graph : les fondamentaux à connaître pour créer n’importe quel Shader (sans rien coder)

C’est tout nouveau, c’est tout chaud. Oui, la version 2018.1 d’Unity est disponible, avec son lot de nouveautés. Vous y trouverez entre autres le tant attendu Shader Graph. Mais comment faire pour tirer parti de cet outil ?

Vu de loin, ça a l’air vachement sexy, mais en vrai, comment ça se passe ?

Vous savez ce qu’il y a de pire que de ne pas avoir d’outils ? Avoir des outils à disposition mais ne pas savoir quel est leur but, ou comment s’en servir.

Prenons un exemple avec… ceci : (oui, c’est totalement hors contexte)

Exemple de machine dont ont ne connait pas ke fonctionnement

Cet outil semble performant dans ce qu’il est sensé faire… mais sans rire ça sert à quoi  ?!

Ceci est un « rogneur de souches » et permet de détruire le reste de la souche d’un arbre coupé. Tout d’un coup, cet outil prend du sens, mais je ne saurais toujours pas m’en servir… Maintenant, pensez au Shader Graph. C’est un super outil… mais savez-vous vraiment à quoi il sert ? Et comment l’utiliser ?

Suivre des tutoriels n’est pas suffisant

Vous avez peut-être déjà entendu parler du Shader Graph comme étant un super truc. Vous avez peut-être même déjà vu des tutoriels dessus. Mais concrètement, vous ne savez pas trop ce que ça cache. Et c’est bien le problème.

Recopier un exemple de shader depuis un tutoriel vous donnera un résultat satisfaisant, mais est-ce que vous saurez créer votre propre shader pour autant ? Avec le rendu que vous voulez ? Les effets que vous volez ? Ce petit truc artistique improbable ? Non. Parce que vous ne connaissez pas les tenants et les aboutissants.

Comment aborder le sujet

Commençons par la base. Avant de parler du Shader Graph, il faut que vous compreniez ce qu’est un shader. Savoir quel est son rôle dans un jeu vidéo et comment il est utilisé. Parce que le Shader Graph n’est qu’une façon visuelle de construire un shader. Si vous ne comprenez pas le fonctionnement d’un shader, c’est pas la peine d’aller plus loin, vous allez être largué.

Ensuite, il vous faudra comprendre le fonctionnement du Shader Graph. Comme expliqué juste avant, c’est un éditeur qui va vous permettre de construire un shader… sans écrire de code ! C’est d’autant plus cool que le langage pour écrire des shaders est assez bas niveau (difficile d’accès).

Enfin, pour pouvoir faire des trucs cools et expérimenter, vous devrez connaître les outils à disposition au sein du Shader Graph pour construire vos propres shaders.

C’est quoi un shader ?

Un shader est un petit programme qui va être exécuté sur votre carte graphique. Son but est (généralement mais pas que) de calculer la couleur d’un pixel à l’écran. Oui, UN SEUL pixel. Ce programme va être appelé autant de fois que vous avez de pixels sur votre écran, plusieurs dizaines de fois par seconde.

Petit exemple avec une résolution de 1920×1080 @60 FPS : le programme sera exécuté 124.416.000 fois en 1 seconde. Voilà, ça fait quand même beaucoup…

Mais ça tombe bien, parce que votre carte graphique (GPU) est physiquement conçue pour exécuter des calculs répétitifs à une cadence démentielle. A l’inverse de votre processeur (CPU) qui lui est plus flexible, mais « moins » rapide.

Grâce à ces shaders, votre programme (Unity) va pouvoir dessiner un rendu de votre scène depuis le point de vue de votre caméra et l’afficher à l’écran. Donc si vous voulez avoir des rendus un peu particuliers, il faut écrire des shaders custom. Ok ?

Le Shader Graph : un éditeur de shaders visuel

Ecrire des shaders est une tâche assez fastidieuse. C’est du code très bas niveau, avec une syntaxe bien particulière. Sans parler du fait que ce sont principalement des maths, des maths, et encore des maths. Le code d’un shader, ça ressemble à ça :

Exemple de code d'un shader simple

Heureusement, l’éditeur visuel est là pour vous faciliter la vie. Il va vous permettre d’assembler des briques les unes avec les autres pour arriver au même résultat que si vous l’aviez codé. Sauf que vous n’aurez fait que relier des boîtes les unes avec les autres. Un Shader Graph ressemble à quelque chose comme ça :

Exemple d'un Shader avec Shader Graph

Une fois que l’enchaînement vous convient, vous pourrez générer le shader correspondant, sans écrire la moindre ligne de code bas niveau. Tout est fait par le Shader Graph. Alors évidemment, il faut toujours que vous compreniez la manipulation d’image. Mais cela vous enlève la difficulté de l’écriture du shader en lui même, ce qui est quand même pas mal !

Note importante

Le Shader Graph d’Unity implique d’utiliser le nouveau système de rendu de la version 2018.1, le Scriptable Render Pipeline (SRP pour les intimes). Ce pipeline rend possible la personnalisation des visuels et donc la création de shaders via un éditeur visuel comme présenté plus bas. Via le SRP, vous pouvez utiliser plusieurs profils de rendus déjà préparés pour vous :

  • High Definition Render Pipeline (HDRP)
  • Lightweight Render Pipeline (LRP)

Mais pour l’instant, seul le LRP est compatible avec le Shader Graph (au 20/05/2018). Pour utiliser le Shader Graph, vous devrez donc paramétrer votre projet pour utiliser le Lightweight Render Pipeline. Si vous essayez d’utiliser le HDRP avec le Shader Graph, vous allez vous retrouver avec quelque chose comme ça :

Vos textures ne seront pas dessinées correctement et le résultat sera un violet bien flashy. Faites donc bien attention à ce détail et utilisez le Lightweight Render Pipeline !

Les fondamentaux du Shader Graph

Quand vous allez créer un nouveau Shader Graph, vous allez avoir un nœud comme ceci :

Noeud Master dans le Shader Graph

Ce nœud représente le résultat final du calcul de votre shader. C’est le « Master ». Le principe général est assez simple. Vous avez à disposition des blocs qui vont vous permettre d’effectuer certains calculs. En les reliant entre eux, vous allez pouvoir enchaîner différents calculs plus complexes pour obtenir votre résultat final dans le Master.

Vous pouvez voir sur la gauche qu’il y a des petits cercles. Ils représentent des points d’entrée de ce nœud. Vous allez pouvoir y glisser le résultat d’autres nœuds. Vous avez également des noeuds de calcul qui prennent des valeurs en entrée et ont des résultats en sortie :

Exemple de noeud avec entrés et sorties dans le Shader Graph

Dans cet exemple, il y a 2 entrées à gauche, et une sortie à droite. Vous pouvez également créer des nœuds « Input » qui vont avoir uniquement une sortie à droite. Via ces nœuds, vous allez pouvoir initialiser des « points de départ » dans votre graphe. Et oui, « des » points de départ, car vous en aurez plusieurs. Par exemple, une couleur ou une texture :

Exemple de noeuds de sortie dans le Shader Graph

En reliant vos blocs les uns aux autres, vous pourrez générer un enchaînement de calculs à effectuer pour arriver au résultat final.

Les propriétés du Shader Graph

Construire un Shader Graph avec des nœuds statiques, c’est bien, mais vous ne pourrez pas le personnaliser. Si vous voulez changer quelque chose, vous devrez recompiler votre shader. Autant dire que c’est pas top.

Pour régler ce soucis, vous avez à votre disposition la possibilité de créer des propriétés. Pour faire le rapprochement, c’est exactement la même chose que d’exposer des variables d’un script dans l’inspecteur. Une propriété d’un shader sera visible depuis l’inspecteur. C’est aussi simple que ça !

La création de propriétés se fait via le bouton « + » de la fenêtre Blackboard généralement en haut à gauche de votre fenêtre Shader Graph :

Fenêtre Blackboard du Shader Graph

Une fois une propriété créée, vous pouvez la glisser / déposer sur votre graph pour l’utiliser et elle apparaîtra dans l’inspecteur de votre shader (une fois compilé) :

Affichage dans l'inspecteur d'une propriété du Shader Graph

Avec cette mécanique, vous allez pouvoir rendre vos shaders paramétrables : textures, sliders, couleurs… tout ce que vous voulez !

Les types de variables

Vous l’aurez peut-être remarqué, la couleur des cercles d’entrée / sortie est parfois différente. En effet, chaque type de variable a sa propre couleur. D’un coup d’œil, vous pouvez donc savoir quel type de variable est renvoyé par quel nœud.

Vous pouvez également le déterminer en lisant le nom et plus précisément ce qui est entre parenthèses :

  • (1) = variable avec 1 composante (nombre à virgule)
  • (2) = variable avec 2 composantes (Vector2)
  • (3) = variable avec 3 composantes (Vector3)
  • (4) = variable avec 4 composantes (Vector4)
  • (B) = Booléen
  • (T) = Texture, dont chaque pixel est représenté par un Vector4 (ou une couleur si vous voulez)
  • (C) = Couleur, représentée par un Vector4 (x=rouge, y=vert, z=bleu, w=alpha)

C’est là que vous devez comprendre une chose vis à vis du Shader Graph. Les blocs de fonctions sont polyvalents et adaptables. Vous allez pouvoir appliquer une fonction sur une variable simple (Vector1) comme sur des variables composées (Vector2 ou Vector4).

Par exemple, la fonction « valeur absolue » prend par défaut un Vector1 en entrée et donne un Vector1 en sortie (la valeur absolue calculée) :

Exemple d'un noeud prenant un Vector1 en entrée dans le Shader Graph

Par contre, si en entrée, vous lui fournissez un Vector4, il s’adapte !

Exemple d'un noeud prenant s'adaptant à son entrée dans le Shader Graph

La fonction « valeur absolue » va alors être appliquée à toutes les composantes de la variable, et donc renvoyer un résultat sous la forme d’un Vector4. Ce fonctionnement peut être déroutant, mais il est important de le comprendre pour créer des effet complexes.

Quelques blocs du Shader Graph à connaître

Les nœuds mathématiques : Multiply, Substract, Add, Divide. Ce sont les opérations simples de mathématiques. Avec des blocs, vous pourrez jouer avec des valeurs pour les modifier. Par exemple pour mélanger des couleurs, ou pour les atténuer.

Le bruit. Vous pouvez demander à un shader de vous générer du « bruit » et vous en servir ensuite pour construire vos effets visuels. Vous n’avez pas idée de ce qu’il est possible de faire à partir d’un simple bruit comme ceci :

Exemple de noeud pour générer du bruit dans le Shader Graph

Lorsque vous allez utiliser des textures, vous aurez besoin de l’UV Mapping. Vous pouvez vous en passer si vous n’en avez pas besoin, une valeur par défaut sera utilisée. Mais en l’utilisant, vous pourrez jouer sur la façon dont la texture est utilisée sur la surface.

Autre élément que vous allez adorer : le temps.

Exemple de noeud pour utiliser l'écoulement du temps dans le Shader Graph

Oui, vous pouvez utiliser le temps dans votre shader. A quoi ça sert me direz-vous ? Et bien vous pouvez vous servir de cette variable qui va changer avec le temps pour modifier la façon dont le shader va dessiner votre texture pour la faire défiler par exemple, ou modifier la génération du bruit pour avoir un résultat différent.

A vous de grapher maintenant !

Vous avez maintenant toutes les bases pour COMPRENDRE comment créer vos propres shaders. Cet article a volontairement passé sous silences des détails techniques pour se concentrer sur les fondamentaux. En fouillant un peu, vous trouverez facilement comment créer un Shader Graph ou ajouter des nœuds. Comme par exemple cette vidéo (en anglais).

A partir de ces notions, vous allez pouvoir commencer à expérimenter et découvrir les différentes fonctions que vous avez sous la main dans le Shader Graph. Avec un peu de pratique, si ce domaine vous intéresse, vous ne tarderez pas à faire des effets visuels très sympas.

Soyez prévenus, vous tomberez sans doute par hasard sur des résultats improbables. Mais c’est la magie des shaders. Le tout rendu facile d’accès via le Shader Graph. Si vous combinez ça à des modèles créés avec ProBuilder et animés avec Mecanim. Vous aurez des résultats vraiment chouettes.

Une petite faveur pour terminer

J’ai maintenant une petite faveur à vous demander. Si cet article vous a permis d’y voir plus clair sur ce qu’est le Shader Graph et comment en tirer le meilleur, alors partagez le sur les réseaux.

D’une part pour donner un coup de pouce à Esprit Unity qui vous apporte régulièrement et gratuitement du contenu de grande qualité. Et d’autre part pour faire passer l’information auprès des autres créateurs.

Merci à vous !

Happy Gamedev !

  • Tepat dit :

    Super cool article ! Bien clair et parfait pour appréhender la notion des shaders. Merci 🙂

  • Jonathan dit :

    Salut et merci pour cette vue large, c’est bien plus clair !
    Je cherche à faire un shader qui détecterait les collision, tu aurais une idée de comment faire ça ? et si c’est possible avec le graph? merci !

    • Alex Frêne dit :

      Hello et merci pour ton commentaire Jonathan. Théoriquement, tu dois pouvoir faire des calculs de collision dans un shader, mais ce n’est pas prévu pour ça à la base. En état, si tu veux faire ça avec le Shader Graph il te faudra te créer tes propres noeuds.

  • >