Attention, ce tutoriel concerne des fonctionnalités uniquement disponibles en Trial et Live. Utilisateurs Start, upgrade now !       

 

Pas-à-pas

Ajouter un shader dans HeavyM

TÉLÉCHARGER LES SHADERS

 

Pour ajouter un shader dans HeavyM, il faut ajouter un player en faisant un drag and drop depuis l’icône correspondant au player dans la barre d’outils. Une forme rectangulaire délimitant ton player apparaît dans ton plan de travail. Et un panneau de paramètres apparaît sur la gauche.

 

 

Tu peux ouvrir ce panneau à tout moment en sélectionnant ton player et le laisser affiché en cliquant sur l’icône en forme de punaise. Pour en savoir plus sur le fontionnement des players en général, tu peux consulter notre tuto sur le sujet.

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

 

Tu peux ensuite choisir ton shader en appuyant sur l’icône+. Cela te permet d’accéder au fichiers disponibles sur ton ordinateur et chercher ton fragment shader. Il doit s’agir d’un fichier avec l’extension . frag.

 

Comprendre le fonctionnement des shaders

Qu’est-ce qu’un shader ?

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, voici un tutoriel complet et bien fait : https://openclassrooms.com/courses/les-shaders-en-glsl.

Pour les utiliser dans HeavyM, il n’y a pas besoin de tout comprendre mais il est bien d’avoir quelques bases. Dans HeavyM, on utilise uniquement 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.

 

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);
}