Sharp Corners avec des champs de distance signés

49

Les champs de distance signés (SDF) ont été présentés comme une solution rapide permettant à Valve d’obtenir un rendu des polices indépendant de la résolution dans cet article .

La solution Valve fonctionne déjà, mais j'aimerais préserver la netteté dans les coins. Valve indique que sa méthode peut obtenir des angles vifs en utilisant un deuxième canal de texture AND avec celui de base, mais ne permet pas d'expliquer comment ce deuxième canal serait généré.

En fait, il y a beaucoup de détails de mise en œuvre laissés en dehors de ce document.

J'aimerais savoir si l'un de vous pourrait m'indiquer la direction à suivre pour obtenir le rendu des polices SDF avec des angles vifs.

Felipe Lira
la source
En fait, Adam a déjà posté du code source sur shadertoy. Voici le lien: shadertoy.com/view/ltXSDB
Felipe Lira
Tu m'as excité. Il a posté les trucs Bézier sur Shadertoy mais pas les trucs du champ de distance de texture!
Alan Wolfe
@AlanWolfe Je pense qu'il ne l'a fait que pour les courbes de Bézier définies de manière procédurale. Je ne suis pas sûr de l'effort nécessaire pour intégrer cela dans un fichier ttf render lib. Quand j'aurai du temps, j'y jetterai un coup d'oeil.
Felipe Lira
il semble qu'il ait une sauce magique sur le côté de stocker et de récupérer les distances d'une texture. Sans texture en jeu, cette partie de l'équation manque dans les exemples de shadertoy.
Alan Wolfe
Peu de temps pour la soirée, mais l'ancien fil de reddit contient une tonne d'informations sur diverses méthodes permettant d'améliorer la netteté du rendu basé sur SDF: reddit.com/r/gamedev/comments/2879jd/…
Necrolis

Réponses:

7

Adam Simmons a fait un travail intéressant dans ce domaine. Je ne sais pas exactement comment il y est parvenu, mais son rendu vectoriel basé sur SDF est le plus net que j'ai jamais vu dans la pratique en dehors de Valve. http://twitter.com/adamjsimmons/status/611677036545863680

warrenm
la source
Bien sûr, je n’ai pas tous les détails, mais il me semble que cette personne a simplement utilisé un champ de pseudo-distance au lieu d’un champ classique, ce qui a déjà été démontré dans un article de 2006 de Qin, McCool et Kaplan ". Glyphes vectoriels de texture-mappés en temps réel ", qui est également référencé dans le document Valve. Cela n'affecte que les onglets des contours et ne fait rien pour améliorer l'apparence des coins. Je suppose que la raison pour laquelle il a l’air vif est qu’il utilise des textures de champs distants trop grandes. Je peux me tromper cependant.
Detheroc
69

EDIT: S'il vous plaît voir mon autre réponse avec une solution concrète.

En fait, j'ai résolu ce problème il y a un an dans le cadre de ma thèse de maîtrise. Dans le document Valve, ils montrent que vous pouvez ET deux champs de distance pour y parvenir, ce qui fonctionne tant que vous n’avez qu’un seul angle convexe. Pour les angles concaves, vous avez également besoin de l'opération OR. Ce gars a en fait développé un système obscur pour basculer entre les deux opérations en utilisant quatre canaux de texture.

Cependant, il existe une opération beaucoup plus simple qui peut faciliter les opérations ET et OU en fonction de la situation, et telle est l’idée principale de ma thèse: la médiane de trois . Donc, en gros, vous utilisez exactement trois canaux (idéaux pour RGB), qui sont complètement interchangeables, et vous les combinez à l’aide de l’opération médiane (choisissez la valeur moyenne parmi les trois).

Pour prendre en charge l'anti-aliasing, nous ne travaillons pas uniquement avec des booléens, mais avec des valeurs à virgule flottante. L'opération AND devient le minimum et l'OU devient le maximum de deux valeurs. La médiane de trois peut en effet faire les deux: si a < b , pour ( a , a , b ), la médiane est le minimum, et pour ( a , b , b ), il est le maximum.

Le processus de rendu est encore extrêmement simple. Le fragment shader entier, y compris l'anti-aliasing, peut ressembler à ceci:

int main() {
    // Bilinear sampling of the distance field
    vec3 s = texture2D(sdf, p).rgb;
    // Acquire the signed distance
    float d = median(s.r, s.g, s.b) - 0.5;
    // Weight between inside and outside (anti-aliasing)
    float w = clamp(d/fwidth(d) + 0.5, 0.0, 1.0);
    // Combining the background and foreground color
    gl_FragColor = mix(outsideColor, insideColor, w);
}

La seule différence par rapport à la méthode originale est donc de calculer la médiane juste après l'échantillonnage de la texture. Vous devrez cependant implémenter la fonction médiane, ce qui peut être fait avec seulement 4 opérations min / max. .

Maintenant, bien sûr, la question est, savoir comment créer un tel champ de distance à trois canaux.Et c'est la partie la plus délicate. L’approche la plus évidente que j’ai adoptée au début consistait à décomposer la forme / le glyphe d’entrée en trois composantes, puis à générer un champ de distance conventionnel à partir de chacune d’elles. Les règles pour cette décomposition ne sont pas si compliquées. Premièrement, la zone avec au moins 2 canaux sur 3 est l’intérieur. Ensuite, si vous imaginez qu'il s'agit des canaux de couleur RVB, les coins convexes doivent être constitués d'une couleur secondaire et ses deux composants principaux doivent continuer vers l'extérieur. Les coins concaves sont l'inverse: deux couleurs secondaires entourent leur couleur primaire commune et le coin entre les deux bords qui restent à l'intérieur est blanc. J’ai également constaté qu’un certain rembourrage était nécessaire là où deux couleurs primaires ou deux couleurs secondaires se toucheraient sinon pour éviter les artefacts (par exemple, dans le trait du milieu du "N").

L'image suivante est un exemple de décomposition générée par le programme à partir de ma thèse:

Décomposition multicanal de glyphes

Cette approche présente toutefois certains inconvénients. L'un d'eux est que les effets spéciaux, tels que les contours et les ombres, ne fonctionneront plus correctement. Heureusement, j'ai aussi mis au point une seconde méthode, beaucoup plus élégante, qui génère directement les champs de distance et prend même en charge tous les effets graphiques. Il est également inclus dans ma thèse et a donc également plus d'un an. Je ne vais pas donner plus de détails pour le moment, car je suis en train d’écrire un article décrivant cette seconde technique en détail, mais je le posterai ici dès que ce sera terminé.

Quoi qu'il en soit, voici un exemple de la différence de qualité. La résolution de la texture est la même dans chaque image, mais celle de gauche utilise une texture régulière, celle du milieu utilise un champ de distance ordinaire et celle de droite utilise mon champ de distance de trois canaux. Le surcoût lié aux performances n’est que la différence entre l’échantillonnage d’une texture RVB et d’une texture monochrome.

entrez la description de l'image ici

Detheroc
la source
5
Bonne première réponse, bienvenue dans Computer Graphics SE! :) Votre thèse est-elle accessible au public? (Ou est-ce que ce sera après que vous ayez fini votre papier?) Si c'est le cas, il serait probablement très utile de faire un lien vers cela aussi.
Martin Ender
Il est censé être accessible au public, mais il semble que l'école ne l'ait pas encore mis en place. Quoi qu'il en soit, je préférerais ne pas le diffuser pour le moment, car l'article que je rédige expliquera vraiment beaucoup mieux les parties importantes et se concentrera sur la manière de le mettre en œuvre. Il devrait être terminé très bientôt.
Detheroc
@Detheroc S'il vous plaît notifier ici et sur le gamedev Q lorsque vous avez terminé avec l'article. L'explication n'est toujours pas claire pour moi. Je suggérerais de montrer la composition étape par étape en images.
Ingénieur
1
J'adorerais pouvoir reproduire vos résultats actuels même s'ils ne sont pas aussi bons que vos résultats futurs, +1 au partage des détails que vous pouvez. très excitant. Avez-vous envisagé l'application de l'une ou l'autre technique à la marche des rayons (tracé de sphère)? Dans les textures de volume ou similaires ...
Alan Wolfe
4
La thèse est disponible au public ici: dspace.cvut.cz/bitstream/handle/10467/62770/…
Romain Guy
43

Désolé de cette longue attente, mais il est devenu évident que bien que l’article que j’ai promis soit en principe complet, le processus de publication prendra un certain temps. Par conséquent, j'ai plutôt préparé un programme open source avec mon nouvel algorithme de construction de champs de distance multicanaux, msdfgen , que vous pouvez essayer dès maintenant.

Il est disponible sur GitHub: https://github.com/Chlumsky/msdfgen

(Je suis nouveau dans ce domaine, alors faites-le-moi savoir s'il y a un problème avec le référentiel.)

Quelqu'un a également demandé comment il se compare à un champ de distance monochrome plus important. Voici donc un aperçu de la différence de qualité. Cependant, cela dépend vraiment de la police de caractères, et je ne dirais pas que cela vaut toujours les données supplémentaires.

Champ de distance multicanal 16x16 Champ de distance monochrome 32x32

Detheroc
la source
3

Plutôt interessant! Je suis l'auteur du journal sur la distance signé par valve. Désolé que les détails de la mise en œuvre soient un peu clairsemés. J'ai seulement inclus l'exemple des deux canaux en tant que travail futur - je n'avais pas de générateur. Je pensais que quelque chose comme générer un sdf haute résolution puis une segmentation basée sur l'angle de la pente du sdf serait une tactique raisonnable. Mais je n'y suis jamais arrivé. Tous les schémas multicanaux doivent être comparés à l’utilisation de données monocanal de résolution supérieure du même empreinte mémoire, pour les ratios de grossissement requis par votre application.

chris green
la source
0

Je ne suis nullement un expert en la matière, mais vous pourriez peut-être, du moins en théorie, conserver des angles vifs dans un pseudo-SDF monochromatique si vous utilisiez soit un filtre bilatéral, soit un filtre directionnel bicubique au lieu d'un filtre bilinéaire standard. Outre l'avantage évident d'économiser de la mémoire, vous pouvez également disposer de plusieurs canaux pour les décalcomanies SDF multicolores.

Alternativement, si cela ne vous dérange pas d’utiliser un second canal, vous pouvez également essayer d’avoir un canal pour Distance horizontale et un autre pour Distance verticale, et utiliser une pyramide d’énergie Différence de Laplacien (DoL) pour compresser la texture de manière à éviter les informations redondantes. ne pas être enregistré.

Une troisième et dernière solution théorique consisterait à expérimenter une texture échantillonnée de manière hexagonale via l’adressage d’ensembles de tableaux.

Malheureusement, je n'ai actuellement aucun moyen de tester mes idées et n'ai trouvé aucun document décrivant ou testant quelque chose de similaire à mes idées. Je vais relier tous les articles pertinents où j'ai eu mon information / idées sous peu.

Amaroq Starwind
la source