Il y a déjà un certain nombre de questions sur le rendu de texte dans OpenGL, telles que:
Mais surtout, ce qui est discuté est le rendu des quads texturés à l'aide du pipeline à fonction fixe. Les shaders doivent sûrement faire mieux.
Je ne suis pas vraiment préoccupé par l'internationalisation, la plupart de mes chaînes seront des étiquettes de tick de tracé (date et heure ou purement numériques). Mais les tracés seront restitués à la fréquence de rafraîchissement de l'écran et il pourrait y avoir beaucoup de texte (pas plus de quelques milliers de glyphes à l'écran, mais suffisamment pour que la mise en page accélérée par le matériel soit agréable).
Quelle est l'approche recommandée pour le rendu de texte à l'aide d'OpenGL moderne? (Citer un logiciel existant en utilisant l'approche est une bonne preuve qu'il fonctionne bien)
- Shaders de géométrie qui acceptent par exemple la position et l'orientation et une séquence de caractères et émettent des quads texturés
- Shaders de géométrie qui rendent les polices vectorielles
- Comme ci-dessus, mais en utilisant des shaders de pavage à la place
- Un shader de calcul pour effectuer la rastérisation des polices
Réponses:
Le rendu des contours, à moins que vous ne rendiez qu'une douzaine de caractères au total, reste un «non» en raison du nombre de sommets nécessaires par caractère pour approximer la courbure. Bien qu'il y ait eu des approches pour évaluer les courbes de Bézier dans le pixel shader à la place, celles-ci souffrent de ne pas être facilement anti-crénelées, ce qui est trivial en utilisant un quad text-map texturé, et l'évaluation des courbes dans le shader est toujours beaucoup plus coûteuse en calcul que nécessaire.
Le meilleur compromis entre «rapide» et «qualité» sont toujours des quads texturés avec une texture de champ de distance signée. Il est très légèrement plus lent que l'utilisation d'un quadruplet texturé normal, mais pas tellement. La qualité, d'autre part, est dans un tout autre stade. Les résultats sont vraiment étonnants, ils sont aussi rapides que possible et les effets tels que la lueur sont faciles à ajouter. En outre, la technique peut être facilement rétrogradée vers un matériel plus ancien, si nécessaire.
Voir le célèbre papier Valve pour la technique.
La technique est conceptuellement similaire au fonctionnement des surfaces implicites (métaboules et autres), bien qu'elle ne génère pas de polygones. Il fonctionne entièrement dans le pixel shader et prend la distance échantillonnée à partir de la texture comme une fonction de distance. Tout ce qui dépasse un seuil choisi (généralement 0,5) est "in", tout le reste est "out". Dans le cas le plus simple, sur un matériel non compatible avec les shaders vieux de 10 ans, la définition du seuil de test alpha à 0,5 fera exactement la même chose (mais sans effets spéciaux et anti-crénelage).
Si l'on veut ajouter un peu plus de poids à la police (faux gras), un seuil légèrement plus petit fera l'affaire sans modifier une seule ligne de code (il suffit de changer l'uniforme de "font_weight"). Pour un effet de lueur, on considère simplement tout ce qui est au-dessus d'un seuil comme "en" et tout ce qui est au-dessus d'un autre seuil (plus petit) comme "en dehors, mais en lueur", et les LERP entre les deux. L'anticrénelage fonctionne de manière similaire.
En utilisant une valeur de distance signée de 8 bits plutôt qu'un seul bit, cette technique augmente la résolution effective de votre texture map 16 fois dans chaque dimension (au lieu du noir et blanc, toutes les nuances possibles sont utilisées, ainsi nous avons 256 fois la informations utilisant le même stockage). Mais même si vous agrandissez bien au-delà de 16x, le résultat semble tout à fait acceptable. Les longues lignes droites finiront par devenir un peu ondulées, mais il n'y aura pas d'artefacts d'échantillonnage "en bloc" typiques.
Vous pouvez utiliser un shader de géométrie pour générer les quads à partir de points (réduire la bande passante du bus), mais honnêtement, les gains sont plutôt marginaux. La même chose est vraie pour le rendu de caractère instancié comme décrit dans GPG8. Les frais généraux d'instanciation ne sont amortis que si vous avez beaucoup de texte à dessiner. Les gains sont, à mon avis, sans rapport avec la complexité supplémentaire et la non-rétrogradation. De plus, vous êtes soit limité par la quantité de registres constants, soit vous devez lire à partir d'un objet tampon de texture, ce qui n'est pas optimal pour la cohérence du cache (et l'intention était d'optimiser pour commencer!).
Un tampon de vertex simple et simple est tout aussi rapide (peut-être plus rapide) si vous planifiez le téléchargement un peu à l'avance et fonctionnera sur tous les matériels construits au cours des 15 dernières années. Et, il n'est pas limité à un nombre particulier de caractères dans votre police, ni à un nombre particulier de caractères à rendre.
Si vous êtes sûr de ne pas avoir plus de 256 caractères dans votre police, les tableaux de texture peuvent valoir la peine d'être supprimés de la bande passante du bus de la même manière que la génération de quadruples à partir de points dans le shader de géométrie. Lors de l' utilisation d' une texture de matrice, les coordonnées de texture de toutes les quads ont, constante identique
s
et lest
coordonnées et ne diffèrent que par lar
coordination, ce qui est égal à l'indice de caractère à rendre.Mais comme avec les autres techniques, les gains attendus sont marginaux au prix d'être incompatibles avec le matériel de génération précédente.
Il y a un outil pratique par Jonathan Dummer pour générer des textures de distance: page de description
Mise à jour:
comme plus récemment souligné dans Vertex Pulling Programmable (D. Rákos, "OpenGL Insights", pp. 239), il n'y a pas de latence ou de surcharge supplémentaire significative associée à l'extraction de données de vertex par programme à partir du shader sur les dernières générations de GPU, par rapport à faire la même chose en utilisant la fonction fixe standard.
De plus, les dernières générations de GPU ont de plus en plus de caches L2 à usage général de taille raisonnable (par exemple 1536 ko sur nvidia Kepler), donc on peut s'attendre au problème d'accès incohérent lors de l'extraction de décalages aléatoires pour les coins du quadruple à partir d'une texture de tampon étant moins d'un problème.
Cela rend l'idée de l'extraction de données constantes (telles que les tailles quadruples) d'une texture de tampon plus attrayante. Une implémentation hypothétique pourrait ainsi réduire au minimum les transferts PCIe et mémoire, ainsi que la mémoire GPU avec une approche comme celle-ci:
gl_VertexID
, et amplifiez cela à 4 points dans le geometry shader, ayant toujours l'index de caractère et l'id de vertex (ce sera "gl_primitiveID mis à disposition dans le vertex shader") en tant qu'attributs uniques, et capturez-le via un retour de transformation.De cette façon, on pourrait idéalement réduire la bande passante du sommet requise de 75% (amorti), bien qu'il ne puisse rendre qu'une seule ligne. Si l'on voulait pouvoir rendre plusieurs lignes en un seul appel, il faudrait ajouter la ligne de base à la texture du tampon, plutôt que d'utiliser un uniforme (ce qui rend les gains de bande passante plus petits).
Cependant, même en supposant une réduction de 75% - puisque les données de sommet pour afficher des quantités de texte "raisonnables" ne se situent que autour de 50-100 ko (ce qui est pratiquement zéroà un GPU ou à un bus PCIe) - Je doute toujours que la complexité supplémentaire et la perte de rétrocompatibilité en valent vraiment la peine. Réduire le zéro de 75% n'est encore que zéro. Je n'ai certes pas essayé l'approche ci-dessus, et plus de recherches seraient nécessaires pour faire une déclaration vraiment qualifiée. Mais encore, à moins que quelqu'un ne puisse démontrer une différence de performances vraiment étonnante (en utilisant des quantités de texte "normales", pas des milliards de caractères!), Mon point de vue demeure que pour les données de vertex, un simple et ancien tampon de vertex simple est à juste titre assez bon à considérer comme faisant partie d'une "solution de pointe". C'est simple et direct, cela fonctionne et cela fonctionne bien.
Ayant déjà référencé " OpenGL Insights " ci-dessus, il convient également de souligner le chapitre "Rendu de forme 2D par champs de distance" de Stefan Gustavson qui explique le rendu des champs de distance de manière très détaillée.
Mise à jour 2016:
En attendant, il existe plusieurs techniques supplémentaires qui visent à supprimer les artefacts d'arrondi de coin qui deviennent perturbants à des grossissements extrêmes.
Une approche utilise simplement des champs de pseudo-distance au lieu de champs de distance (la différence étant que la distance est la distance la plus courte non pas au contour réel, mais au contour ou à une ligne imaginaire dépassant le bord). C'est un peu mieux et fonctionne à la même vitesse (shader identique), en utilisant la même quantité de mémoire de texture.
Une autre approche utilise la médiane de trois dans une texture à trois canaux et une implémentation disponible sur github . Cela vise à être une amélioration par rapport aux hacks et-ou utilisés précédemment pour résoudre le problème. Bonne qualité, légèrement, presque imperceptiblement, plus lent, mais utilise trois fois plus de mémoire de texture. De plus, les effets supplémentaires (par exemple la lueur) sont plus difficiles à obtenir correctement.
Enfin, le stockage des courbes de Bézier réelles constituant les personnages et leur évaluation dans un fragment shader est devenu pratique , avec des performances légèrement inférieures (mais pas tellement que c'est un problème) et des résultats étonnants, même avec des grossissements les plus élevés.
Démo WebGL rendant un grand PDF avec cette technique en temps réel disponible ici .
la source
clip(...)
ligne parif (text.a < 0.5) {discard;}
(outext.a < threshold
). HTH.http://code.google.com/p/glyphy/
L'inconvénient est que le code est pour iOS avec OpenGL ES. Je vais probablement créer un port Windows / Linux OpenGL 4.x (j'espère que l'auteur ajoutera une vraie documentation, cependant).
la source
La technique la plus répandue reste les quads texturés. Cependant, en 2005, LORIA a développé ce qu'on appelle des textures vectorielles, c'est-à-dire le rendu de graphiques vectoriels sous forme de textures sur des primitives. Si l'on utilise cela pour convertir les polices TrueType ou OpenType en une texture vectorielle, vous obtenez ceci:
http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005
la source
Je suis surpris que le bébé de Mark Kilgard, NV_path_rendering (NVpr), n'ait été mentionné par aucun des éléments ci-dessus. Bien que ses objectifs soient plus généraux que le rendu de polices, il peut également restituer du texte à partir de polices et avec crénage. Il ne nécessite même pas OpenGL 4.1, mais il s'agit pour le moment d'une extension fournisseur / Nvidia uniquement. Il transforme essentiellement les polices en chemins en utilisant
glPathGlyphsNV
ce qui dépend de la bibliothèque freetype2 pour obtenir les métriques, etc. Ensuite, vous pouvez également accéder aux informations de crénage avecglGetPathSpacingNV
et utiliser le mécanisme général de rendu de chemin de NVpr pour afficher le texte à l'aide des polices "converties" par chemin. (Je mets cela entre guillemets, car il n'y a pas de véritable conversion, les courbes sont utilisées telles quelles.)La démo enregistrée pour les capacités de police de NVpr n'est malheureusement pas particulièrement impressionnante. (Peut-être que quelqu'un devrait en faire un sur le modèle de la démo SDF beaucoup plus brillante que l' on peut trouver sur les intertubes ...)
La présentation de présentation de l'API NVpr 2011 pour la partie polices commence ici et se poursuit dans la partie suivante ; il est un peu regrettable que cette présentation soit divisée.
Matériaux plus généraux sur NVpr:
Et puisque le mot "stencil" n'a pas produit de résultats sur cette page avant ma réponse, il semble que le sous-ensemble de la communauté SO qui a participé sur cette page dans la mesure où, bien qu'il soit assez nombreux, n'était pas au courant de la tessellation-free, stencil-buffer- méthodes basées sur le rendu de chemin / police en général. Kilgard a un post de type FAQ sur le forum opengl qui peut montrer comment les méthodes de rendu de chemin sans pavage diffèrent des graphiques 3D standard, même s'ils utilisent toujours un GPU [GP]. (NVpr a besoin d'une puce compatible CUDA.)
Pour une perspective historique, Kilgard est également l'auteur du classique "A Simple OpenGL-based API for Texture Mapped Text", SGI, 1997 , qui ne doit pas être confondu avec le NVpr basé sur pochoir qui a fait ses débuts en 2011.
La plupart sinon toutes les méthodes récentes discutées sur cette page, y compris les méthodes basées sur le pochoir comme NVpr ou les méthodes basées sur SDF comme GLyphy (dont je ne parle pas plus ici car d'autres réponses le couvrent déjà) ont cependant une limitation: elles sont Convient pour un affichage de texte volumineux sur des moniteurs conventionnels (~ 100 DPI) sans jaggies à n'importe quel niveau de mise à l'échelle, et ils ont également fière allure, même à petite taille, sur des écrans rétiniens à haute résolution. Cependant, ils ne fournissent pas entièrement ce que Microsoft Direct2D + DirectWrite vous donne, à savoir des petits glyphes sur les écrans grand public. (Pour un aperçu visuel des indices en général, consultez cette page de typothèque par exemple. Une ressource plus approfondie se trouve sur antigrain.com .)
Je ne connais aucun élément basé sur OpenGL ouvert et productif qui puisse faire ce que Microsoft peut faire avec des indices pour le moment. (J'avoue ignorer les composants internes d'OS X GL / Quartz d'Apple, car à ma connaissance, Apple n'a pas publié comment ils effectuent le rendu des polices / chemins basé sur GL. Il semble que OS X, contrairement à MacOS 9, ne le fasse pas. faire des allusions du tout, ce qui agace certaines personnes .) Quoi qu'il en soit, il existe un article de recherche de 2013 qui traite des allusions via des shaders OpenGL écrits par Nicolas P. Rougier de l'INRIA; cela vaut probablement la peine d'être lu si vous avez besoin de faire des suggestions à partir d'OpenGL. Bien qu'il puisse sembler qu'une bibliothèque comme freetype fasse déjà tout le travail en matière d'indices, ce n'est pas vraiment le cas pour la raison suivante, que je cite dans l'article:
La solution n'est pas exactement triviale, donc je ne vais pas essayer de l'expliquer ici. (Le document est en libre accès.)
Une autre chose que j'ai apprise de l'article de Rougier (et que Kilgard ne semble pas avoir pris en compte) est que les pouvoirs de police en place (Microsoft + Adobe) ont créé non pas une mais deux méthodes de spécification de crénage. L'ancien est basé sur une soi-disant table kern et il est pris en charge par freetype. Le nouveau s'appelle GPOS et n'est pris en charge que par les bibliothèques de polices plus récentes comme HarfBuzz ou pango dans le monde du logiciel libre. Comme NVpr ne semble prendre en charge aucune de ces bibliothèques, le crénage peut ne pas fonctionner avec NVpr pour certaines nouvelles polices; il y en a apparemment dans la nature, selon ce forum de discussion .
Enfin, si vous devez faire une mise en page de texte complexe (CTL), vous semblez actuellement malchanceux avec OpenGL car aucune bibliothèque basée sur OpenGL ne semble exister pour cela. (DirectWrite, d'autre part, peut gérer CTL.) Il existe des bibliothèques open source comme HarfBuzz qui peuvent rendre CTL, mais je ne sais pas comment les faire fonctionner correctement (comme dans l'utilisation des méthodes basées sur le pochoir) via OpenGL. Vous devrez probablement écrire le code de la colle pour extraire les contours remodelés et les alimenter en solutions basées sur NVpr ou SDF en tant que chemins.
la source
Je pense que votre meilleur pari serait d'examiner les graphiques du Caire avec le backend OpenGL.
Le seul problème que j'ai eu lors du développement d'un prototype avec le noyau 3.3 était l'utilisation obsolète des fonctions dans le backend OpenGL. C'était il y a 1-2 ans donc la situation aurait pu s'améliorer ...
Quoi qu'il en soit, j'espère que dans le futur, les pilotes graphiques opengl implémenteront OpenVG.
la source