La première étape dessine la
scène normalement, le cube gris ainsi que le carré vert
(cf. vignette ligne 2, colonne 1). Une deuxième étape
extrait de cette image la partie sur laquelle appliquer le flou : le
carré vert (cf. vignette ligne 1, colonne 1). Les étapes
suivantes réalisent le flou du carré vert et la
dernière étape combine la scène "normale" et la
version floue du carré vert.
Cet affichage est donc composé de 4 étapes :
- rendu de la scène complète, résultat buffer0
- extraction du carré vert, résultat buffer1 (source buffer0)
- filtrage (flou) du carré vert, résultat buffer2 (source buffer1)
- composition finale : résultat buffer normal (sources buffer0 et buffer2)
Chaque étape utilise les résultats de
l'étape précédente. Les sections suivantes
précisent comment créer de nouveaux buffers et comment réaliser chaque étape.
Partie 1 : rendu dans une texture
Pour réaliser toutes les étapes, il faudra prévoir 3 textures afin de
stocker les résultats des étapes 1, 2 et 3.
La section suivante explique comment créer
une texture "classique" et dessiner une scène dedans.
utilisation des render targets (frame buffer objects)
Les frame buffer objects permettent de créer des ensembles de
textures et de les faire remplir lors du rendu de la scène
à la place du buffer d'affichage de la fenêtre.
render_target.c (fourni avec sdlkit) crée
un buffer contenant deux textures : une couleur et une de profondeur.
exemples d'utilisation (pas d'ordre particulier) :
#include "render_target.h"
// avant toute utilisation
render_target_init();
// à la fin du programme
render_target_quit();
// creation d'un render target (frame buffer object) de dimensions largeur x hauteur
// contenant un buffer couleur et un buffer de profondeur
RENDER_TARGET *buffer= render_target_create(largeur, hauteur);
// creation d'un render target contenant uniquement un buffer couleur
// (ne permet pas de dessiner correctement des objets, mais permet de traiter tous les pixels d'un buffer)
RENDER_TARGET *buffer= render_target_create_format(largeur, hauteur, GL_TEXTURE_2D, GL_RGBA, 0);
// utilisation d'un render target pour afficher une scene : les rendu suivants rempliront 'buffer'
render_target_bind(buffer);
// afficher la scene dans buffer
display( );
// utilisation
d'un render target : retour à la normale : remplissage du buffer
d'affichage de la fenêtre
render_target_disable();
// afficher la scene dans la fenetre (dans le render
target par defaut, crée par opengl lors de la création de
la fenetre)
display( );
// active la texture couleur du buffer pour l'unite de texture 0
glActiveTexture(GL_TEXTURE0);
render_target_bind_texture(buffer);
// afficher la scène en utilisant le buffer couleur comme texture0
display( );
// idem, mais
utilise la texture de profondeur, active la texture de profondeur du
buffer pour l'unite de texture 1
glActiveTexture(GL_TEXTURE1); // on peut bien sur utiliser n'importe quelle unite de texture
render_target_bind_depth_texture(buffer);
// afficher la scene en utilisant texture1
display( );
// detruit le buffer
render_target_delete(buffer);
// recuperer les dimensions du buffer
int viewport[4];
render_target_get_viewport(buffer, viewport);
// c'est la même convention qu'openGL
// viewport[0] = xmin, viewport[1]= ymin
// viewport[2]= largeur, viewport[3]= hauteur
Les parties suivantes précisent comment réaliser chaque étape du rendu.
Partie 2 : extraction
Le plus simple est de sélectionner tous les
pixels dont le gris moyen est supérieur à un seuil
choisit par l'application, 160, par exemple.
rappel : gris moyen = (R + G + B) / 3
Q1. écrivez un shader qui
s'exécute
sur tous les pixels d'une texture et qui copie un pixel dans le buffer
résultat si son gris moyen est supérieur au seuil. Sinon,
le shader écrit un pixel noir dans le buffer résultat. Le
seuil sera un paramètre (de quel type ?) du shader.
Partie 3 : filtrage
Le plus simple est de calculer la couleur moyenne
des pixels d'un voisinage 3x3 autour de chaque pixel du buffer
d'entrée.
Q1. écrivez un shader qui s'exécute
sur tous les pixels d'une texture et écrit dans le buffer
résultat la moyenne des couleurs des pixels voisins.
Partie 4 : composition finale
Le plus simple est de calculer la couleur moyenne
des pixels des 2 buffers. Le shader aura donc 2 entrées et une
sortie.
Q1. écrivez un shader qui s'exécute
pour tous les pixels d'une texture et qui calcule la moyenne des pixels
correspondants dans les 2 buffers d'entrées.
Q2. amélioration : calculer la moyenne
assombrit les parties de l'image qui ne correspondent pas à
l'objet extrait lors de la première étape. Proposez une
solution à ce problème.