Interpolation en profondeur pour z-buffer, avec scanline


10

Je dois écrire mon propre logiciel de rastérisation 3D, et jusqu'à présent, je suis capable de projeter mon modèle 3D composé de triangles dans un espace 2D:

Je fais pivoter, traduire et projeter mes points pour obtenir une représentation spatiale 2D de chaque triangle. Ensuite, je prends les 3 points du triangle et j'implémente l'algorithme de la ligne de balayage (en utilisant l'interpolation linéaire) pour trouver tous les points [x] [y] le long des bords (gauche et droite) des triangles, afin de pouvoir balayer le triangle horizontalement, ligne par ligne, et remplissez-la de pixels.

Cela marche. Sauf que je dois également implémenter la mise en mémoire tampon z. Cela signifie que connaissant les coordonnées z pivotées et traduites des 3 sommets du triangle, je dois interpoler la coordonnée z pour tous les autres points que je trouve avec mon algorithme de ligne de balayage.

Le concept semble assez clair, je trouve d'abord Za et Zb avec ces calculs:

var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);

Puis pour chaque Zp je fais la même interpolation horizontalement:

var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);

entrez la description de l'image ici

Et si le z actuel est plus proche du spectateur que le z précédent à cet index ALORS écrivez la couleur dans le tampon de couleur ET écrivez le nouveau z dans le tampon z. (mon système de coordonnées est x: gauche -> droite; y: haut -> bas; z: votre visage -> écran d'ordinateur;)

Le problème, c'est que ça se détraque. Le projet est et si vous sélectionnez le bouton radio "Z-Buffered", vous verrez les résultats ... ( notez que j'utilise l'algorithme du peintre (-seulement- pour dessiner le filaire) en mode "Z-Buffered") à des fins de débogage )

PS: J'ai lu ici que vous devez transformer les z en leurs inverses (ce qui signifie z = 1/z) avant d'interpoler. J'ai essayé, et il semble qu'il n'y ait aucun changement. Qu'est-ce que je rate? (quelqu'un pourrait-il clarifier précisément où vous devez transformer z en 1 / z et où (si) le retourner?)

[MODIFIER] Voici quelques données sur les valeurs z maximales et minimales que j'obtiens:

    max z: 1;                  min z: -1;                 //<-- obvious, original z of the vertices of the triangles
    max z: 7.197753398761272;  min z: 3.791703256899924;   //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
    max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.

Avant d'entrer dans un débogage minutieux, quelqu'un peut-il confirmer que mon concept jusqu'à présent est correct?

[EDIT2]

J'ai résolu le z-buffering. Il s'est avéré que l'ordre de dessin n'était pas du tout foiré. Les coordonnées z étaient calculées correctement.

Le problème était, dans le but d'augmenter ma fréquence d'images, je dessinais des boîtes 4px / 4px, tous les 4 pixels, au lieu de pixels réels à l'écran. Je dessinais donc 16 pixels par pixel, mais en vérifiant le tampon z pour un seul d'entre eux. Je suis un tel boob.

TL / DR: La question se pose toujours: comment / pourquoi / quand devez-vous utiliser l'inverse de Z (comme dans 1 / z) au lieu de Z? Parce qu'en ce moment, tout fonctionne dans les deux sens. (il n'y a pas de différence notable).


Re: "Et bien sûr, j'ajoute au zBuffer, si le z actuel est plus proche du spectateur que la valeur précédente à cet index." Ce n'est pas clair pour moi que vous avez dit que vous vouliez, mais que vous vouliez vous assurer que ce que vous vouliez dire était "si le z actuel est plus proche du spectateur que le z précédent à cet index PUIS écrivez la couleur dans le tampon de couleur ET écrivez le nouveau z dans le tampon z "Le but du tampon z est de bloquer les écritures couleur si une couleur à ce pixel était déjà écrite plus près de l'œil de la caméra.
Alturis

C'est exact. Désolé, il était tard lorsque j'ai formulé ma question. Je vais réviser.
Spectraljump

Réponses:


5

Réponse rapide: Z n'est pas une fonction linéaire de (X ', Y'), mais 1 / Z l'est. Puisque vous interpolez linéairement, vous obtenez des résultats corrects pour 1 / Z, mais pas pour Z.

Vous ne le remarquez pas car tant que la comparaison entre Z1 et Z2 est correcte, le zbuffer fera la bonne chose, même si les deux valeurs sont fausses. Vous remarquerez certainement lorsque vous ajoutez un mappage de texture (et pour répondre à la question, vous devrez alors: interpoler 1 / Z, U / Z et V / Z, et reconstruire U et V à partir de ces valeurs: U = (U / Z) / (1 / Z), V = (V / Z) / (1 / Z). Vous me remercierez plus tard)

Un exemple. Obtenez un morceau de papier. Vue de haut en bas, oubliez donc la coordonnée Y. X est l'axe horizontal, Z est l'axe vertical, la caméra est à (0, 0), le plan de projection est z = 1.

Considérez les points A (-2, 2) et B (2, 4). Le point milieu M du segment AB est (0, 3). Jusqu'ici tout va bien.

Vous projetez A dans A ': X' = X / Z = -1, donc A 'est (-1, 1). De même, B 'est (0,5, 1). Mais notez que la projection de M est (0, 1), ce qui n'est PAS le milieu de A'B '. Pourquoi? Parce que la moitié droite du segment est plus éloignée de la caméra que la moitié gauche, elle semble donc plus petite.

Alors, que se passe-t-il si vous essayez de calculer le Z de M 'en utilisant une interpolation linéaire? dx = (0,5 - -1) = 1,5, dz = (4 - 2) = 2, donc pour M 'où X' = 0, le Z interpolé linéairement est zA + (dz / dx) (x - xA) = 2 + (2 / 1,5) (0 - -1) = 2 + 1,333 = 3,3333 - PAS 3!

Pourquoi? Parce que pour chaque pas dans la direction X ', vous ne déplacez pas la même quantité dans la direction Z (ou, en d'autres termes, Z n'est pas une fonction linéaire de X'). Pourquoi? Parce que plus vous allez à droite, plus le segment est éloigné de la caméra, donc un pixel représente une distance plus longue dans l'espace.

Enfin, que se passe-t-il si vous interpolez 1 / Z à la place? Vous calculez d'abord 1 / Z à A et B: 0,5 et 0,25 respectivement. Ensuite, vous interpolez: dx = (0,5 - -1) = 1,5, dz = (0,25 - 0,5) = -0,25, donc à X '= 0 vous calculez 1 / Z = 0,5 + (-0,25 / 1,5) * (0 - -1) = 0,3333. Mais c'est 1 / Z, donc la valeur de Z est ... exactement, 3. Comme il se doit.

Oui, les mathématiques sont géniales.


1
Oh, et concernant "quand": calculez les valeurs 1 / Z avant de commencer à pixelliser le triangle (par exemple juste avant la boucle verticale), de sorte que vous obtenez interpolé 1 / Z à gauche et à droite de la ligne de balayage. Interpolez-les linéairement (ne refaites PAS 1 / Z - les valeurs interpolées sont déjà 1 / Z!), Et annulez la transformation juste avant de vérifier le zbuffer.
ggambett

1
Et enfin, pourquoi. Un plan (où le triangle est intégré) est Ax + By + Cz + D = 0. z est clairement une fonction linéaire de (x, y). Vous projetez donc x '= x / z et y' = y / z. De là, x = x'z et y = y'z. Si vous les remplacez dans l'équation d'origine, vous obtenez Ax'z + By'x + Cz + D = 0. Maintenant z = -D / (Ax '+ By' + C), où il est clair que z n'est pas une fonction linéaire de (x ', y'). Mais 1 / z est donc (Ax '+ By' + C) / -D, qui est une fonction linéaire de (x ', y').
ggambett

1
Vous savez, j'ai lu pas mal d'articles et de cours, et aucun d'eux n'était aussi clair que votre réponse. Pour la postérité, je noterai également que "Les lettres" U "et" V "désignent les axes de la texture 2D car" X "," Y "et" Z "sont déjà utilisés pour désigner les axes de l'objet 3D dans le modèle La texture UV permet aux polygones qui composent un objet 3D d'être peints avec la couleur d'une image. " - Wikipedia - Cartographie UV
Spectraljump

Content de l'entendre. En fait, j'ai enseigné l'infographie dans une vie antérieure :)
ggambett

Merci beaucoup - j'ai toujours été curieux à ce sujet - et je ne sais pas si j'aurais jamais trouvé une meilleure réponse! +1
Codeur
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.