[Z-buffer] Le Z-buffer et le Z-fighting expliqués : est-ce correct ?

a marqué ce sujet comme résolu.

Salut à tous !

Que pensez-vous de mes explications sur le Z-buffer, l’algorithme du Z-buffer et le Z-fighting ? Avez-vous des remarques à faire ? Trouvez-vous que je manque de précision ? Que j’ai fait des erreurs ?

Définitions : Z-buffer et algorithme du Z-buffer

Le Z-buffer est la structure de données utilisée par l’algorithme du Z-buffer, lequel permet de dessiner, depuis un espace à trois dimensions mais dans un espace à deux dimensions, tout ou partie d’un objet 3D par-dessus (donc en cachant) tout ou partie d’un autre objet 3D.

Le Z-buffer est en fait un tableau à deux dimensions, l’une correspondant à l’abscisse des pixels de l’écran (coordonnée “X”), l’autre à l’ordonnée des pixels de l’écran (coordonnée “Y”). Autrement dit, une case de ce tableau représente un pixel. La valeur de chaque case est, quant à elle, la profondeur du pixel (= coordonnée “Z”, d’où “Z-buffer”). Enfin, le Z-buffer a la même taille que le nombre de pixels de l’écran.

Algorithme du Z-buffer et événements qui déclenchent à la fois l’exécution de l’algorithme du Z-buffer et l’utilisation du Z-buffer par ce dernier

Algorithme

L’algorithme du Z-buffer fonctionne comme suit.

  1. Initialisation de chaque case du Z-buffer à 0 ;

  2. Un cube et une sphère doivent être dessinés à l’écran : ces deux objets 3D ne se touchent pas, mais le cube est placé devant la sphère et la cache ;

  3. On donne à l’algorithme du Z-buffer la profondeur “A” de chaque pixel de chaque objet 3D à dessiner à l’écran (note : dans ce qui suit, “case adéquate” signifie “case de mêmes coordonnées X et Y que le pixel qui sera ou ne sera pas dessiné”) :

  4. Si la valeur stockée dans le Z-buffer (laquelle est celle de la case adéquate) est égale à 0, alors le pixel sera dessiné et “A” remplacera l’ancienne valeur ;

  5. Si “A” est strictement inférieure à la valeur stockée dans le Z-buffer (laquelle est celle de la case adéquate), alors ce pixel sera dessiné et “A” remplacera l’ancienne valeur ;

  6. Sinon, si “A” est strictement supérieure à la valeur stockée dans le Z-buffer (laquelle est celle de la case adéquate), alors ce pixel ne sera pas dessiné et aucun remplacement de valeur n’a lieu.

  7. A l’issue de ce traitement, pour tout couple de pixels qui sont superposés, seul celui de profondeur moindre est dessiné, reproduisant ainsi la notion de “profondeur” de la vraie vie et de l’espace en trois dimensions, dans un espace en deux dimensions.

  8. En conclusion, seul le cube sera dessiné.

  9. On notera par ailleurs qu’on obtiendrait un résultat correct et correspondant bien à ce qu’on veut, si une partie du cube cachait une partie de la sphère tout en ayant un dépassement de l’un de ces deux objets sur l’autre (exemple avec des triangles : http://raphaello.univ-fcomte.fr/IG/ZBuffer/Images/ZBuffer3-01.gif).

Evénements déclencheurs

L’exécution de cet algorithme a lieu suite à plusieurs événements :

  1. Dans une visualisation 2D d’une scène 3D, chaque fois que la caméra se déplace d’une unité (en reculant par-rapport aux objets ou bien en avançant) ;

  2. Dans une visualisation 2D d’une animation 3D, chaque fois qu’une milliseconde s’écoule.

Problème : le Z-fighting

Définition

On notera l’existence d’un problème nommé “Z-fighting” si deux objets 3D se touchent et qu’une partie de leurs pixels ont les mêmes coordonnées X, Y et Z (en particulier, on constatera qu’ils ont la même profondeur : coordonnée “Z”).

Dès lors, en considérant tout couple de pixels qui se chevauchent, l’algorithme dessinera le pixel de l’un de ces deux objets (lequel est choisi aléatoirement), puis à l’événement suivant (après une milliseconde ou bien si la caméra avance d’une unité), ce choix aléatoire se fera de nouveau : en résulte un clignotement de cette partie des deux objets 3D, clignotement visible par l’utilisateur de l’ordinateur.

Le Z-fighting a aussi lieu quand les cases du Z-buffer manquent de précision… !

Si deux objets 3D, un cube et une sphère, possèdent des pixels qui ont les mêmes coordonnées X et Y, mais une profondeur, notée “Z”, très légèrement différente, l’utilisateur de l’ordinateur, qui les visualise dans l’espace en trois dimensions, pourra constater que ces deux objets ne se touchent pas : le Z-fighting ne devrait donc pas apparaître. Or, chaque case du Z-buffer n’accepte des valeurs que plus ou moins précises. Imaginons par exemple que le pixel du cube (1 ; 1) ait une Z = 2.6, que le pixel de la sphère (1 ; 1) ait une Z = 2.8, que chaque case du Z-buffer n’accepte que des valeurs comme : {2, 3, 4…} et que la case du Z-buffer (1 ; 1) vaut 0 : que se passera-t-il d’après l’algorithme précédemment donné ? Un 0 est présent dans la case adéquate, donc le pixel de l’objet 3D à dessiner en 2D sera forcément dessiné et mis dans la case du Z-buffer ; sauf que cette dernière ne peut contenir que des valeurs comme {2, 3, 4…} : ainsi 2.6 sera-t-il converti en 3 (il en serait de même pour 2.8). Puis lorsqu’un prochain événement déclencheur aura lieu, la comparaison retournera de nouveau VRAI, il y aura de nouveau conversion et de nouveau remplacement de valeur. Donc le Z-fighting aura lieu. Sans conversion (due au manque de précision et donc de bits de chaque case du Z-buffer), il n’y aurait en revanche pas eu de Z-fighting.

Exemple avec Z-fighting

Chaque case du Z-buffer peut contenir des valeurs comme : {2, 3, 4…}

  1. Cube(1 ; 1 ; 2.6) - Sphère (1; 1; 2.8) - Z-buffer (1 ; 1 ; 0)

  2. Il existe un 0 donc Z-buffer (1 ; 1 ; 3) (Cube(1 ; 1) dessiné)

  3. 2.8 < 3 donc Z-buffer(1 ; 1 ; 3) (Sphère(1 ; 1) dessiné)

  4. 2.6 < 3 donc Z-buffer(1 ; 1 ; 3) (Cube(1 ; 1) dessiné)

Et à chaque événement déclencheur, ça recommence… : présence du clignotement (= présence du Z-fighting).

Exemple sans Z-fighting

Chaque case du Z-buffer a suffisamment de précision.

  1. Cube(1 ; 1 ; 2.6) - Sphère (1; 1; 2.8) - Z-buffer (1 ; 1 ; 0)

  2. Il existe un 0 donc Z-buffer (1 ; 1 ; 2.6) (Cube(1 ; 1) dessiné)

  3. 2.8 > 2.6 donc Z-buffer(1 ; 1 ; 2.6) (Sphère(1 ; 1) non-dessiné)

Et à chaque événement déclencheur, ça recommence… : absence de clignotement car le pixel du cube est dessiné, et jamais celui de la sphère (= absence de Z-fighting).

+1 -0

Bonjour.

Avec ce que je sais sur le sujet, je n’irai pas m’avancer sur l’algorithme (chaque moteur de rendu doit avoir sa variante de l’algo…), mais le principe est la. Et le problème du z-fighting est bien celui la.

Peut être préciser que la profondeur dont tu parle est en fait la distance entre la camera et le "pixel" dans son environnement en 3 dimension.

Quelques illustrations pourraient simplifier les explication.

Le z-fighting n’arrive "jamais" entre un cube et une sphère. Il n’y aurait qu’un point et ce serait presque invisible. Le problème est clairement visible avec les surfaces planes. Deux cubes placé au même endroit et avec des couleurs différentes par exemple.

+1 -0

j’ai cependant oublié le cas où les deux objets sont beaucoup trop loin et donc que leur distance respective avec la caméra est égale (NB : "égale" à la valeur maximale d’une case du Z-buffer). C’est en fait là aussi un manque de précision des cases du Z-buffer mais cette fois-ci rien à voir avec les décimales.

Je rajouterais ce cas du coup.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte