GeeXLab
Current version: 0.45.1
>GeeXLab homepage

FurMark
Current version: 1.30.0
>FurMark homepage

GPU Caps Viewer
Current version: 1.55.0.0
>GPU Caps Viewer homepage

GPU Shark
Current version: 0.26.0.0
>GPU Shark homepage


Blogs
>JeGX's HackLab

Geeks3D's Articles
>GPU Memory Speed Demystified

>Multi-Threading Programming Resources

>GeForce and Radeon OpenCL Overview

>How to Get your Multi-core CPU Busy at 100%

>How To Make a VGA Dummy Plug

>Night Vision Post Processing Filter

PhysX FluidMark
Current version: 1.5.4
>FluidMark homepage

TessMark
Current version: 0.3.0
>TessMark homepage

ShaderToyMark
Current version: 0.3.0
>ShaderToyMark homepage
>ShaderToyMark Scores

Demoniak3D
Current Version: 1.23.0
>Demoniak3D
>Download
>Libraries and Plugins
>Demos
>Online Help - Reference Guide
>Codes Samples
 
Introduction au GLSL
OpenGL Shading Language

Par Jérôme GUINOT aka 'JeGX' - The oZone3D Team
jegx [at] ozone3d [dot] net

Version initiale: 7 Octobre 2005
Mise à jour: 8 Novembre 2005


1 - Introduction

2 - Le "Hello World" du GLSL

3 - Downloads




1 - Introduction


Le GLSL, acronyme d'OpenGL Shading Language, fait partie, au même titre que le HLSL de Direct3D ou le Cg de nVidia, des langages de programmation des vertex et pixel processeurs de la carte graphique. Les vertex et pixel processeurs sont des unités de traitement, situés dans le GPU (Graphics Processing Unit), qui agissent respectivement sur les vertices et sur les pixels. Afin de ne pas dupliquer ce que j'ai déjà dit sur la présentation des shaders programmables, je vous renvoie à la partie 3 du tutoriel sur les cartes graphiques.

Pour aborder sérieusement la programmation des vertex et pixel shaders en GLSL, il est fortement conseillé de se munir de l'Orange Book, le livre de référence en matière de GLSL (de Randi Rost - ISBN: 0-321-19789-5):

GLSL - Orange book
Fig. 1 - Le livre de référence sur le langage GLSL

Nous allons, dans la suite de ce tutoriel, nous servir de la plateforme Demoniak3D pour intégrer et tester nos vertex et pixel shaders écrits en GLSL. Il vous faudra aussi une carte 3D supportant les shaders. Toutes les cartes nVidia Geforce FX 5200 et supérieures ou ATI Radeon 9600 et supérieures supportent le GLSL. Bien sûr, la dernière version des pilotes graphiques des constructeurs (Forceware pour nVidia et Catalyst pou ATI) doit être installée.

Petite mise en garde: la programmation des vertex et pixel shaders est globalement une programmation de bas niveau. Il y a donc très souvent, malheureusement, des comportements différents entre les différentes cartes 3D. L'idéal, pour coder en GLSL et s'assurer que son code fonctionnera partout, est d'avoir 2 machines avec dans l'une une carte nVidia Geforce et dans l'autre une ATI Radeon... ça promet!

Avant d'aller plus loin, clarifions le vocabulaire. Un vertex shader est une portion de code (un programme) qui va être compilé puis exécuté dans le vertex processeur. Idem pour le pixel shader. Un shader (aussi appelé shader program) est le terme général pour nommer l'ensemble formé par un vertex shader et un pixel shader. Dans la terminologie OpenGL, le vertex shader se nomme vertex program et le pixel shader se nomme fragment program. Dans la suite, j'utiliserai plus souvent vertex shader et pixel shader, qui sont d'après moi les termes les plus courants pour qualifier les shaders programs.

Les différents langages de shading (GLSL, Cg et HLSL) sont assez proches les uns des autres. Aussi, l'apprentissage de l'un permet de passer rapidement à l'autre. Pour ma part, je consulte souvent des sources en HLSL avant de les convertir/adapter à mes besoins en GLSL. Ceci étant dit, nous allons passer au codage de notre premier shader.




2 - Le 'Hello World' du GLSL


Pour notre premier shader, je vous propose quelque chose d'extrêmement simple. Le but recherché est de voir la structure d'un programme en GLSL et surtout de comprendre le fonctionnement de base d'un shader. Une fois cette étape passée, la porte vers le monde merveilleux des vertex et pixel shaders vous est ouverte!

Un shader program est composé de deux parties:
  • le code du vertex shader
  • le code du pixel shader

En fonction des plateformes de dévéloppement, ces 2 codes peuvent se trouver dans deux fichiers distincts, ou dans le même. Dans le cas de Demoniak3D, un shader program (vertex shader + pixel shader) est codé dans un seul fichier. Mais, à ce niveau , Demoniak3D offre une plus grande souplesse, puisque l'on peut directement coder notre shader dans le script XML, nous évitant ainsi la gestion d'un grand nombre de fichiers lors des projets volumineux.

La fonction de ce premier shader program est de colorier de manière uniforme un simple mesh plan composé de 4 vertices. La figure 2 montre le rendu que l'on va obtenir en appliquant ce shader au mesh.

GLSL
Fig. 2 - Le rendu de notre premier shader



Afin de comprendre la suite, je vous conseille de télécharger le projet d'accompagnement et de le charger dans Demoniak3D. Le téléchargement se situe en bas de cette page.

Avant d'entrer dans le détail du code du shader, il faut comprendre ce que appliquer un shader veut dire.

Tous les objets 3D dans Demoniak3D sont dotés d'au moins un matériau. Le matériau est fondamental puisqu'il intervient dans les calculs d'éclairage, peut posséder des textures et enfin, et c'est le plus important pour ce tutoriel, le matériau permet de faire la liaison entre un shader program et un objet 3D.

Donc, en un mot, pour qu'un shader program puisse agir sur un mesh, il faut affecter ce shader à l'un des matériaux qui composent le mesh. Dans notre cas, le mesh est composé d'un unique matériau (appelé plane_mat dans le script XML). L'affectation du shader au matériau se fait de la manière suivante:
<material name="plane_mat" shader_program_name="simple_color_shader"  />

où simple_color_shader est le nom de notre shader. On retrouvera ce nom dans le noeud shader_program. Ce noeud est le noeud central pour la création d'un shader program.


2.1 - Le vertex shader

Passons maintenant à l'analyse du vertex shader. Ce code est le suivant:
[Vertex_Shader]
void main(void)
{
	gl_Position = ftransform();
}

La première ligne, [Vertex_Shader], marque le debut du vertex shader. Attention: il n'y a aucun standard à ce niveau. Chaque environnement de développement 3D, chaque moteur 3D, a sa propre façon de marquer le début d'un vertex ou pixel shader. Le moteur oZone3D, qui est tapi dans l'ombre de Demoniak3D, a opté pour cette façon là qui semblait la plus simple, vu que le même fichier contient à la fois le code du vertex shader et celui du pixel shader.

La syntaxe GLSL s'inspire, comme beaucoup de langages actuels, du vénérable langage C. A ce titre, le point d'entrée du vertex shader est la fonction main(). C'est la première fonction qui sera exécutée, c'est aussi simple que ça. Le corps de la fonction main, situé entre les deux incolades, est réduit au strict minimum:
gl_Position = ftransform();

Cette ligne de code d'apparence anodine est pourtant fondamentale. En fait elle est d'ailleurs obligatoire et tous les vertex shaders doivent au minimum contenir cette fonctionnalité. Mais que fait-elle vraiment? Pour y repondre, il nous faut quelques informations complémentaires.

Un vertex shader traite un vertex à la fois. Donc s'il y a 10000 vertices dans notre mesh, le vertex processor va exécuter 10000 fois le vertex shader. Un vertex est composé de plusieurs attributs (vertex attrib): position, coordonnées de texture, normale et couleur pour les plus courants. L'attribut de position, ou simplement la position, est le plus important. Les coordonnées (x, y et z) de la position du vertex entrant sont celles qui ont été données par l'artiste 3D lors de la modélisation. La position du vertex est définie dans le repère local du mesh (ou repère objet).

On peut maintenant répondre à la question précédente: le but de ce vertex shader est de transformer la position du vertex du repère local vers le repère 2D de la caméra. C'est seulement sous cette forme que la position du vertex pourra être utilisée dans les étages suivants du pipeline 3D. De manière plus détaillée, le vertex shader va multiplier la position du vertex entrant par la matrice 4x4 model_view_projection. Cette matrice est la concaténation des trois matrices suivantes:
  • la matrice de transformation de l'objet
  • la matrice de transformation de la caméra
  • la matrice de projection de la caméra
Le code suivant est tout aussi valable:
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

Théoriquement, il est cencé faire la même chose. Mais il peut y avoir des artefacts de rendu dus aux différentes implémentations du standard OpenGL dans les cartes graphiques. La fonction ftransform() garantie que le rendu sera le même quelque soit l'implémetation OpenGL.

gl_Vertex est un mot-clé du langage GLS. Plus exactement c'est une des nombreuses variables prédéfinies dans GLSL, qui permet d'accéder directement aux différents attributs des vertices et pixels entrants. Il en est de même pour gl_Position. gl_Vertex représente la position du vertex entrant, tandis que gl_Position est celle du vertex sortant transformé.

Un vertex processor ne traite, comme je l'ai dit plus haut, que des vertices. Ceci est important à comprendre car même si un polygone est composé de 3 ou plus vertices, le vertex processeur n'en saura jamais rien. Il ignore même que le vertex entrant fait partie d'un polygone. Il est donc impossible pour le vertex shader d'effectuer des opérations comme le back-face culling car cette opération nécessite la connaissance de tous les vertices composants une face ou de la normale de cette face.

Nous verrons dans un prochain tutoriel, l'utilisation des autres attributs d'un vertex (normal, couleur, coordonnées de texture, ...).


2.2 - Le pixel shader

Attaquons maintenant l'analyse du pixel shader. Le code est le suivant:
[Pixel_Shader]
void main (void)
{
	gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
}

La structure du pixel shader est la même que celle du vertex shader. Le début du pixel shader est marqué par [Pixel_Shader] et le point d'entrée est défini par la fonction main(). Ce pixel shader ne fait qu'une chose: écrire le vecteur 4D <1.0, 0.0, 0.0, 1.0> dans la variable gl_FragColor.

gl_FragColor fait partie des variables prédéfinies du GLSL, tout comme gl_Vertex et gl_Position. Le seul but d'un pixel shader est de calculer la valeur qui sera écrite dans gl_FragColor. gl_FragColor représente la couleur finale du pixel dans le frame buffer. Mais attention: certains tests se situant après le pixel processeur, comme l'alpha-test, peuvent modifier cette affirmation. En effet, si le pixel sortant du pixel processeur ne passe pas le test alpha, il ne sera tout simplement pas écrit dans le frame buffer.

vec4 est un des nombreux types de données disponibles dans GLSL. vec4 représente un vecteur 4D. gl_FragColor n'est rien d'autre qu'un vecteur 4D qui contient les 4 composantes de couleur d'un pixel: Red, Green, Blue et Alpha. Pour accéder aux coordonnées du vecteur gl_FragColor, rien de plus simple comme le montre le bout de code suivant:
gl_FragColor.r = 1.0; 
gl_FragColor.g = 0.0; 
gl_FragColor.b = 0.0; 
gl_FragColor.a = 1.0;

Ce code a exactement le même effet que le code originel. Nous aurions aussi pu écrire la chose suivante:
vec4 final_color = vec4(1.0, 0.0, 0.0, 1.0); 
gl_FragColor.r = final_color.x; 
gl_FragColor.g = final_color.y; 
gl_FragColor.b = final_color.z;  
gl_FragColor.a = final_color.w; 

GLSL nous offre une grande liberté d'expression!

Que d'explications pour ce simple shader! Peut-être commencez-vous à comprendre le mythe qui dit que la programmation des shaders est complexe. Elle est complexe, c'est un fait. Mais elle nous oblige à véritablement comprendre ce qui se passe sous le capot de nos chères (et onéreuses!) cartes graphiques. C'est seulement à ce prix que vous pourrez concevoir des shaders évolués et laisser libre cours à votre imagination...

Voici, pour terminer, une liste de liens utiles:
  • 3DLabs Fixed Functionality Shader Tool: ce petit utilitaire développé par 3DLabs vous permettra de générer des vertex et pixel shaders GLSL qui reproduisent le fonctionnement des unités fixes de Transform & Lighting et de Texturing. Vraiment intéressant pour comprendre le pipeline 3D...
  • nVidia SDK: Ce SDK comporte des dizaines d'exemples sur la prog des shaders GLSL. A avoir dans sa trousse à outils de développeur 3D!
  • ATI SDK: Le SDK d'ATI est maintenant vraiment cool et bien présenté (genre nVidia!). Il y a un grand nombre de code sources et de bons whitepapers. A avoir également dans sa trousse à outils de développeur 3D!




3 - Downloads



Codes sources d'accompagnement
Mise à jour: 7 Octobre 2005




GeeXLab demos


GLSL - Mesh exploder


PhysX 3 cloth demo


Normal visualizer with GS


Compute Shaders test on Radeon


Raymarching in GLSL



Misc
>Texture DataPack #1
>Asus Silent Knight CPU Cooler
Page generated in 0.0020720958709717 seconds.