Je voudrais terminer cette histoire de transformations subies par un sommet pendant son parcours à travers le pipeline de rendu. Notre dernier arrêt est l’espace 2D. Alors - on y va !
La transformation du viewport
Nous reprenons notre discussion à partir de NDC. Pour l’instant, on est encore dans l’espace 3D.
Comment allons-nous à l’espace 2D ?
Il faut transformer notre sommet de NDC en coordonnées de l’écran.
Lors de l’initialisation du Canvas, on est chargé de configurer sa taille. Cette taille est utilisée pour convertir nos coordonnées NDC en coordonnées de l’écran. Voici l’illustration :
Faites attention à la position de l’origine de chaque espace dans l’illustration ci-dessus :
- NDC - L’origine est au centre. Nos coordonnées NDC sont normalisées entre les valeurs (-1, 1) dans les axes
x
ety
. La valeur de l’axez
est entre (0, 1). - Les coordonnées de l’écran - l’origine est en haut à gauche. Le point qui se trouve en bas à droit est la taille définie de notre écran (
w
largeur,h
hauteur).
Le framebuffer
Pour dessiner notre image à l’écran, le WebGPU doit écrire des informations sur chaque pixel dans un tampon de couleur (color buffer).
Le tampon de couleur, combiné avec d’autres tampons qui peuvent être utilisés pour rendre une image finale tels que le tampon de profondeur (depth buffer) et le tampon de stencil (stencil buffer), sont stockés dans la mémoire GPU. Cette combinaison s’appelle un framebuffer.
Si l’on considère que notre framebuffer contient un tampon de couleur qui stocke les informations de couleur d’une aire de pixels de la taille de notre écran (ou d’une taille de Canvas arbitrairement définie par nous), il faudrait donc transformer ces coordonnées normalisées dans celles qui correspondent aux coordonnées de notre cible de rendu (l’écran / Canvas).
Les mathématiques de la transformation
Les axes x
et y
correspondent à la taille définie de l’image finale. Heureusement, les docs de WebGPU nous fournissent ce calcul :
La hauteur (vp.h
) et la largeur (vp.w
) sont la largeur et la hauteur définies de notre viewport. Les positions vp.x
et vp.y
sont des décalages de position. Supposons que nous les définissions comme 0
.
En ce moment, le calcul pour convertir l’axe z
n’est pas défini dans les docs. Cependant, Songho nous indique que pour OpenGL, le calcul est comme suit :
où f
est la valeur de la position du plan lointain, et n
est la valeur de la position du plan proche. Voyez l’article de la semaine dernière pour en savoir plus.
Avec ces calculs, nous pouvons voir que le mapping entre NDC et les coordonnées de l’écran est une relation linéaire :
💡 Que devient-elle, la coordonnée z ?
Lors de la rastérisation, la couleur d’un pixel qui sera rendu sur l’écran est provisionnée dans le tampon de couleur.
Cependant, si l’on configure un test de profondeur (depth test), la coordonnée z
pourrait être utilisée pour résoudre la visibilité, avec l’utilisation du tampon de profondeur pendant le processus qui s’appelle merging.
Bref, le test de profondeur assure que les sommets / primitives les plus proches de la caméra sont provisionnés dans le tampon de couleur (rendu sur l’image finale) et les autres sont rejetés.
Nous reviendrons sur ce sujet quand nous abordons la rastérisation.
Le code dans WebGPU
Il y a quelques semaines, nous avons vu du code afin de créer un triangle avec WebGPU. Rappelons qu’il y a une étape pour configurer à la fois notre CanvasContext et swap chain :
const configureContext = (presentationFormat) => {
const devicePixelRatio = window.devicePixelRatio || 1;
const presentationSize = [
this._context.canvas.clientWidth * devicePixelRatio,
this._context.canvas.clientHeight * devicePixelRatio,
];
this._context.configure({
device: this._device,
format: presentationFormat,
size: presentationSize,
});
}
const presentationFormat = this._context.getPreferredFormat(this._adapter);
configureContext(presentationFormat)
C’est notre travail de fournir la taille de l’image finale. Cette taille est utilisée pendant la transformation de NDC en coordonnées de l’écran.
C’est à nous de redéfinir cette valeur au cas où nous changerions la taille de la fenêtre.
La suite
Je pense qu’il est temps de continuer l’aventure de la simulation de tissu. Étant équipés de ces nouvelles connaissances, on est prêt à implémenter un moyen de charger un fichier .obj dans notre scène.