Lesson 4 : Post-Processing

Au cours de ce tutoriel vous découvrirez les post-traitements (ou post-fx) en OpenGL. Vous apprendrez à utiliser les FrameBuffer Objects pour appliquer à votre image plusieurs traitements successifs en implémentant un mécanisme de va-et-vient (ou ping-pong) sur les textures attachées aux framebuffers.

aiogl_codex.022

Pour commencer

Consultez cette page pour récupérer le code de base, ou partez du code écrit pour la leçon précédente.

Construisez la scène suivante.

1_1

Pour ce tutorial vous aurez besoin de rendre votre scène illuminée dans une texture qu’on appellera la passe de beauty, vous aurez aussi besoin de rendre votre scène dans une texture de profondeur qu’on appellera la passe de depth.

Si vous utilisez un forward shading, vous devez créer un framebuffer object et lui attacher deux textures, une texture de couleur et une texture de profondeur.

Si vous utilisez un deferred shading, vous avez de grande chances d’avoir déjà une texture de profondeur à disposition. Vous devez simplement modifier votre code pour que la passe d’illumination soit elle-aussi rendue dans un framebuffer auquel vous n’attacherez qu’une texture de couleur.

Pour créer et paramétrer un framebuffer object ainsi que les textures associées, référez-vous au tutorial 03.

Commencez par créer un framebuffer object dédié aux postfx. Ce fbo n’aura qu’un seul drawbuffer.

Créez ensuite quatre textures aux dimensions de la fenêtre.

Attachez la première de ces textures au framebuffer.

Comme d’habitude testez la complétion du framebuffer object et repassez sur le framebuffer par défaut.

Dans les morceaux de code suivants la texture contenant l’illumination sera nommée BEAUTY et la texture
contenant la profondeur de la scène sera nommée DEPTH.

Ajoutez un viewport de blit pour visualiser votre texture d’illumination et de profondeur si ce n’est pas déjà fait.

Gamma Correction

Le principe consiste à appliquer une correction sur la couleur d’une image à fin de tenir compte du rendu non-linéaire des couleurs qu’affiche un moniteur. Vous trouverez les explications détaillées ici wikipedia.org et ici geeks3d.com.

Créez un nouveau fragment shader contenant le code suivant. Vous pouvez réutiliser le vertex shader de blit.

Dans la boucle de rendu après le calcul de l’illumination mais avant l’affichage des viewports de debug et l’interface graphique. Dessinez un quad plein écran dans le framebuffer par défaut et appliquez y le shader que vous venez de créer.

Commencez par mettre le framebuffer par défaut dans les bons états. Veilliez à optimiser votre code, ne modifiez que les états qui le nécessitent.

Dessinez le quad avec le shader de gamma. Vérifiez que vous obtenez bien la bonne texture.

Modifiez le shader de gamma pour appliquer la formule suivante à la texture en entrée color^\frac{1}{\gamma} ave 0 < \gamma < 6. Passez gamma en uniform pour tester les différentes valeurs.

lowgamma

highgamma

Le postfx de correction gamma sera toujours le dernier de la chaine, il faudra donc changer la texture sur laquelle il s’applique à chaque postfx que vous intercalerez entre l’illumination et la correction gamma.

Sobel Operator

Le filtre de Sobel est un filtre basique de détection de contours. Vous trouverez les explications détaillées ici [Wikipedia].

Commencez par créer un nouveau fragment shader.

Ensuite vous devez de nouveau rendre un quad plein écran, cette fois ici avant le postfx gamma et dans le framebuffer de postfx.

Commencez par activer le framebuffer créé lors du premier exercice. Gardé le activé jusqu’à la correction gamma.

Attachez-y la texture dans laquelle vous souhaitez rendre la passe SOBEL qui sera l’une des textures du tableau fxTexture.

Effacez le contenu de la texture attachée au framebuffer.

Dessinez votre quad avec le shader que vous venez de créer en lui passant la texture BEAUTY. Vérifiez que vous obtenez la même image qu’avant et que le réglage du gamma fonctionne toujours.

Vous devez maintenant implémenter l’opérateur de Sobel dans votre shader. Commencez par rajouter dans le fragment shader les deux kernels utilisés par l’opérateur.

Il faut maintenant appliquer la convolution à chaque pixels et ses voisins. Documentez vous sur le fonctionnement de la fonction texelFetch.

Créez une matrice 3×3 contenant la norme des valeurs du pixel courant et de ses voisins.

Il faut maintenant calculer la convolution des deux kernels avec la matrice précédemment crée.

Affichez maintenant le résultat de la convolution

sobel

Modifiez le code pour mixer l’affichage de la texture en entrée et le résultat de l’opérateur Sobel selon un facteur passé en uniform.

sobelsub

Basic Depth of Field

Le flou de profondeur de champ consiste à simuler le fonctionnement d’une lentille. Implémentez cette technique avec quatre passes et trois shaders successifs, après l’opérateur de Sobel mais avant la correction gamma. Attention veillez à ne pas perdre le compte de la texture que vous lisez via glBindTexture et de la texture dans laquelle vous écrivez via glFramebufferTexture2D.

Blur

Flouter une image consiste à appliquer un kernel remplaçant la valeur du pixel par une moyenne locale de la valeur du pixel et de ses voisins. Appliquer un kernel 2D sur une image est sous-optimal sur un processeur doté d’un cache mémoire, on préfère souvent utiliser des filtres 2D séparables c’est à dire décomposables en deux filtres 1D.

Créez un nouveau shader en vous basant sur le fragment shader suivant.

Vous devez l’appliquer deux fois successivement en alternant les textures pour que le deuxième appel lise dans la texture modifiée par le premier.

Vérifiez que l’affichage ne change pas et que vous pouvez toujours régler l’opérateur de Sobel et la correction gamma.

Il faut maintenant modifier le shader pour qu’il puisse flouter verticalement ou horizontalement l’image. Ajoutez les deux uniforms suivants.

Calculez une moyenne avec un kernel 1D parametrable dans la direction passée en uniform.

Faites varier la direction entre les deux appels au shader et vérifiez vos resultats en faisant varier la taille du kernel.
smallblur

highblur

Circle of Confusion

Il faut maintenant calculer par pixel le coefficent de flou aussi appelé Circle of Confusion.

Commencez par ajouter un nouveau shader en se basant sur le fragment shader suivant.

Appliquez ce shader sur un quad en lui faisant lire la texture DEPTH.

Vérifiez le résultat en passant la texture COC à la suite de vos traitements ou en l’affichant via les viewports de debug.

Il faut maintenant modifier le shader pour qu’il calcule un coefficient de flou en se basant sur la profondeur en espace caméra. Rajoutez les uniforms suivants.

Reconstruisez la profondeur en espace caméra dans le shader.

L’uniform Focus est un vec3 contenant successivement les trois plans de near, focus, et far.
aiogl_schematics.001
shortfocal

Utilisez le code suivant pour implémenter le calcul.

longfocal

Depth of Field

Pour implémenter la passe finale de la technique il suffit de mixer la texture SOBEL et la texture HBLUR en utilisant la valeur stockée dans la passe COC.

Ajoutez un shader avec le fragment shader suivant.

Appliquez le sur un quad en lui faisant lire les textures SOBEL, HBLUR et COC.

Modifiez le shader pour implémenter un mix entre les textures de SOBEL et BLUR utilisant COC comme coefficient. Vérifiez que votre chaine de traitement fonctionne toujours.

doflight

final

Leave a Reply