Les shaders sont des programmes informatiques qui communiquent directement avec la carte graphique pour créer des visuels. N’aie pas peur si tu ne sais pas coder, il en existe de nombreux prêts à être utilisés ! A partir de la version 1.10, HeavyM dispose même d’une bibliothèque qui en intègre déjà une centaine. 

Dans ce tutoriel, nous détaillerons l’utilisation de la bibliothèque de shaders dans HeavyM et nous te donnerons quelques ressources si tu souhaites trouver de nouveaux shaders ou même en créer toi-même !

 

Utiliser les shaders dans HeavyM

Ajouter un shader dans un player

Pour ajouter un shader dans HeavyM, il faut tout d’abord ajouter un player en faisant un drag & drop depuis l’icône correspondante dans la barre d’outils. Une forme rectangulaire délimitant ton player apparaît alors dans ton plan de travail et un panneau de paramètres s’affiche sur la gauche.

Par défaut, un player est en mode média (vidéo, image ou GIF). Pour passer en mode shader, tu dois cliquer sur l’icône correspondante dans la partie paramètres de ton player.

 

Le panneau s’ouvre en cliquant sur un player, puis tu peux le garder affiché en cliquant sur l’icône de punaise 

Tu peux ensuite ouvrir ta bibliothèque de shaders en appuyant sur l’icône +. Tu peux voir que HeavyM te propose une centaine de shaders prêts à être utilisés. Il te suffit de sélectionner celui que tu veux et de cliquer sur “Open”. (Tu peux aussi directement double cliquer sur le shader de ton choix.) 

HeavyM shaders library
Survole les miniatures pour prévisualiser les shaders

Ensuite, depuis le panneau des players, tu peux modifier les paramètres de ton shader comme tu le souhaites !

Note : n’oublie pas de cliquer sur play et de choisir une option d’affichage pour ton player pour le voir dans la projection ! Pour en savoir plus sur le fonctionnement des players en général, consulte le tuto sur le sujet.

HeavyM shader uniform values
Le shader BitStreamer a de nombreuses uniform values !

Les paramètres des shaders sont appelés des uniform values et diffèrent selon le shader que tu choisis. Tu trouveras une grande variété de paramètres, comme des variables de couleur, vitesse, position, etc. Certains shaders prennent aussi une source en entrée : tu peux utiliser une image, une vidéo, un flux webcam ou même syphon/spout (seulement dans HeavyM Live pour ce dernier). Le shader est alors appliqué sur ta source et tu peux voir les modifications en temps réel !

 

Gérer sa bibliothèque de shaders

Comme tu as pu le voir, tu disposes déjà d’une centaine de shaders prêts à être utilisés. Ceux-ci ont été fournis par les créateurs du format ISF : VidVoxMais en plus de ceux-là, la bibliothèque te permet de stocker tes créations ou trouvailles. Elle a été introduite à partir de la version 1.10 et peut contenir des shaders ISF, ainsi que GLSL « classiques » dont les variables ont été adaptées à HeavyM (ce sont simplement des noms de formats, plus d’infos sur comment s’en procurer dans la suite du tuto.)

Ta collection personnelle se trouve dans le deuxième onglet de la bibliothèque, intitulé « My Shaders ». Pour ajouter un shader, il suffit de cliquer sur   et parcourir les fichiers sur ton ordinateur. Ces fichiers doivent être des .fs pour les ISF ou des .frag pour les GLSL classiques. 

Quand tu ajoutes un shader, celui-ci est copié dans le dossier correspondant à ta bibliothèque HeavyM sur ton ordinateur. Il est ensuite utilisable dans HeavyM comme les autres shaders. Tu peux gérer ta bibliothèque comme tu l’entends, supprimer certains shaders, mais aussi ajouter une image ou un gif qui servira de miniature pour ton shader pour te retrouver plus facilement dans la liste.

Note technique 1 : certains ISF contiennent également un .vs qui sera copié automatiquement avec s’il se trouve dans le même dossier et porte le même nom.

Note technique 2 : HeavyM ne supporte pas aujourd’hui les shaders prenant du son en entrée. Vous pouvez aussi rencontrer des problèmes de compatibilité avec certains ISF v1 ou utilisant des persistent buffer et des multipass, notamment sur Mac si votre carte graphique n’est pas spécialisée. De manière générale, n‘hésitez pas à mettre à jour vos pilotes graphiques, cela peut régler certains soucis. Le site ISF permet également de convertir les isf v1 en v2.

Note technique 3 : HeavyM est capable de détecter et afficher certains types d’erreurs dans les shaders, celles-ci sont alors affichées dans un pop up et te donne des indications sur les problèmes dans le code. 

 

Où trouver des shaders compatibles ?

Il y a de nombreuses sources qui vont te permettre de trouver de nouveaux shaders à utiliser dans HeavyM sans avoir à les créer toi-même. En effet, il existe une communauté très active d’artistes qui partagent leur travail. Voici quelques ressources et conseils pour trouver et importer des shaders dans HeavyM :

Tout d’abord, sache que les shaders au format ISF, qui tend à se démocratiser, sont très simples à ajouter : si tu trouves un .fs, tu peux directement l’importer et l’utiliser dans HeavyM comme décrit ci-dessus. A l’inverse, un .frag classique, s’il n’a pas été créé spécifiquement pour HeavyM, ne sera pas directement compatible avec le logiciel. Tu peux l’adapter toi-même à la main (la méthodologie est décrite dans la dernière partie de ce tuto), ou plus simplement utiliser un convertisseur .frag → .fs. (Attention, si tu es sur une version de HeavyM antérieure à la 1.10, les ISF ne sont pas pris en charge, tu dois donc te référer à la méthode « manuelle ».)

Voici quelques liens qui te seront utiles :

interactiveshaderformat.com homepage
page d’accueil du site interactiveshaderformat.com

Note : selon l’usage que tu comptes en faire, n’oublie pas de vérifier la licence qu’a choisie le créateur ! Elle est souvent indiquée au début du code du shader.

Bien sûr, tu peux aussi créer toi-même tes propres shaders ! Si cela t’intéresse, la suite de ce tuto te donnera plus d’infos sur les aspects techniques des shaders et la démarche pour se lancer dans la création de contenu.

 

Comprendre les shaders et créer ses propres contenus

Mais au fait, qu’est-ce qu’un shader exactement ?

Un shader est un programme informatique qui communique directement avec la carte graphique pour afficher une image. Si tu veux comprendre les shaders dans le détails, tu peux trouver beaucoup de ressources sur le web, comme ce tutoriel assez complet qui permet de bien débuter.

Dans HeavyM, on utilise des fragment shaders. Pour faire simple il s’agit du programme qui détermine la couleur de chaque pixel dans l’image que tu veux afficher. Pour faire fonctionner ces programmes, il faut au minimum une carte graphique supportant une version OpenGL 2.0.

En ce qui concerne la différence entre les formats, les ISF ne sont en fait rien d’autre que des fragment shaders GLSL légèrement modifés afin d’être compris plus facilement par des applications interactives et ainsi créer un standard. Pour faire simple, une partie du code d’un ISF décrit comment l’interpréter, c’est pour cela que tu n’as pas besoin de le convertir pour l’utiliser dans HeavyM (plus d’explications par les créateurs du format ici).

 

Créer son propre shader ISF

Si tu veux créer tes propres shaders, nous t’incitons donc à écrire directement des ISF, afin qu’il soient compatibles avec le plus d’applications. Néanmoins, si tu veux en créer spécifiquement pour une version de HeavyM antérieure à la 1.10 qui ne supporte que les .frag, tu devras te référer à la partie suivante pour comprendre comment déclarer les uniform values dans ce cas.

Nous n’allons pas t’apprendre à coder ici, mais voici quelques conseils pour commencer :

Tu peux déjà aller voir les shaders sur le site d’ISF et jouer à les modifier pour voir ce qu’il se passe. Par exemple, tu peux commencer par le shader Solid Color qui affiche simplement une couleur. Clique en haut à gauche sur « FS » pour afficher le code et essaye de le modifier, tu verras tes changement appliqués en direct sur la visualisation. Puis tu peux aller voir le shader Linear Gradient. Tu peux essayer de le modifier aussi et évoluer ainsi vers des shaders de plus en plus complexes.

Tu pourras alors te lancer et commencer à créer tes propres shaders ISF en allant sur la page d’accueil et en cliquant sur « create your own » et ainsi avoir accès à un template ISF de base. Note : il existe d’autres éditeurs en ligne ou en application avec une prévisualisation en direct, comme ISF Editor (seulement sur MAC pour le moment).

Voilà, si tu veux plus de détails théoriques sur comment fonctionne le code des ISF, tu peux également lire la partie suivante concernant les .frag dans HeavyM. La seule différence est la partie sur les uniforms values, mais le principe du corps du code reste le même !

 

Créer ou convertir un .frag compatible avec HeavyM manuellement

Comme nous l’avons détaillé dans ce tutoriel, nous avons mis en place le format ISF à partir de la version 1.10 de HeavyM. Si tu utilises une version antérieure, tu ne peux utiliser que des shaders .frag et il faut de plus les « convertir » pour qu’ils soient compatibles avec HeavyM. Tu peux commencer par tester les shaders proposés par l’équipe, que tu peux utiliser directement dans HeavyM : 

TÉLÉCHARGER LES SHADERS

Pour utiliser d’autres shaders, il n’y a pas besoin de tout comprendre mais il est bien d’avoir quelques bases. Pour reprendre des spécifications indiquées dans une partie précédente, HeavyM supporte uniquement les fragment shaders et pour faire fonctionner ces programmes, il faut au minimum une carte graphique supportant une version OpenGL 2.0.

 

Ouput color

void main( void )
{
      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Il s’agit ici d’un très court code qui assigne à chaque pixel la couleur rouge. Tu peux déjà tester ce petit bout de code dans HeavyM. Copie ce texte dans un éditeur de texte et sauve-le avec l’extension .frag afin de pouvoir l’importer dans HeavyM.

En appuyant sur Play et en mode “active on top”, ton player se comportera comme une forme rouge.

 

 

Pour comprendre : chaque pixel passe dans ce petit bout de code. gl_FragColor est le nom que l’on donne à la couleur qu’on obtient. On lui assigne un vecteur correspondant à une couleur en format RGBA avec des valeurs entre 0 et 1 (ici R = 1, G = 0, B = 0, A = 1).

Tu peux maintenant essayer de modifier ces paramètres pour obtenir différentes couleurs avec différentes opacités en faisant varier les paramètres entre 0 et 1.

 

Position en entrée

Mais le but n’est pas de donner la même couleur à chaque pixel. On peut donc modifier cette couleur en fonction de la position du pixel. Cette position, on la récupère sous forme de vecteur 2D qu’on appelle gl_FragCoord, si l’on ne veut récupérer que le x (abscisse) ou le y (ordonnée) : gl_FragCoord.x et gl_FragCoord.y.

Un effet simple est de faire varier les composantes de la couleur de sortie en fonction de la position pour faire un dégradé. Par exemple :

void main( void )
{
      float red = gl_FragCoord.y / 1000.0;
      float blue = gl_FragCoord.x / 1000.0;
      gl_FragColor = vec4(red, 0.0, blue, 1.0);
}

Dans ce code, on déclare un nombre red égal à la coordonnée y du pixel divisé par 1000. De même pour le nombre blue égale à la coordonnée x du pixel divisé par 1000. On a ainsi, pour le pixel situé en (0,0), c’est à dire en haut à gauche, des valeurs de rouge et de bleu égales à 0, il sera donc noir. Alors que le pixel situé en (1280, 720) (pour une résolution de 720p), c’est à dire en bas à droite, a des valeurs de rouge et de bleu égales à 1 ou plus., il sera donc rose (rouge + bleu).

Ici, on divise par 1000 pour avoir une valeur contenue environ entre 0 et 1, mais dans la réalité, cela dépend de la résolution de ton shader.

 

Tu peux ensuite appliquer toutes sortes de transformations mathématiques sur tes couleurs pour obtenir les effets voulus. Pour cela, nous te conseillons de consulter des tutoriels sur les shaders qui t’expliqueront comment écrire ton code.

 

Uniform Values

Mais tout cela ne permet que d’avoir une image fixe. Dans un mapping, c’est quand même plus sympa d’avoir une image animée, il faut alors prendre en compte un facteur temps. Pour cela, on peut communiquer à un shader des valeurs qui lui seront communiquées à chaque frame : ces valeurs sont appelées Uniform values.

Dans HeavyM, nous avons décidé d’envoyer 6 valeurs :

  • HM_x, HM_y, HM_z et HM_speed: des nombres entiers entre 0 et 100 que tu peux modifier depuis l’interface du logiciel.
  • HM_resolution: un vecteur (x,y) correspondant à la résolution de ton shader.
  • HM_time: un nombre float correspondant au temps écoulé depuis l’ouverture de ta projection en seconde.

uniform float HM_x;
uniform float HM_y;
uniform float HM_z;
uniform float HM_speed;
uniform float HM_time;
uniform vec2 HM_resolution;

void main( void )
{
      float red = (gl_FragCoord.y / HM_resolution.y);
      float blue = (gl_FragCoord.x / HM_resolution.x);
      float green = (sin(HM_time) + 1.0) * 0.5;
      gl_FragColor = vec4(red, green, blue, 1.0);
}

En premier lieu, on déclare ces uniform values, pour dire au shader que l’on va les utiliser, comment elles s’appellent et ce qu’elles contiennent. On peut ensuite les utiliser dans le shader lui même.
Dans l’exemple au-dessus, la composante verte de la couleur est égale au sinus du temps (on a ainsi une valeur entre -1 et 1) auquel on ajoute 1 et qu’on multiplie par 0.5 pour obtenir une valeur entre 0 et 1 qui varie en fonction du temps.

 

 

En autre exemple, voici un code qui dessine un cercle qui change de couleur en fonction du temps.
Le rayon du cercle est dépendant de la variable HM_x que l’on peut modifier dans le logiciel.

uniform float HM_x;
uniform float HM_y;
uniform float HM_z;
uniform float HM_speed;
uniform float HM_time;
uniform vec2 HM_resolution;

void main(void)
{
         float x = (gl_FragCoord.x / HM_resolution.x) – 0.5;
         float y = (gl_FragCoord.y / HM_resolution.y) – 0.5;

         float rayon = HM_x / 100.0;

      float d = sqrt(x*x + y*y);
      float red;
      float mov = 0.5 * sin(HM_time);

      if( d < rayon)
      {
         red = 0.7 – 2.0 * d + mov;
      }
      else
      {
         red = 0.6 * d – mov;
      }
      gl_FragColor = vec4(red, 0.0, 0.4, 1.0);
}

 

 

Modifier un shader déjà existant

Si tu veux pouvoir utiliser des shaders trouvés sur internet, sur les sites tels que https://www.interactiveshaderformat.com/ ou http://glslsandbox.com/, il faut pouvoir comprendre un minimum le code de ces shaders.

Mais la principale chose à modifier dans ces shaders sont les Uniforms values. Celles-ci sont choisies par celui qui exécute le shader. Dans HeavyM, nous avons choisi d’en mettre 6 et de les appeler d’une certaine façon (voir plus haut). Tu dois donc adapter le shader pour prendre en compte ces uniform values et les appeler de la même façon.

Prenons un exemple: http://glslsandbox.com/e#40449.0.

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 resolution;

void main( void ) {

      vec2 position = ( gl_FragCoord.xy * 2.0 – resolution) / min(resolution.x, resolution.y);
      vec3 destColor = vec3(1.0, 0.0, 0.8 );
      float f = 0.0;

      for(float i = 0.0; i < 50.0; i++){

         float s = sin(time + i ) ;
         float c = cos(time + i );
         f += 0.003 / abs(length(8.0* position *f – vec2(c, s)) -0.4);
      }

      gl_FragColor = vec4(vec3(destColor * f), 1.0);
}

Dans ce code, glslsandbox appelle les uniform values time et resolution. Tu dois donc remplacer toutes les occurrences de time par HM_time et toutes les occurrences de resolution par HM_resolution.

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float HM_time;
uniform vec2 HM_resolution;

void main( void ) {

      vec2 position = ( gl_FragCoord.xy * 2.0 – HM_resolution) / min(HM_resolution.x, HM_resolution.y);
      vec3 destColor = vec3(1.0, 0.0, 0.8 );
      float f = 0.0;

      for(float i = 0.0; i < 50.0; i++){

         float s = sin(HM_time + i ) ;
         float c = cos(HM_time + i );
         f += 0.003 / abs(length(8.0* position *f – vec2(c, s)) -0.4);
      }

      gl_FragColor = vec4(vec3(destColor * f), 1.0);
}