03 — Le pipeline de projection
Ce que tu vas apprendre
- Les cinq espaces traversés par un point, du monde au pixel
- La division perspective, le cœur de l'effet de profondeur
- Pourquoi on passe par des coordonnées normalisées (NDC)
- Comment on retombe enfin sur des coordonnées pixel
Prérequis
On a une caméra réglée. Reste à faire voyager un point 3D jusqu'à son pixel. Ce voyage traverse une suite d'espaces, chacun avec sa transformation. C'est mécanique une fois qu'on connaît les étapes — et c'est exactement ce que fait une carte graphique des millions de fois par image.
Les cinq espaces
monde → caméra → écran → NDC → raster
(world) (camera) (screen) (pixel i,j)
M⁻¹ ÷(-z) normalise ×résolution
Suivons un point P à chaque étape.
Étape 1 — Monde → caméra
P est défini en espace monde. Pour le projeter, il faut d'abord l'exprimer du point de vue de la caméra. On le multiplie par la matrice monde-vers-caméra, qui est l'inverse de la matrice caméra-vers-monde (celle de LookAt). Comme cette matrice est orthogonale, son inverse est sa transposée — gratuit, comme vu en série maths.
Après cette étape, la caméra est à l'origine et regarde vers les z négatifs. La profondeur d'un point est donnée par son z (négatif s'il est devant la caméra).
Étape 2 — Caméra → écran : la division perspective
Voici le cœur de la perspective. Pour projeter un point sur le plan image, on divise ses coordonnées x et y par sa profondeur :
P'.x = P.x / -P.z
P'.y = P.y / -P.z
(Le signe moins vient de la caméra qui regarde vers les z négatifs.) C'est tout ! Cette simple division crée l'effet de profondeur : plus un point est loin (|z| grand), plus on divise par un grand nombre, donc plus il se rapproche du centre de l'image et paraît petit. Deux objets identiques à des distances différentes se projettent à des tailles différentes. C'est la traduction mathématique de « les rails se rejoignent à l'horizon ».
Le résultat P' vit sur le plan image, dans l'espace écran (screen space) — des coordonnées 2D exprimées dans l'unité du canvas, centrées sur l'axe optique.
Étape 3 — Écran → NDC
Les coordonnées écran dépendent de la taille du canvas. On les normalise dans un intervalle propre et indépendant de la résolution : les coordonnées normalisées (Normalized Device Coordinates, NDC). Selon la convention, NDC va de [0, 1] ou de [-1, 1].
P_ndc.x = (P'.x + largeurCanvas/2) / largeurCanvas // → [0, 1]
P_ndc.y = (P'.y + hauteurCanvas/2) / hauteurCanvas
L'intérêt des NDC : à ce stade, tout est exprimé en proportions de l'image (« à 30 % de la largeur, 70 % de la hauteur »), sans savoir si l'image finale fera 800 ou 4000 pixels de large. C'est un espace pivot, propre et réutilisable.
Étape 4 — NDC → raster
Dernière marche : convertir les proportions en vraies coordonnées pixel (raster space). On multiplie par la résolution, on prend la partie entière, et on retourne l'axe y (en NDC, y monte ; en raster, y descend, le pixel (0,0) étant en haut à gauche) :
i = floor( P_ndc.x × largeurImagePx )
j = floor( (1 − P_ndc.y) × hauteurImagePx ) // y inversé
(i, j) est enfin l'adresse du pixel. Le voyage est terminé.
En une fonction
Mis bout à bout, voici le squelette du calcul (rasterization) :
cppbool computePixelCoordinates(const Vec3f& pWorld, const Matrix44& worldToCamera,
/* canvas, résolution... */ int& i, int& j)
{
Vec3f pCamera = pWorld * worldToCamera; // 1. monde → caméra
Vec2f pScreen;
pScreen.x = pCamera.x / -pCamera.z; // 2. division perspective
pScreen.y = pCamera.y / -pCamera.z;
Vec2f pNDC; // 3. écran → NDC
pNDC.x = (pScreen.x + canvasW/2) / canvasW;
pNDC.y = (pScreen.y + canvasH/2) / canvasH;
i = floor(pNDC.x * imageW); // 4. NDC → raster
j = floor((1 - pNDC.y) * imageH);
return /* le point est-il dans le canvas ? (visible) */;
}
Tout ce pipeline suppose que le point est dans le volume visible. Définir ce volume — le frustum — et écarter ce qui en sort, c'est le sujet de l'article suivant.
Sources
- Scratchapixel. Computing the Pixel Coordinates of a 3D Point — Mathematics of Computing the 2D Coordinates. scratchapixel.com
- Scratchapixel. Perspective Projection. scratchapixel.com
- Marschner, S., & Shirley, P. (2021). Fundamentals of Computer Graphics (5ᵉ éd.), chap. « Viewing ». CRC Press.