Buffer stencil - TPs Web réalisés par jean

Transcription

Buffer stencil - TPs Web réalisés par jean
ENSICAEN
2007
TP3-OpenGl
Buffer stencil
Ce buffer ressemble au buffer de profondeur (le Z-buffer). C’est une zone mémoire, qui contient une donnée par pixel, appelée la valeur stencil du pixel.
Cette donnée est un entier court non signé. Nous supposons dans la suite que
sa taille est de 8 bits par pixel.
Rappelons le fonctionnement des tests de profondeur : avec ce mécanisme, la
valeur d’un pixel qui normalement est une couleur devient un couple (c, d) où
c est une couleur et d un réel dit la profondeur du pixel. Chaque pixel a une
valeur courante (c, d). La couleur c est stockée dans le tampon des couleurs et
d se trouve dans le Z-buffer.
Lorsqu’on calcule une nouvelle valeur (c′ , d′ ) pour un pixel, on compare d à d′
(test de profondeur). Suivant le résultat, soit on remplace la valeur courante du
pixel par sa nouvelle valeur (c′ , d′ ), soit on conserve l’ancienne valeur.
En introduisant le stencil, on ajoute aux données du pixel une donnée supplémentaire dite valeur stencil du pixel. La valeur stencil courante d’un pixel se
trouve dans le tampon stencil. Il existe aussi un test stencil : il consiste à comparer une valeur stencil à une valeur de référence. Si le test échoue, le buffer de
couleur et le Z-buffer resteront inchangés. S’il réussit, ces deux buffers peuvent
être l’objet d’une mise à jour, suivant les méthodes habituelles. Dans tous les
cas, on peut demander la modification du stencil suivant une méthode prédéfinie, parmi 6 méthodes proposées.
Nous verrons dans ce TP les applications de ce mécanisme. Sans plus tarder,
nous allons voir les étapes nécessaires à l’utilisation de ce buffer.
a. Déclaration. Nécessaire à la réservation des ressources appropriées.
glutInitDisplayMode(GLUT_STENCIL)
b. Initialisation. Elle se fait par :
glClear(GL_STENCIL_BUFFER_BIT)
La valeur d’initialisation par défaut est 0, mais on peut spécifier toute valeur
entre 0 et 255 par la fonction glClearStencil Par exemple :
1
glClearStencil(127)
c. Activation et désactivation. L’activation est nécessaire à la prise en
compte des tests stencil.
glEnable(GL_STENCIL_TEST) et glDisable(GL_STENCIL_TEST)
Ajoutons que le test stencil est effectué avant le test de profondeur.
d. Fonction de comparaison et valeur de référence.
glStencilFunc(GLenum func, GLint ref, GLunit mask)
Cette fonction qui prend trois arguments, définit la fonction de comparaison
(func), la valeur de référence (ref) et le masque (mask) à utiliser durant le test
stencil. La valeur de référence est comparée à la valeur se trouvant dans le tampon stencil via la fonction de comparaison. La comparaison porte uniquement
sur les bits positionnés à 1 dans mask, ce qui signifie que les deux valeurs à comparer subissent un ET logique avec la valeur du masque, avant la comparaison.
L’argument func est à choisir parmi les 8 fonctions prédéfinies :
GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL,
GL_GREATER, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER
Si par exemple la valeur spécifiée est GL_LESS, le test réussit, si et seulement si,
la valeur de référence est strictement inférieure à celle se trouvant dans le tampon. Avec GL_ALWAYS le test stencil réussit toujours et avec GL_NEVER il échoue
en toute circonstance.
Par défaut, func=GL_ALWAYS, ref=0, mask=255 et le test est désactivé.
e. Modification du tampon stencil en fonction du résultat d’un test.
glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
Terminologie : Un test stencil réussi est un stencilpass. Lorsqu’il échoue on
aura un stencilfail. La réussite et l’échec d’un test de profondeur seront désignées par zpass et zfail.
Le test stencil produit trois situations différentes :
(1) le test stencil échoue (stencilfail),
(2) le test réussit mais le test de profondeur échoue (stencilpass + zfail),
(3) les deux tests réussissent (stencilpass+zpass).
Les arguments de la fonction glStencilOp indiquent (dans l’ordre cité) les opérations à effectuer dans chaque cas. On peut les choisir dans la liste ci-dessous :
– GL_KEEP : conserver la valeur existante du stencil,
– GL_ZERO : la remplacer par 0,
2
–
–
–
–
GL_REPLACE : la remplacer par la valeur de référence,
GL_INCR : l’incrémenter (sans dépasser la valeur maximale),
GL_DECR : la décrémenter (sans dépasser la valeur minimale),
GL_INVERT : inverser l’ordre des bits.
Ajoutons enfin, que dans le cas d’un stencilfail le buffer des couleurs et le
Z-buffer restent inchangés. On peut contrôler le rendu par ce biais.
f. Masque d’écriture
glStencilMask(GLuint mask)
Cette fonction contrôle l’écriture dans le tampon stencil : la valeur à écrire subira un ET logique avec la valeur placée dans l’argument mask et le résultat sera
placé dans le tampon. Remarquons que le masquage se produit après les tests.
Attention. Le masquage à l’écriture s’applique aussi à l’initialisation par glClear.
Exercice 1. Nous voulons visualiser une scène où l’on voit le reflet d’un objet dans un plan (par exemple dans un miroir). Il suffit pour cela, de réaliser
une symétrie de la scène par rapport au plan du miroir. La symétrie concerne
uniquement les objets dont on veut voir la réflexion dans le miroir.
Nous réaliserons cet exercice sans l’utilisation de stencil buffer. Nous corrigerons
les imperfections de notre réalisation en utilisant le buffer stencil.
Le miroir est un cube aplati qui se trouve dans le plan xoy, collé à un mur,
ce qui simplifie le problème (aucun objet ne pourra être caché par le miroir).
L’objet “bague” est formé d’un tore et d’une sphère rencontrant le tore. Il se
trouve dans le premier octant. La scène comprend une source lumineuse. Nous
utiliserons le mécanisme de “ColorMaterial” pour définir la couleur des objets.
Complétez la maquette tp3_exo1 :
– Ecrivez la fonction draw_ring qui place l’objet “bague”, en mouvement,dans
le premier octant.
– Ecrivez la fonction draw_mirror qui dessine le miroir comme indiqué.
– Ecrivez la fonction draw_wall (un quadrilatère, assez grand),
– Ecrivez la fonction reflection qui place un objet symétrique de la bague
par rapport au plan xoy. On pourra procéder de la manière suivante (expliquez la raison d’être de chaque instruction) :
glEnable(GL_CULL_FACE);
glPushMatrix();
glScalef(1,1,-1); //symétrie par rapport au plan xoy
glCullFace(GL_FRONT);
draw_ring();
glCullFace(GL_BACK);
glPopMatrix();
3
– Faites le nécessaire pour qu’on puisse déplacer le miroir dans le plan xoy,
à l’aide des touches du clavier.
– Dans la fonction display, dessiner d’abord le mur et le miroir, en masquant
(par glDepthMask(GL_FALSE)) l’écriture dans le Z-buffer (pourquoi cette
opération ?).
– Visualisez ensuite l’objet et puis son reflet.
– Déplacez le miroir et remarquez que le reflet de la bague peut se trouver
en dehors du surface du miroir.
Exercice 2. On veut maintenant réaliser la même scène, mais en s’assurant
que le reflet d’un objet ne pourra jamais sortir de la surface du miroir. On procédera de la manière suivante (expliquez la raison d’être des instructions) :
– Dans le programme principal :
glutInitDisplayMode(GLUT_RGB|...|GLUT_STENCIL) ;
– Dans la fonction display, initialisez le stencil à 0.
– Dessinez le miroir, en interdisant l’écriture dans le Z-buffer.
– Rétablissez l’écriture dans le Z-buffer et dessinez le reflet de la bague.
– On veut maintenant positionner à 1, toutes les valeurs stencil des pixels
se trouvant sur le miroir (mais sans dessiner le miroir dans le buffer des
couleurs). On exécute les instructions suivantes (dire pourquoi) :
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xff);
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
draw_mirror();
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
– Dessinez le mur, en faisant échouer le test stencil, pour chaque pixel du
miroir.
– Dessiner l’anneau, en désactivant le test de stencil.
Déplacez maintenant le miroir et remarquez la disparition du reflet, en dehors
de la surface du miroir.
Exercice 3. Intersection des volumes convexes.
La surface qui entoure un volume convexe peut être décomposée, en fonction
de la position de la caméra, en deux parties S1 et S2 . S1 est formée de faces
avant (faisant face à la caméra), entièrement visibles. S2 est composée de faces
arrière, cachées par les faces avant.
Nous voulons visualiser la surface Σ qui entoure l’intersection de N volumes
convexes et finis. On suppose que la caméra se trouve en O et ce point est extérieur à tous les volumes intervenant dans l’intersection. Σ peut être décomposée
en Σ1 et Σ2 comme précédemment. Un point M de Σ1 est caractérisé par la propriété suivante : le segment qui relie la position O de la caméra à M rencontre
4
toutes les faces avant. De même, si M ′ ∈ Σ2 , aucune face arrière ne pourra se
trouver entre M ′ et le point O.
Grâce à ces propriétés, nous allons visualiser Σ.
Voici l’algorithme de visualisation que vous devez justifier :
1. Initialisez le Z-buffer et le stencil à zéro. Remplissez le buffer des couleurs avec la couleur du fond d’écran. Rappelons que les réels qui se
trouvent dans le Z-buffer représentent les distances normalisées dn au plan
d’images et appartiennent à l’intervalle [0, 1]. dn = 0 pour les points du
plan d’image, dn = 1 pour les points les plus éloignés à ce plan. Avant
de procéder à l’initialisation, assurez vous que les masques d’écriture des
trois buffers autorisent l’écriture.
2. Interdisez l’écriture dans le buffer des couleurs, désactivez le test de stencil. Activez le test de profondeur, la fonction de comparaison de buffer de
profondeur étant GL_GREATER. Autorisez l’élimination des faces arrière et
dessinez toutes les surfaces. Décrivez ce que contient chaque buffer.
3. L’écriture dans le buffer des couleurs reste interdite. Interdisez aussi l’écriture dans le Z-buffer. Autorisez l’élimination des faces avant. Exécutez les
deux fonctions glStencilFunc et glStencilOp avec les paramètres suivant :
glStencilFunc(GL_ALWAYS, 0, 0xff);
glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
Redessinez toutes les surfaces. Décrivez le contenu du buffer stencil.
4. Dessinez le plan z = −zf ar, en exécutant, avant ce dessin, les instructions
suivantes :
glStencilFunc(GL_NOTEQUAL, N, 0xff);
glStencilOp(GL_ZERO,GL_ZERO,GL_ZERO);
glDepthFunc(GL_ALWAYS);
glDepthMask(GL_TRUE);
glDisable(GL_CULL_FACE);
drawzfar();
Décrivez le contenu de chaque buffer.
5. Autorisez l’écriture dans le buffer des couleurs, désactivez le test de stencil, interdisez l’écriture dans le Z-buffer, la fonction de comparaison de
Z-buffer étant GL_EQUAL. Autorisez l’élimination des faces arrières et redessinez les surfaces.
Dans la maquette de cet exercice (exo3.cpp), on réalise l’intersection de N cylindres. Les cylindres proposés par la librairie glu sont des surfaces ouvertes
des deux côtés. Pour que l’algorithme fonctionne correctement, il faut choisir la
hauteur des cylindres assez grande et positionner la caméra de telle qu’elle se
trouve toujours devant la face externe des cylindres.
5

Documents pareils