Fonctions de mise en forme

Starter pack

La logique du shader est spéciale, elle est différente de celle à laquelle nous sommes habitués en JavaScript ou dans d'autres langages de programmation. Bien que la syntaxe soit similaire, la manière dont nous implémentons la logique est différente. C'est un peu comme une boîte noire, vous mettez des données et vous obtenez des couleurs pour le fragment shader ou des positions pour le vertex shader.

Mais comment contrĂ´lez-vous la sortie ? Comment le faire ressembler Ă  ce que vous voulez ? C'est lĂ  qu'interviennent les fonctions de mise en forme.

Nous nous concentrerons sur le fragment shader pour cette leçon, mais les mêmes principes s'appliquent au vertex shader.

Zone de pratique

Pour maîtriser l'art de la mise en forme, vous devrez pratiquer et expérimenter. Il faudra du temps pour s'habituer au fonctionnement du shader, mais une fois que vous en aurez pris l'habitude, vous pourrez créer des effets étonnants.

Parce que je veux vous mettre dans les meilleures conditions pour réussir, j'ai préparé cette scène de galerie d'art en 3D pour que vous puissiez visualiser vos shaders en temps réel dans un environnement agréable.

Sentez-vous votre créativité couler ? Tous ces cadres vides attendent vos chefs-d'œuvre !

Le modèle 3D utilisé est VR Gallery par Maxim Mavrichev et est sous licence Creative Commons Attribution.

J'ai utilisé <CameraControls /> pour créer une caméra à la première personne pour naviguer dans la galerie et Squoosh pour réduire la taille des textures.

SimpleShaderMaterial

Tous les cadres de la galerie sont des copies du SimpleShaderMaterial, c'est un shader custom basique que j'ai préparé pour vous avec :

  • uColor : une couleur
  • uTime : le temps Ă©coulĂ© depuis le dĂ©but de l'application
  • vUv : les coordonnĂ©es UV du fragment (de 0 Ă  1 sur les deux axes)

Ils sont tous étendus dans le <App.jsx /> pour pouvoir les utiliser de manière déclarative dans notre scène.

Ils sont nommés en fonction de leur position dans la galerie, mais n'hésitez pas à les renommer en quelque chose de plus significatif une fois que vous aurez créé des chefs-d'œuvre avec eux !

Fonctions

Pour chaque fragment de notre shader, notre même code sera exécuté avec des entrées différentes.

Si nous voulons dessiner une ligne, nous pourrions utiliser des instructions if pour vérifier si le pixel est à l'intérieur de la ligne ou non. Mais faire des formes plus complexes serait très difficile et inefficace.

Au lieu de cela, nous utilisons des fonctions pour façonner notre sortie. Ne vous inquiétez pas, vous n'avez pas besoin d'être un expert en mathématiques pour les utiliser. Vous avez seulement besoin de comprendre quelles fonctions sont à votre disposition, et ce qu'elles font.

Pensez à une fonction comme à une machine qui prend en entrée et vous donne une sortie. Par exemple, la fonction f(x) = x * 2 prend un nombre x et vous donne x * 2 comme résultat.

Pour visualiser l'effet des différentes fonctions, nous utiliserons Graphtoy, c'est un outil simple pour taper des fonctions et voir leur sortie. Cela aide à valider notre compréhension des fonctions lorsque nous les expérimentons dans nos shaders.

Visualisons notre fonction f(x) = x * 2 dans Graphtoy :

Graphtoy

Graphtoy deviendra rapidement votre meilleur ami lorsque vous expérimentez avec des shaders.

Il est temps d'expérimenter avec les différentes fonctions à notre disposition.

Step

La fonction step est une fonction simple qui renvoie 0 si l'entrée est inférieure à un seuil, et 1 si l'entrée est supérieure au seuil.

Elle prend deux paramètres :

  • edge : le seuil
  • x : la valeur d'entrĂ©e

Essayons-la sur le shader de fragment du cadre avant ArtFront02Material.jsx :

void main() {
  float pct = 1.0;
  pct = step(0.5, vUv.x);
  vec3 finalColor = pct * uColor;
  gl_FragColor = vec4(finalColor, 1.0);
}

Nous déclarons une variable pct pour déterminer le pourcentage de la couleur que nous voulons afficher. Nous la définissons à 1.0 par défaut, puis nous utilisons la fonction step pour la définir à 0.0 si le vUv.x est inférieur à 0.5.

Représentation de la fonction Step

On peut voir que la moitié gauche du cadre est noire, et la moitié droite est la couleur définie dans l'uniforme uColor.

Appliquons-la à l'axe vertical avec un seuil différent :

void main() {
  float pct = 1.0;
  pct = step(0.2, vUv.y);
  vec3 finalColor = pct * uColor;
  gl_FragColor = vec4(finalColor, 1.0);
}

Représentation verticale de la fonction Step

On peut voir que 20 % du bas du cadre est noir, et le reste est violet.

Les coordonnées UV ont leur origine dans le coin inférieur gauche du cadre, donc [0, 0] est le coin inférieur gauche, et [1, 1] est le coin supérieur droit.

Si vous voulez inverser l'effet, vous pouvez simplement échanger les paramètres de la fonction step :

void main() {
  float pct = 1.0;
  pct = step(vUv.y, 0.2);
  vec3 finalColor = pct * uColor;
  gl_FragColor = vec4(finalColor, 1.0);
}

Représentation verticale renversée de la fonction Step

Nous avons maintenant l'effet opposé.

Mix

La fonction mix est une fonction simple qui renvoie une interpolation linéaire entre deux valeurs.

Elle prend trois paramètres :

  • x: la première valeur
  • y: la seconde valeur
  • a: la valeur Ă  interpoler entre x et y

Essayons-la :

void main() {
  float pct = 1.0;
  pct = mix(0.0, 1.0, vUv.x);
  vec3 finalColor = pct * uColor;
  gl_FragColor = vec4(finalColor, 1.0);
}

Représentation de la fonction Mix

Nous pouvons voir un joli dégradé de noir à violet.

Comme beaucoup d'autres fonctions, vous pouvez l'utiliser sur d'autres types de données, comme les composants de vecteur. Utilisons-la pour créer un dégradé de blanc à violet sur l'axe vertical :

void main() {
  vec3 whiteColor = vec3(1.0);
  vec3 finalColor = mix(whiteColor, uColor, vUv.y);
  gl_FragColor = vec4(finalColor, 1.0);
}

Fonction Mix avec deux couleurs

Nous pouvons voir un joli dégradé de blanc à violet.

Changeons la valeur d'interpolation en appelant la fonction mix une première fois pour obtenir la valeur pct, puis utilisons-la pour interpoler entre whiteColor et uColor :

void main() {
  vec3 whiteColor = vec3(1.0);
  float pct = mix(0.0, 0.3, vUv.y);
  vec3 finalColor = mix(whiteColor, uColor, pct);
  gl_FragColor = vec4(finalColor, 1.0);
}

Fonction Mix avec deux couleurs et pct

Le violet est très clair car la valeur maximale de pct est 0.3.

Utilisez Graphtoy pour expérimenter avec la fonction mix et comprendre son fonctionnement.

Graphtoy fonction mix

3 interpolations différentes avec la fonction mix donnent des résultats complètement différents.

Smoothstep

La fonction smoothstep est une fonction simple qui retourne une interpolation lisse entre deux valeurs.

Elle prend trois paramètres :

  • edge0 : la bordure infĂ©rieure
  • edge1 : la bordure supĂ©rieure
  • x : la valeur Ă  interpoler entre edge0 et edge1

Elle donne trois résultats différents :

  • 0.0 si x est infĂ©rieur Ă  edge0
  • 1.0 si x est supĂ©rieur Ă  edge1
  • une interpolation lisse entre 0.0 et 1.0 si x est entre edge0 et edge1

Utilisons-la pour changer notre valeur pct :

void main() {
  vec3 whiteColor = vec3(1.0);
  float pct = smoothstep(0.4, 0.6, vUv.y);
  vec3 finalColor = mix(whiteColor, uColor, pct);
  gl_FragColor = vec4(finalColor, 1.0);
}

Smoothstep function representation

La transition se fait maintenant seulement entre 0.4 et 0.6. Tout ce qui est en dessous est blanc, et tout ce qui est au-dessus est violet.

Min & Max

min et max sont des fonctions simples qui renvoient la valeur minimale ou maximale entre deux entrées. Elles fonctionnent exactement comme les fonctions Math.min et Math.max en JavaScript.

Utilisons-les pour affiner notre valeur pct. D'abord, assurons-nous qu'elle ne soit jamais en dessous de 0.4 (ce qui signifie jamais totalement blanc):

void main() {
  vec3 whiteColor = vec3(1.0);
  float pct = smoothstep(0.4, 0.6, vUv.y);
  pct = max(pct, 0.4);
  vec3 finalColor = mix(whiteColor, uColor, pct);
  gl_FragColor = vec4(finalColor, 1.0);
}

Et jamais au-dessus de 0.6 (ce qui signifie jamais totalement violet):

void main() {
  vec3 whiteColor = vec3(1.0);
  float pct = smoothstep(0.4, 0.6, vUv.y);
  pct = max(pct, 0.4);
  pct = min(pct, 0.6);
  vec3 finalColor = mix(whiteColor, uColor, pct);
  gl_FragColor = vec4(finalColor, 1.0);
}

Min & Max function representation

Les couleurs sont délavées, et la transition est très douce.

Visualisons-le sur Graphtoy :

Max graph

Représentation de max(x, 0.4)

Min graph

Représentation de min(x, 0.6)

Et si nous les combinons :

Min & Max graph

Vous pouvez voir que nos valeurs ne descendent jamais en dessous de 0.4 et ne montent jamais au-dessus de 0.6.

Notre combinaison des fonctions min et max peut être remplacée par la fonction clamp, qui est une abréviation de min(max(x, min), max).

Opérations & motifs

Avant de découvrir de nombreuses autres fonctions utiles, voyons comment nous pouvons utiliser les opérations pour créer des motifs.

End of lesson preview

To get access to the entire lesson, you need to purchase the course.