AccueilAccueil  FAQFAQ  RechercherRechercher  S'enregistrerS'enregistrer  MembresMembres  Connexion  

Partagez | 
 

 [Traduction] YYG Techblog - Vue d'ensemble des shaders

Voir le sujet précédent Voir le sujet suivant Aller en bas 
AuteurMessage
Invité
Invité



MessageSujet: [Traduction] YYG Techblog - Vue d'ensemble des shaders   Mer 5 Mar 2014 - 22:34

Salut, aujourd'hui j'ai décidé de traduire un article très sympa du blog YYG traitant le shaders et leurs fonctionnement dans GMS, pour ceux qui veulent lire l'article original, c'est par ici : http://yoyogames.com/tech_blog/20

En même temps je tiens a vous dire que c'est le tout premier article que j'ai traduit, si vous avez des critiques ou remarques concernant la qualité de rédaction ou la compréhension de certains passages, n'hésitez surtout pas à me le faire savoir, en même temps si vous connaissez d'autre articles qui vous intéresse et que vous voulez qu'ils soient traduits, envoyez moi un MP. Smile


GameMaker: Studio – Vue d'ensemble des shaders.

Avec l’arrivé proche de la version 1.2 de Studio, il était temps qu’on lève le rideau sur le fonctionnement des Shaders, ce qu’on peut faire avec, et la manière dont on va les utiliser dans Studio. Cependant, étant vu qu’il s’agit d’un sujet vaste, Je ferai en sorte de le décortiquer en plusieurs articles, dont le premier étant simplement un aperçu pour vous donner une idée de la manière dont vous allez les utiliser.

Il faut noter que, du fait que Studio est conçu pour le développement sur  plusieurs plateformes, nous avons choisi un langage de shaders qui sera indépendant de celles-ci : GLSL ES, ce qui signifie que vous allez écrire le shader qu’une seul fois, et ça va fonctionner dans n’importe quelle plateforme tant qu’il y a un support des shaders dans celle-ci.

Cependant il faut noter que GLSL ES a ses limitations, mais nous allons s’y pencher plus tard. Alors pour commencer on va parler brièvement de ce que c’est que les shaders, et de leurs fonctionnements.

Partie 1 - Vue d’ensemble des shaders.

Alors premièrement, qu’est-ce que c’est qu’exactement un shader ? Eh bien, quand on parle de shaders, on parle de deux différents types de programmes qui s’exécutent directement dans le processeur graphique, un vertex shader, et un fragment (ou pixel) shader. Ces deux microprogrammes fonctionnent ensembles afin de manipuler ce que la carte graphique affiche dans l’écran, vous permettant alors de changer, en temps réel, la position et la couleur (en valeurs RGBA) qui sont actuellement rendues dans le tampon d’affichage (display buffer).

Alors quel sorte d’effet pourrions nous produire avec les shaders ? Eh ben, en bref, presque tout :
Saturation de couleur, disons par exemple qu’un joueur tire une balle sur le méchant, on veut que celui "clignote" pour montrer que la cible a bien été touchée, pour l’instant tout ce qu’on peut faire c’est assombrir le sprite, et non l’éclairer.

C'est-à-dire c’est que si on règle la couleur de dessin à c_black, le sprite deviendra entièrement noir (comme un ombre), mais on peut pas le faire dans l’autre sens, au moins, pas très facilement. Certains développeurs ont trouvés des techniques en utilisant la fonction de brouillard (d3d_set_fog), mais ce n’est pas une solution pratique. Cependant, avec les shaders, cela devient beaucoup plus simple, étant vu que l’information de couleur est en cours d’écriture, vous pouvez simplement changer les valeurs à c_white ou n’importe qu’elle couleur tout en gardant la même valeur alpha (de transparence) afin de garder la forme du sprite intacte. Cela produit l’effet de flash voulu, et c’est le shader qui a permis de le faire.

Vous pouvez bien évidemment faire beaucoup plus, comme par exemple réaliser un effet de profondeur de champ, effet de "verre" ou réfraction d’eau, déplacement des coordonnées de couleurs HSV, ou même l’utilisation de plusieurs texture pour créer des effets telle que le normal mapping et ainsi de suite. Si vous pouvez l’imaginer, alors vous pouvez probablement le faire.

Dans le passé j’avais l’habitude de les utiliser pour faire des choses qui n’ont réellement pas grand-chose à voir avec les rendus. J’ai par exemple assigné à chaque objet une valeur et je les ai créé, un fois que tout l’affichage a été rendu, J’étais alors capable de « prendre » une couleur de l’écran, et de le passer de nouveau sur l’objet que j’ai cliqué dessus, pour les dizaines de milliers d’objet que j’ai choisi, c’était très pratique – et simple.
Tout cela est évidemment incroyablement puissant. Alors, qu’est-ce que Studio fait pendant le rendu ? Eh ben quand on affiche un QUAD (quadrilatère), c’est en réalité 2 triangles, chacun avec ses propres coordonnées de vertex, un vertex étant un point avec des valeurs de position, couleurs et coordonnées de texture que la carte graphique utilise pour le rendu.

Alors à quoi ressemble ces données ? Chaque point contient des coordonnées X, Y, Z (Z n’étant pas nécessaire pour la 2D), couleur et 0.0 à 1.0 pour les coordonnées de textures U et V, cela fait en sorte que chaque point ou vertex ressemble à ça :
Code:
X=10
Y=10
Z=1
Colour=$FFFFFFFF
U=0.0
V=1.0
Avant de commencer dans l’écriture des shaders, regardons comment nous allons créer et utiliser un shader dans Studio.



Les shaders ont été ajouté en tant que ressource standard, vous pouvez les éditer dans l’éditeur de scripts, avec un support total de syntaxe colorés, on a cependant modifié un peu l’éditeur pour permettre une création encore plus facile.
Comme vous voyez, il y a maintenant deux onglets dans l’éditeur de scripts, nommés Vertex et Fragment, vous écrivez à l’intérieur de chaque onglet le script approprié. Chaque ressource de shader est utilisé de la même manière qu’un script, c'est à dire que vous pouvez les utiliser avec les noms que vous leur avez assigné, Cela rend le processus d’écriture et d’intégration de shaders une partie naturelle de votre flux de travail.



Comme vous pouvez le voir dans l’image ci-dessus, Studio vous passera certaines choses, comme les matrices, les éclairages, et autres paramètres. Vous libérant ainsi de la nécessité de les mettre en place.
Alors, maintenant qu’on peut créer un shader, comment allions-nous l’utiliser dans Studio ? Il y deux aspects pour utiliser un shader, le premier étant le shader lui-même, et le deuxième est les deux constantes du shader (vertex et fragment).

Premièrement, mettre en place un shader est la simplicité même :
Code:
shader_set( MaskShader );

et ensuite pour arrêter de l’utiliser, tout simplement :
Code:
shader_reset();

Maintenant, alors que vous pouvez déjà faire des trucs géniaux juste avec ça, ce qui fait la puissance des shader, est le fait qu’on peut créer des constants dans le shader lui-même, pour obtenir une constante qui est à la fois visible dans le shader, GML et dans GLSL ES, vous devez utiliser le mot-clé UNIFORM. Vous pouvez alors passer certains éléments spécifique aux instances comme par exemple, une teinte de couleur, un index de réfraction, une valeur de fluorescence.

La première chose à faire cependant c’est de retourner le handle de chaque constante. Il y a 2 types de constantes ; Uniforms et Samplers. Uniforms sont les constantes standards ; ints, bools, floats, vectors, matrices et ainsi de suite, alors que les Samplers sont des textures. Contrairement à l’usage normal dans le GML, vous pouvez utiliser à un maximum de 8 textures simultanément, ou autant que la carte graphique est capable de supporter- Il peut être moins.

Dans l’exemple de masque ci-dessous nous avons besoin d’accéder à l’uniforme u_vMaskCol. Il s’agit d’un vecteur à 4 dimensions (ou vec4) que nous utilisons dans le fragment shader pour définir la couleur du masque utilisé quand le sprite est touché, ce qui nous permettra d’utiliser le clignotement (ou saturation) du sprite comme effet.
Code:
global.maskshader_col = shader_get_uniform( MaskShader, “u_MaskCol” );

Celle-ci va chercher la variable, et si il a trouve, il va assigner son handle à la variable globale maskshader_col. Vous pouvez alors utiliser cette variable à chaque fois que vous réglez la constante, ce qui ressemblera à ça…

Code:
shader_set( MaskShader );
shader_set_uniform_f( global.maskshader_col, Red, Green, Blue, AlphaMask );

Définissez d’abord le shader, qui prend alors le processus du rendu de studio et indique au système quel constantes de shader sont sur le point d’être réglés. Ces valeurs qui sont transmise sont en simples variables à virgules flottantes, leurs nature sont, bien sur, spécifiques à vos shaders.

Et c’est tout ! Studio va remplir toute la view/matrice de projections, définir la texture de base (nommée gm_BaseTexture) et ensuite appeler votre shader quand il affiche les sprites/tiles/arrière-plans et ainsi de suite.
Tout ce dont un fragment shader nécessite de votre part c’est de régler le gl_FragColor à la sortie, il va en suite retourner le vec4 à l’écran.

Pour l’utilisation normale, vous pouvez toujours utiliser des commandes comme draw_self(), draw_sprite_ext() et ainsi de suite, et Studio va créer les primitives, paramétrer les matrices et textures, vous laissant alors la simple tâche du dessin des pixels.

Et c’est tout pour la première partie. La deuxième partie concernera le fonctionnement technique de la création des shaders, et comment vous allez les utiliser.
Pour plus d'information, voici un peu de *ahem* lecture légère (en anglais) : http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
Revenir en haut Aller en bas
Invité
Invité



MessageSujet: Re: [Traduction] YYG Techblog - Vue d'ensemble des shaders   Jeu 6 Mar 2014 - 14:45

Partie 2

Dans la première partie, on s’est penché sur le concept général des shaders et leurs implémentation dans Studio, alors dans cette partie, nous allons créer un shader simple et voir comment nous allons les utiliser effectivement.

Tout d’abord, jetons un coup d’œil sur les variable basiques par défaut que Studio met en place, et les entrées (inputs) qu’il utilise, Si vous vous souvenez de la première partie, j’ai parlé des données de vertex et de quoi ils s’agissaient, alors dans cette première section nous allons voir comment ces données sont implémentés dans les shaders.

Code:
attribute vec3 in_Position;
attribute vec4 in_Colour;
attribute vec2 in_TextureCoord;
attribute vec3 in_Normal;

En ajoutant ces lignes au début de votre vertex shader permet de déclarer les entrée (ou inputs) dans le shader. Notons qu’un vec4 est un vecteur contenant 4 valeurs a virgule flottante dans une seule variable (in_Colour.argb par exemple), tandis qu’un vec3 contient 3 variables a virgule flottante (in_Position.xyz), et vec2, 2 flottantes (in_TextureCoord.xy). vec4 étant le plus large, (mis à part les tableaux), mais vous pouvez bien évidemment avoir une seul valeur flottante si vous voulez.

Ce sont les valeurs que votre shader doit travailler avec, et ils doivent être appelés en ordre afin de permettre a Studio de mapper certaines entrées correctement en multiplateforme. Ça  a également l’avantage d’être facilement compréhensible lorsqu’ils sont partagés entre les membres de la communauté.

Maintenant, tant que ceux-ci sont en haut, Studio va correspondre la position, la couleur, les coordonnées de texture et les normales comme voulu, mais si vous n’utilisez pas un (comme les normales par exemples), vous n’avez pas besoin de les inclure dans votre code.

Maintenant que nous avons déclarés les entrée du vertex shader, nous devons également déclarer les sorties – ce sont les valeurs transmises sur le fragment shader.

Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

Dans ce cas, notre vertex shader va envoyer une coordonnée de texture ainsi qu’une couleur au fragment shader, ces deux lignes seront également en tête de notre fragment shader.

Chaque shader doit avec une fonction main(), c’est le point d’entrée principal pour chaque vertex et fragment shader. Nos pouvons définir une fonction vide de cette façon…

Code:
void main()
{
}

Cette fonction bien sûr, ne fera grand-chose, et pourra même causer une erreur, car vous devez stocker à l’intérieur du vertex shader la sortie vers la variable GLSL intégrée gl_Position (voir http://www.khronos.org/opengles/sdk/docs/manglsl/ pour plus d'informations sur les variable intégrés). Alors jetons un coup d’œil sur à quoi un simple shader de type « pass-through» ressemblerait.

Code:
//
// Simple passthrough vertex shader
//
attribute vec3 in_Position;
attribute vec4 in_Colour;
attribute vec2 in_TextureCoord;

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 pos= vec4( in_Position, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * pos;
    
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}

Comme vous pouvez le voir, nous copions d’abord l’information de position dans une nouvelle variable pos. La raison pour cela c’est de pouvoir étirer la valeur afin qu’elle puisse complètement remplir un vec4. Une fois que nous avons converti la position en un format utilisable, nous multiplions ensuite par la matrice de projection view,  ce qui nous donne alors la position finale de l’espace du "clip" (la position que la carte graphique veut effectivement traiter). Studio fournit tout un tas de matrices prêtes à être utilisées, vous épargnant ainsi la tache des devoir les implémenter vous-même, ou les fournir a chaque shader que vous créez. Chacun de ces éléments peut être utilisé pour créer moult effets, mais si vous voulez tout simplement les transformer pour les afficher à l’écran, vous aurez probablement besoin d’utiliser la ligne ci-dessus.

Ces 2 dernière lignes sont simplement là où nous copions la couleur et les coordonnées de texture de l’entrée de donnée du vertex, prêts à être transférés vers le fragment shader.

Jetons maintenant un coup d’œil sur le fragment shader, puisqu’il s’agit d’un "pass through" shader, c’est incroyablement simple.

Code:
//
// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
}

Au sommet, nous avons nos deux entrées du pixel shader, et ceci est utilisés à côte d’une autre constante intégrée : gm_BaseTexture. Tous les sprites, arrière-plans, surfaces etc. Se trouvent tous sur des textures, ce qui fait qu’a chaque fois que vous dessinez quelque chose, vous spécifiez une texture (dans une forme ou figure ), et lorsque vous utilisez un shader, Studio affecte la véritable pour être la texture que vous dessiner avec. Ce qui vous facilite de nouveau la tache de la mise en place des shaders, et vous facilite largement le développement

Alors qu’est-ce que fait exactement cette ligne de shader ? Eh bien, la fonction texture2D() qui est une fonction shader de GLSL ES cherche un pixel  dans la texture en utilisant les coordonnées UV fournies,  Alors, il cherche dans la texture(votre sprite/arrière-plan/surface etc) en utilisant les coordonnées UV fournies à partir du sommet, et retourne ainsi le pixel ARGB, Il le multiplie ensuite avec la couleur du sommet – vous permettant de teinter le pixel avec une couleur. Ce pixel est ensuite passé a la variable intégré gl_FragColor pour être calculé dans la carte graphique.

Et c’est tout pour le fonctionnement des shaders ! Alors comment allez-vous les utiliser ? Eh bien, on ne peut faire plus simple...

Code:
shader_set(PassThroughShader);
draw_self();
shader_reset();

Si nous appelons notre shader « Pass Through », puis en réglant simplement le shader, affichant le sprite, et le réinitialiser, cela va tout passer à travers le shader, même si ça a la même apparence - pour le moment !


Voici maintenant la partie amusante. Puisque nous ne passons pas à travers un shader, voyons ce qui va se passer si nous stockons tout simplement une valeur à la place.

Code:
void main()
{
    gl_FragColor = vec4( 1,1,1,0.5 );
}

Si vous exécutez ce code, vous devez tout simplement obtenir un carré blanc à moitié transparent, (comme illustré ci-dessous)


Alors mélangeons un peu les choses… Les vecteurs sont  des petites choses sympas, des structures avec des composants x,y,z et w (ou r, g, b et a), et vous pouvez lire/écrire sur à partir de/vers comme bon vous semble. Dégageons les canaux bleu et vert de notre sprite, et voyons ce qui va se passer. Ajoutez cette ligne en bas du fragment shader original.

Code:
gl_FragColor.bg = vec2(0,0);

Ceci définit les canaux bleu et vert à zero, ne laissant ainsi que le canal rouge et le canal alpha.


Comme vous pouvez le voir, nous nous retrouvons avec une version rouge du sprite. si nous avons également défini le canal alpha à 0, nous obtiendrions la même image mais avec un carrée noir autour du sprite.

Code:
gl_FragColor.a = 0.0;



Dernière édition par sachem le Jeu 6 Mar 2014 - 15:44, édité 1 fois
Revenir en haut Aller en bas
 
[Traduction] YYG Techblog - Vue d'ensemble des shaders
Voir le sujet précédent Voir le sujet suivant Revenir en haut 
Page 1 sur 1

Permission de ce forum:Vous ne pouvez pas répondre aux sujets dans ce forum
Forum Le CBNA :: Développement :: Game Maker-
Sauter vers: