Votre premier shader 2D

Introduction

Les shaders sont des programmes spéciaux qui s'exécutent sur le GPU et sont utilisés pour le rendu graphique. Tous les rendus modernes sont effectués avec des shaders. Pour une description plus détaillée de ce que sont les shaders, veuillez consulter Que sont les shaders.

Ce tutoriel se concentre sur les aspects pratiques de l'écriture de programmes de shaders en vous guidant à travers le processus d'écriture d'un shader et ses fonctions de vertex et de fragment. Ce tutoriel s'adresse aux débutants absolus en matière de shaders.

Note

Si vous avez de l'expérience dans l'écriture de shaders et que vous cherchez simplement un aperçu du fonctionnement des shaders dans Godot, consultez Shading Reference.

Configuration

Les shaders CanvasItem sont utilisés pour dessiner tous les objets 2D dans Godot, tandis que les shaders Spatial sont utilisés pour dessiner tous les objets 3D.

Pour pouvoir utiliser un shader, il doit être rattaché à un Material qui lui doit être associé à un objet. Les matériaux sont de type Resource. Pour dessiner plusieurs objets avec le même matériau, le materiau doit être associé à chaque objet.

Tous les objets dérivés d'un CanvasItem ont une propriété Matériau. Cela inclut tous les éléments GUISprite2DsTileMapsLayersMeshInstance2Ds etc. Ils ont également la possibilité d'hériter du matériau de leurs parents. Cela peut être utile si vous avez un grand nombre de nœuds pour lesquels vous souhaitez utiliser le même matériau.

To begin, create a Sprite2D node. You can use any CanvasItem, so long as it is drawing to the canvas, so for this tutorial we will use a Sprite2D, as it is the easiest CanvasItem to start drawing with.

In the Inspector, click beside "Texture" where it says "[empty]" and select "Load", then select "icon.svg". For new projects, this is the Godot icon. You should now see the icon in the viewport.

Ensuite, regardez dans l'inspecteur, sous la section CanvasItem, cliquez à côté de "Material" et sélectionnez "New ShaderMaterial". Cela crée une nouvelle ressource matérielle. Cliquez sur la sphère qui apparaît. Actuellement, Godot ne sait pas si vous écrivez un CanvasItem Shader ou un Spatial Shader et il prédit la sortie de shaders spatiaux. Ce que vous voyez est donc la sortie du Spatial Shader par défaut.

Note

Materials that inherit from the Material resource, such as StandardMaterial3D and ParticleProcessMaterial, can be converted to a ShaderMaterial and their existing properties will be converted to an accompanying text shader. To do so, right-click on the material in the FileSystem dock and choose Convert to ShaderMaterial. You can also do so by right-clicking on any property holding a reference to the material in the inspector.

Click beside "Shader" and select "New Shader". Finally, click on the shader you just created and the shader editor will open. You are now ready to begin writing your first shader.

Votre premier shader de CanvasItem

Dans Godot, tous les shaders commencent par une ligne précisant de quel type de shader il s'agit. Il utilise le format suivant :

shader_type canvas_item;

Comme nous écrivons un shader CanvasItem, nous spécifions canvas_item à la première ligne. Tout notre code sera sous cette déclaration.

Cette ligne indique au moteur quelles variables et fonctionnalités intégrées doivent vous être fournies.

Dans Godot, vous pouvez passer outre trois fonctions pour contrôler le fonctionnement du shader : vertex, fragment, et light. Ce tutoriel vous guidera dans l'écriture d'un shader avec les fonctions vertex et fragment. Les fonctions lumières sont beaucoup plus complexes que les fonctions vertex et fragments et ne seront donc pas traitées ici.

Votre première fonction fragment

La fonction fragment s'exécute pour chaque pixel d'un Sprite2D et détermine la couleur de ce pixel.

Ils sont limités aux pixels couverts par le Sprite2D, ce qui signifie que vous ne pouvez pas en utiliser un pour, par exemple, créer un contour autour d'un Sprite2D.

La fonction fragment la plus élémentaire ne fait rien d'autre qu'attribuer une seule couleur à chaque pixel.

We do so by writing a vec4 to the built-in variable COLOR. vec4 is shorthand for constructing a vector with 4 numbers. For more information about vectors see the Vector math tutorial. COLOR is both an input variable to the fragment function and the final output from it.

void fragment(){
  COLOR = vec4(0.4, 0.6, 0.9, 1.0);
}
../../../_images/blue-box.png

Félicitations ! Vous avez fini. Vous avez réussi à écrire votre premier shader dans Godot.

Maintenant, rendons les choses plus complexes.

Il existe de nombreuses entrées pour la fonction fragment que vous pouvez utiliser pour calculer COLOR. UV est l'un d'entre eux. Les coordonnées UV sont spécifiées dans votre Sprite2D (sans que vous le sachiez !) et elles indiquent au shader où lire les textures pour chaque partie du maillage.

Dans la fonction de fragment, vous ne pouvez lire qu'à partir de UV, mais vous pouvez l'utiliser dans d'autres fonctions ou pour attribuer des valeurs à COLOR directement.

Le UV varie entre 0-1 de gauche à droite et de haut en bas.

../../../_images/iconuv.png
void fragment() {
  COLOR = vec4(UV, 0.5, 1.0);
}
../../../_images/UV.png

Utilisation de TEXTURE intégrée

The default fragment function reads from the set Sprite2D texture and displays it.

Lorsque vous voulez ajuster une couleur dans un Sprite2D, vous ne pouvez pas simplement ajuster la couleur à partir de la texture manuellement comme dans le code ci-dessous.

void fragment(){
  // This shader will result in a blue-tinted icon
  COLOR.b = 1.0;
}

Certain nodes, like Sprite2Ds, have a dedicated texture variable that can be accessed in the shader using TEXTURE. If you want to use the Sprite2D texture to combine with other colors, you can use the UV with the texture function to access this variable. Use them to redraw the Sprite2D with the texture.

void fragment(){
  COLOR = texture(TEXTURE, UV); // Read from texture again.
  COLOR.b = 1.0; //set blue channel to 1.0
}
../../../_images/blue-tex.png

Entrée uniforme

Une entrée uniforme est utilisée pour faire passer les données dans un shader qui sera le même dans tout le shader.

Vous pouvez utiliser des variables uniformes en les définissant en haut de votre shader de cette manière :

uniform float size;

Pour plus d'informations sur l'utilisation, voir le document Shading Language doc.

Ajoutez une variable uniforme pour changer l'intensité du bleu dans notre Sprite2D.

uniform float blue = 1.0; // you can assign a default value to uniforms

void fragment(){
  COLOR = texture(TEXTURE, UV); // Read from texture
  COLOR.b = blue;
}

Vous pouvez maintenant modifier la quantité de bleu dans le Sprite2D à partir de l'éditeur. Retournez voir l'inspecteur sous l'endroit où vous avez créé votre shader. Vous devriez voir une section intitulée "Shader Param". Dépliez cette section et vous verrez la variable uniform que vous venez de déclarer. Si vous modifiez la valeur dans l'éditeur, elle écrasera la valeur par défaut que vous avez fournie dans le shader.

Interagir avec les shaders à partir du code

Vous pouvez changer les variables uniformes du code en utilisant la fonction set_shader_param() qui est appelée sur la ressource matérielle du nœud. Avec un nœud Sprite2D, le code suivant peut être utilisé pour définir la variable uniforme blue.

var blue_value = 1.0
material.set_shader_parameter("blue", blue_value)

Notez que le nom de la variable uniforme est une chaîne de caractères. La chaîne doit correspondre exactement à la façon dont elle est écrite dans le shader, y compris l'orthographe et la casse.

Votre première fonction vertex

Maintenant que nous avons une fonction fragment, écrivons une fonction vertex.

Utilisez la fonction vertex pour calculer où chaque vertex devrait se trouver à l'écran.

La variable la plus importante dans la fonction de sommet est VERTEX. Au départ, il spécifie les coordonnées des sommets dans votre modèle, mais vous y écrivez également pour déterminer où dessiner réellement ces sommets. VERTEX est un vec2 qui est initialement présenté dans l'espace local (c'est-à-dire non relatif à la caméra, viewport ou aux nœuds parents).

Vous pouvez décaler les sommets en ajoutant directement à VERTEX.

void vertex() {
  VERTEX += vec2(10.0, 0.0);
}

Combined with the TIME built-in variable, this can be used for basic animation.

void vertex() {
  // Animate Sprite2D moving in big circle around its location
  VERTEX += vec2(cos(TIME)*100.0, sin(TIME)*100.0);
}

Conclusion

Au fond, les shaders font ce que vous avez vu jusqu'à présent, ils calculent VERTEX et COLOR. C'est à vous d'imaginer des stratégies mathématiques plus complexes pour attribuer des valeurs à ces variables.

Pour vous inspirer, jetez un coup d'œil à certains des tutoriels de shaders les plus avancés, et consultez d'autres sites comme Shadertoy et The Book of Shaders.