Textures de feuille de sprite ramassant les bords de la texture adjacente


10

J'ai une routine de sprite personnalisée (openGL 2.0) qui utilise une simple feuille de sprite (mes textures sont disposées horizontalement les unes à côté des autres).

Donc, par exemple, voici une feuille de sprite de test avec 2 textures simples:

entrez la description de l'image ici

Maintenant, ce que je fais lors de la création de mon objet sprite openGL est de spécifier le nombre total de cadres dans son atlas et lors du dessin, de spécifier le cadre que je veux dessiner.

Il détermine ensuite où récupérer la texture en:

Division du numéro de trame requis par le nombre total de trames (pour obtenir la coordonnée de gauche)

Et puis plongée 1 par le nombre total d'images et en ajoutant le résultat à la coordonnée de gauche calculée ci-dessus.

Cela semble fonctionner mais j'ai parfois des problèmes. Dites par exemple, je veux dessiner le X ci-dessous et je reçois ...........

entrez la description de l'image ici

J'ai entendu parler de mettre un «rembourrage» de 1 px entre chaque texture, mais quelqu'un pourrait-il expliquer exactement comment cela fonctionne? Je veux dire que si je fais cela, cela détruira sûrement les calculs pour obtenir la texture.

Si j'inclus simplement le rembourrage dans la texture ramassée (de sorte que le sprite est dessiné avec une bordure vierge), alors cela causera sûrement un problème avec la détection de collision? (c'est-à-dire que les sprites peuvent sembler entrer en collision lors de l'utilisation de boîtes englobantes lorsque les parties transparentes entrent en collision).

J'apprécierais si quelqu'un pouvait expliquer.


Utilisez-vous GL_NEARESTou GL_LINEARpour rendre la texture?
MichaelHouse

J'utilise GL_Linear @ Byte56
BungleBonce

Réponses:


15

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_EDGEdans 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.

  http://lucera-project.com/blog/wp-content/uploads/2010/06/wrap.png

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_LINEARnous é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_EDGEcomportement en présence d'un GL_LINEARfiltre 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_EDGEcomportement.

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_REPEATpeut ê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:)


Merci @AndonMColeman, pourriez-vous montrer la bordure dans un diagramme car je ne suis toujours pas sûr de comprendre comment cela fonctionne - cela signifie-t-il que lorsque la texture est appliquée à mon objet, elle comprendra la bordure? Je veux que la texture réelle passe directement sur les bords de mon quad - désolé si je ne comprends pas correctement - j'apprécierais plus de détails - merci
BungleBonce

@ user22241 Certes, le fonctionnement de cette bordure consiste à dupliquer le texel au bord de la texture.
Andon M. Coleman

@ user22241: Non, cette bordure ne sera pas visible dans des circonstances normales. Vous traiterez vos textures compressées comme ayant les mêmes dimensions pour le calcul des coordonnées de texture, il vous suffit de leur appliquer un décalage pour passer la frontière. Le point entier de la bordure est d'empêcher l'échantillonnage de texture linéaire de dépasser et d'échantillonner les texels qui appartiennent à des images distinctes dans votre feuille de sprite. Si vous utilisez l'échantillonnage du voisin le plus proche, rien de tout cela n'est nécessaire, mais vous obtenez alors des sprites aliasés méchants.
Andon M. Coleman

Réponse brillamment détaillée - merci! Juste une dernière chose si je pouvais. Comment pourrais-je déterminer le «décalage» à ajouter à mes coordonnées de texture? Ai-je raison de dire que ce serait simplement 1 / widthOfTexture?
BungleBonce

@ user22241: Oui, le début de l'image de texture serait + 1 / widthOfTexture dans la direction X et + 1 / heightOfTexture dans la direction Y. Vous aurez une bordure qui va tout autour de chaque texture. Au moment où vous souhaitez calculer les coordonnées de texture pour la 3e texture horizontale, l'emplacement compressé pour cette texture est en fait +5 texels (+2 texels pour la bordure de la première texture, +2 pour la bordure de la deuxième texture et +1 pour le début de cette texture) en plus de la largeur des 2 autres textures. Cela semble compliqué de simplement l'écrire; Je peux vous dessiner un diagramme si besoin est :)
Andon M. Coleman
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.