Filtrage de texture
Les coordonnées de texture ne dépendent pas de la résolution (largeur
x hauteur) de l’image. Par contre, elles sont exprimées avec deux
float
. OpenGL doit trouver comment associer la
coordonnées \((u,v) \in \mathbb{R}^2\)
à un pixel de texture (texel).
Faisons abstraction d’OpenGL : supposons que nous voulons texturer une ligne 1D avec une image 1D. La ligne connecte deux sommets ensembles. Le premier sommet est donné une coordonnées de texture \(u = 0\). Le deuxième sommet a \(u = 1\).
La ligne n’est pas trop loin, ni trop proche de la caméra. Après la discrétisation (rasterization), elle occupe 6 fragments. Les valeurs \(u\) pour chaque fragment sont interpolées comme suit :
Maintenant, nous voulons colorer chaque fragment à l’aide d’une texture. La texture est 6 pixels de longueur.
Ceci est le cas idéal, mais il est rare.
Sur-échantillonnage (oversampling)
Supposons que l’image pour la texture est maintenant 3 pixels au lieu de 6, et le nombre de fragments est toujours 6. (Sinon, imaginez que notre deuxième sommet a \(u = 0.5\) au lieu de \(1\), donc nous utilisons que la moitié de l’image).
Prenons la couleur du pixel sur lequel \(u\) tombe (nearest neighbour filtering).
Voyons de plus près où nous échantillons la texture :
Ici, nous avons du sur-échantillonnage : il y a plus de fragments que de pixels d’images Nous l’observons présentement sur un axe, mais ceci arrive aussi en 2D. Par exemple, une grille de fragment \(6\times6\) doit être mappée à une image \(3\times3\). Nous appelons ce phénomène le sur-échantillonnage, car chaque pixel est échantillonné plus qu’une fois. Il y a de la redondance.
Supposons que la ligne se reproche de la caméra. Nous avons maintenant 9 fragments :
Il y a plus de sur-échantillonnage. La petite résolution de la texture devient de plus en plus évidente.
Sous-échantillonnage (undersampling)
Supposons que la ligne est maintenant beaucoup plus loin de la caméra. Elle n’a pas encore dépassé le far clipping plane, mais elle n’a qu’un seul fragment. On obtient un probleme de sous-échantillonnage lorsque qu’il y a plus de pixels d’image que de fragments.
Bien que nous voulons texturer toute la ligne avec l’image au complète, seulement une partie de la texture est échantillonnée. Peu importe les \(uv\) des fragments, nous n’aurons pas toutes les couleurs.
Notez la réduction de qualité avec la distance.
Filtrage neareast neighbour vs. bilinéaire (bilinear filtering)
Revenons en 2D. Le filtrage neareast neighbour est celui par
defaut, dans OpenGL. Pour un \((u,v)\) marqué par le +
, la
couleur échantillonnée est la même qu’une des pixels de l’image :
Au lieu de prendre la couleur exacte du pixel où tombe les \((u,v)\), pouvons-nous obtenir une nouvelle couleur en interpolant entre plusieurs pixels ? En d’autres mots, est-ce qu’il y a des techniques de filtrage autre que le nearest neighbour ?
Si nous interpolons avec les pixels voisins en considérant leur distance avec le \((u,v)\):Ceci est l’interpolation bilinéaire. Il existe plusieurs autres types de filtrages, mais nous allons nous concentrer sur les deux cas présentés.
Nous voyons que plus qu’une couleur est proche du point \((u,v)\), plus la couleur contribue au mélange ; elle a plus de poids. | Neareast Neighbour | Bilinear | |———|———-| | Rapide | Plus long | | Aliasing | Plus fluide |
Selon le contexte, une technique peut être plus approprié. Par exemple, les jeux avec une esthétique rétro préfèrent le nearest neighbour.
Nous pouvons utiliser des méthodes de filtrages telles que bilinear filtering pour “dégrader” le cas d’oversampling.
Mais que faisons-nous pour régler l’undersampling ? On ne peut pas dégrader sur très peu de fragments…
Avec le filtrage bilinéaire, nous avons quand même des artéfactes visuels (effet de moiré, notamment).
Nous pouvons subdiviser les fragments pour avoir du sur-échantillonnage :
Ça résout pas complètement le problème et c’est coûteux à calculer…
Mip mapping
Idéalement, nous avons une texture avec le même nombre de pixel que de fragments à texturer. Pour les objets plus proches, nous avons une texture avec une plus grande résolution. Pour les objets plus loins, des textures avec une plus basse résolution. Il n’y aurait jamais de sur/sous-échantillonnage. Par contre, ceci demande une image par profondeur possible par texture distinct. Par exemple, 1000 images de la même texture de gazon à plusieurs résolutions, 1000 images de la même texture de sable, etc…
Bien que nous pouvons précalculer/générer toutes ces textures à partir d’une seule (via upscaling ou downscaling de l’image source), celles-ci saturera la VRAM rapidement.
La solution est une approche hybride précalculer-des-textures/interpolation : le mip mapping.
Nous pouvons générer \(n\) nombre de textures plus bases résolutions :
Trilinear filtering
Pour la couleur d’un fragment, interpoler entre deux textures de résolution voisines :