Le problème de l'utilisation des atlas de texture et des fuites de texels adjacentes est lié au fonctionnement du filtrage de texture linéaire.
Pour tout point de la texture qui n'est pas échantillonné exactement au centre d'un texel, l'échantillonnage linéaire échantillonnera 4 texels adjacents et calculera la valeur à l'emplacement que vous avez demandé comme moyenne pondérée (basée sur la distance du point d'échantillonnage) des 4 échantillons.
Voici une belle visualisation du problème:
Comme vous ne pouvez pas utiliser quelque chose comme GL_CLAMP_TO_EDGE
dans un atlas de texture, vous devez créer des texels de bordure autour du bord de chaque texture. Ces texels de bordure empêcheront les échantillons voisins de textures complètement différentes dans l'atlas de modifier l'image par l'interpolation pondérée expliquée ci-dessus.
Notez que lorsque vous utilisez le filtrage anisotrope, vous devrez peut-être augmenter la largeur de la bordure. En effet, le filtrage anisotrope augmentera la taille du voisinage de l'échantillon à des angles extrêmes.
Pour illustrer ce que je veux dire en utilisant une bordure autour du bord de chaque texture, considérez les différents modes d'habillage disponibles dans OpenGL. Portez une attention particulière à CLAMP TO EDGE
.
Bien qu'il existe un mode appelé "Clamp to Border", ce n'est en fait pas ce qui nous intéresse. Ce mode vous permet de définir une seule couleur à utiliser comme bordure autour de votre texture pour toutes les coordonnées de texture qui se situent en dehors de la normalisée [0.0 -1,0] plage.
Ce que nous voulons, c'est reproduire le comportement de CLAMP_TO_EDGE
, où toute coordonnée de texture en dehors de la plage appropriée pour la (sous-) texture reçoit la valeur du dernier centre de texels dans la direction où elle était hors limites. Puisque vous avez un contrôle presque complet sur les coordonnées de texture dans un système d'atlas, le seul scénario dans lequel les coordonnées de texture (effectives) pourraient se référer à un emplacement en dehors de votre texture sont pendant l'étape moyenne pondérée du filtrage de texture.
Nous savons que GL_LINEAR
nous échantillonnerons les 4 voisins les plus proches comme le montre le diagramme ci-dessus, nous n'avons donc besoin que d'une bordure de 1 texel. Vous pouvez avoir besoin d'une bordure de texel plus large si vous utilisez le filtrage anisotrope, car il augmente la taille du voisinage de l'échantillon dans certaines conditions.
Voici un exemple d'une texture qui illustre plus clairement la bordure, bien que pour vos besoins, vous pouvez faire la bordure de 1 texel ou 2 texels de large.
(REMARQUE: la bordure à laquelle je fais référence n'est pas le noir autour des quatre bords de l'image, mais la zone où le motif en damier cesse de se répéter régulièrement)
Au cas où vous vous poseriez la question, voici pourquoi je continue d'évoquer le filtrage anisotrope. Il modifie la forme du voisinage de l'échantillon en fonction de l'angle et peut entraîner l'utilisation de plus de 4 texels pour le filtrage:
http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg
Plus le degré d'anisotropie que vous utilisez est élevé, plus vous aurez de chances de traiter des échantillons de voisinage contenant plus de 4 texels. Une bordure de 2 texels devrait être adéquate pour la plupart des situations de filtrage anisotrope.
Enfin, voici comment un atlas de textures compacté serait construit qui reproduirait le GL_CLAMP_TO_EDGE
comportement en présence d'un GL_LINEAR
filtre de textures:
( Soustrayez 1 de X et Y dans les coordonnées noires, je n'ai pas vérifié la lecture de l'image avant de poster. )
En raison du stockage des bordures, le stockage de 4 textures 256x256 dans cet atlas nécessite une texture aux dimensions 516x516. Les bordures sont codées par couleur en fonction de la façon dont vous les remplissez de données texels lors de la création de l'atlas:
- Rouge = remplacer par texel directement en dessous
- Jaune = Remplacer par texel directement au-dessus
- Vert = Remplacer par texel directement à gauche
- Bleu = Remplacer par texel directement à droite
En effet, dans cet exemple compact, chaque texture de l'atlas utilise une région 258x258 de l'atlas, mais vous générerez des coordonnées de texture qui correspondent à la région 256x256 visible. Les texels de bordure ne sont utilisés que lorsque le filtrage des textures est effectué sur les bords des textures de l'atlas, et la façon dont ils sont conçus imite le GL_CLAMP_TO_EDGE
comportement.
Au cas où vous vous poseriez la question, vous pouvez implémenter d'autres types de modes d'habillage en utilisant une approche similaire - GL_REPEAT
peut être implémenté en échangeant les texels de bordure gauche / droite et haut / bas dans l'atlas de texture et un peu de mathématiques de coordonnées de texture intelligentes dans un shader. C'est un peu plus compliqué, alors ne vous en faites pas pour l'instant. Puisque vous ne traitez qu'avec des feuilles de sprite, limitez-vous à GL_CLAMP_TO_EDGE
:)
GL_NEAREST
ouGL_LINEAR
pour rendre la texture?