Troika: Idée rapide pour améliorer l'anticrénelage du texte

Créé le 17 juin 2021  ·  7Commentaires  ·  Source: protectwise/troika

Je ne sais pas si vous avez récemment mis à jour le code d'anticrénelage, car j'utilise une version plus ancienne, mais après avoir trouvé une bonne façon de faire l'anticrénelage des cercles dessinés par shader, je voulais aussi l'essayer sur votre texte , car le texte est basé sur SDF et l'anticrénelage du cercle est également basé sur la distance.

Dans ma version actuelle de Troika, vous faites return length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.5; pour la distance aa. Cela a pour artefact que lors de la visualisation sous un angle, les bords les plus à gauche et les plus à droite obtiennent un flou quelque peu visible :
image

Je l'ai changé en scalaire ; la distance, comme dans mon code de cercle : return fwidth(distance) * 0.5; Avec la distance passée de troikaGetFragDistValue comme ceci : float distance = troikaGetFragDistValue(); float aaDist = troikaGetAADist(distance);
En le faisant de cette façon, je n'obtiens pas l'artefact de flou:
image

Le facteur 0.5 peut être augmenté pour un anticrénelage plus fluide. Par exemple 0.8 :
image

Je pensais que vous n'étiez peut-être pas au courant de cette méthode, tout comme moi, alors j'ai pensé que je la partagerais. Ma "mise en œuvre" a cependant quelques artefacts étranges (voir ci-dessous), et c'est peut-être la raison pour laquelle vous avez opté pour l'autre méthode. De plus, je ne sais pas exactement comment vous utilisez la variable aaDist dans le code du shader, vous serez donc peut-être mieux équipé pour l'implémenter. Peut-être y a-t-il du code qui devrait être modifié ou supprimé à cause de ce changement par exemple, cela pourrait encore améliorer ma "mise en œuvre".

image

J'ai trouvé cette méthode pour le faire dans le post de bgolus ici : https://forum.unity.com/threads/antialiasing-circle-shader.432119/ où il y a plus d'informations. Il dit également que vous pouvez faire par exemple length(vec2(dFdx(distance), dFdy(distance))) au lieu de fwidth(distance) pour une précision encore plus grande, bien que je ne sois pas sûr si cela est négligeable ou non.

Tous les 7 commentaires

Merci pour la suggestion! Je vais certainement me pencher là-dessus, car j'ai également remarqué ces bords flous aux angles obliques et j'aimerais les éliminer.

Théoriquement, je pense que le changement de distance et le changement de vTroikaGlyphUV * vTroikaGlyphDimensions devraient être équivalents car ils représentent tous deux une distance en unités d'espace de police, mais il doit y avoir une différence subtile là-bas. négligé. Si je peux éviter les artefacts que vous avez montrés, alors je serai heureux d'intégrer votre changement. :)

Génial! Le changement est aussi simple que cette ligne (et en passant cet argument de distance pour l'adapter). Si vous souhaitez toujours le code brut, je peux l'envoyer quand je travaille demain.

Théoriquement, je pense que le changement de distance et le changement de vTroikaGlyphUV * vTroikaGlyphDimensions devraient être équivalents car ils représentent tous deux une distance en unités d'espace de police

Je ne comprends pas exactement comment les dérivés seraient les mêmes. distance est la distance SDF je suppose, mais l'autre est une position uv mise à l'échelle. Je n'ai pas regardé le code et comment ils se comparent, mais j'ai l'impression que leurs dérivés devraient être différents. Autant que je sache, fwidth prend simplement la différence de la valeur d'entrée spécifique transmise en tant qu'argument avec ces mêmes valeurs d'entrée spécifiques dans les fragments voisins, ce qui est possible car les fragments voisins s'exécutent en même temps en parallèle. J'ai effectué un test plus tôt dans la journée avec gl_FragColor.rgb = vec3(fwidth(gl_FragColor.x + gl_FragColor.g + gl_FragColor.b)); pour voir s'il rendait les bords comme dans la détection des bords/un filtre sobel, pour essayer de confirmer un peu ce fait, et c'est le cas.

Merci pour la discussion, ce truc me casse parfois la cervelle. ;)

Quand j'ai dit qu'ils sont "équivalents", je voulais dire qu'ils représentent tous les deux une distance dans les mêmes unités, mais vous avez raison, ils ne sont pas exactement les mêmes.

En reculant, ce que nous voulons ici, c'est le taux de changement _potentiel_ entre les fragments. L'utilisation du changement dans la variable distance comme vous le suggérez sera souvent exacte pour cela, mais dans certains cas, elle sera très imprécise. C'est parce que le SDF à partir duquel cette valeur est échantillonnée est _non uniforme_ ; il se courbe et change sa direction de changement à travers le glyphe. Par conséquent, la dérivée de distance entre des fragments voisins peut finir par être beaucoup trop petite, voire nulle, comme lorsque le champ de distance passe d'une augmentation à une diminution à mi-chemin entre les chemins de glyphes, ou beaucoup trop grande, comme lorsque le texte est affiché à de petites tailles et la grille de fragments recouvre le SDF à des endroits imprévisibles. Je soupçonne que cela explique au moins certains des artefacts que vous voyez.

Alors, comment pouvons-nous déterminer le taux de changement _potentiel_ sans utiliser distance ? Eh bien, cette "position uv mise à l'échelle" comme vous l'appelez est essentiellement une coordonnée x/y dans le rect du glyphe, en utilisant les mêmes unités que distance . La dérivée de ce x/y nous donne un taux de déplacement potentiel entre les fragments. Dans l'ensemble, cela donne un meilleur résultat que d'utiliser distance , car il est basé sur un taux de changement _uniforme_ sur le glyphe, et nous n'obtenons donc pas d'artefacts et c'est plus précis aux petites tailles.

Mais, comme vous l'avez vu, là où il se décompose, c'est aux angles obliques; dans ces cas, le taux de changement potentiel x/y dans la verticale est très différent de celui de l'horizontale. Et donc nous finissons par utiliser une seule valeur pour le taux de changement potentiel qui est trop grande dans une direction et trop petite dans l'autre, donnant des lignes floues et/ou saccadées en fonction de la direction réelle de changement du SDF à ce fragment.

Alors oui, il y a certainement place à l'amélioration dans le cas oblique, mais le simple fait d'utiliser la dérivée de distance n'est pas suffisant en soi. Je suis ouvert aux idées pour améliorer cela bien sûr. Une possibilité pourrait être d'essayer de détecter le scénario (grande taille de texte à un angle oblique, près d'un chemin) et d'utiliser la dérivée distance uniquement dans ce cas.

Ouais, c'est déroutant d'y penser, haha. Je peux voir que le champ de distance est moins lisse, ouais.

Ces pixels glitchy pourraient simplement être dus au fait que les fragments ont des valeurs de distance étranges.

Ce n'est pas incroyablement agité de loin, mais vous pouvez certainement voir que les UV sont meilleurs. Peut-être que l'interpolation entre la variable de distance et les UV dépendant de la distance de la caméra fonctionnerait bien ; comme dans choisir plus de fwidth (distance) lorsqu'il est proche, et plus de fwidth (uv) lorsqu'il est loin.

À titre de comparaison (n'a pas capturé les deux exactement à la même position et orientation de la caméra, mais je pense que cela montre bien la différence de toute façon):
Distance (facteur 0,8) :
image
UV :
image

Je remarque que cette modification améliore considérablement le résultat des transformations de texte personnalisées. Voici du texte, modifié pour suivre une courbe en utilisant createDerivedMaterial ( voir cette technique ). Cela utilise les shaders actuels de troika-three-text :

image

Voici la même capture d'écran, mais avec la modification de @asbjornlystrup en troikaGetAADist :

image

Dans le deuxième plan, vous pouvez voir le "GREAT!" extrêmement étiré. est un peu plus croustillant.

Pour l'anecdote : j'ai également constaté que le fait d'ajuster la constante à 0,25 (à partir de 0,5) donne également un joli bord net :

return length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.25;

Merci @canadaduane , je peux certainement voir l'amélioration des parties étirées. Je peux également voir les artefacts laids apparaître entre les L dans HELLO, que nous aurions certainement besoin de comprendre avant d'adopter ce changement.

Cette page vous a été utile?
0 / 5 - 0 notes