Pixi.js: Vorschlag: Verbesserung der Textwiedergabe

Erstellt am 5. Apr. 2020  ·  27Kommentare  ·  Quelle: pixijs/pixi.js

Die Community hat es gesagt - Pixis Text-Rendering-Leistung muss verbessert werden. Diese Ausgabe widmet sich der Frage, wie wir uns verbessern können und was meiner Meinung nach der beste Weg ist, dies zu erreichen:

  • Vorzeichenbehaftete Distanzfelder: Diese Technik rendert den Text in eine Textur (mithilfe der Canvas 2D API) und wendet eine Distanztransformation an. Einfach ausgedrückt, setzt die Distanztransformation den Wert jedes Pixels in der Ausgabetextur auf den Abstand dieses Pixels zum nächsten Umriss des Textes in der Eingabetextur. pixi-sdf-text ist ein Beispiel: https://github.com/PixelsCommander/pixi-sdf-text

  • VTMs: Vektortexturmaps kodieren Kurvendiskontinuitäten auf Pixelebene in Texturen.

  • Exaktes Bezier-Kurven-Rendering: Dies rendert die Schriftart "wie sie ist", indem alles außer den Kurven tesselliert wird. Die Kurven werden mit einem speziellen Fragment-Shader gerendert (es wird kein Sampling der Kurve durchgeführt, sie wird mit Antialiasing exakt auf der GPU gerendert): https://www.microsoft.com/en-us/research/wp-content/uploads /2005/01/p1000-loop.pdf. Ich habe eine Demo für quadratische Bezierkurve erstellt: https://codepen.io/sukantpal/pen/GRJawBg?editors=0010

@bigtimebuddy und ich haben diese Methoden besprochen und wir dachten, der dritte Ansatz ist der beste, weil:

  • SDFs erfordern vorgenerierte Atlanten. Das Generieren von Mehrkanal-SDFs ist sehr kompliziert (wenn wir es zur Laufzeit tun wollen).

  • VTMs sind viel zu kompliziert für nur Schriftarten.

  • Genaue Bezierkurven erfordern lediglich, dass Sie die Schriftart wie alles andere in Graphics als Pfad rendern.

Hilfreichster Kommentar

@eXponenta bitte hör auf so feindselig zu sein. Wir untersuchen Ansätze, noch ist nichts fest. Seien Sie bitte konstruktiv und verwenden Sie keine Beleidigungen.

Alle 27 Kommentare

Es sollte nicht im Kern sein.
Es ist ein schweres Paket und MUSS außerhalb des Hauptpakets implementiert werden, das Kernteam sollte sich keine Sorgen um die Implementierung machen.

Pixi SDF ist das richtige Beispiel.

Bitte versuchen Sie nicht, Phaser aus PIXI . zu machen

Ich möchte etwas mehr Kontext geben. Ich habe @SukantPal gebeten, alternative Text-/BitmapText-Ansätze zu recherchieren, die unterschiedliche Kompromisse aufweisen. Vor allem, wenn wir etwas finden, das besser funktioniert als Text und gut aussieht.

Ich denke, hier gibt es mehrere Ansätze. Einige können als Drittanbieter-Plugins geeignet sein, andere sind möglicherweise im Repository enthalten, aber nicht gebündelt, und einige ersetzen/erweitern möglicherweise die aktuelle API. Lassen Sie uns herausfinden, was der fruchtbarste Text-Rendering-Ansatz ist, der die Leistung optimiert, aber weniger Kompromisse bei BitmapText eingeht.

Es gibt einige Kriterien, die ich verwenden würde, um ein gutes Textanzeigeobjekt zu beurteilen:

  • Gute Laufzeitleistung - Das Rendern von Text und das Ändern von Text ist kostengünstig
  • Geringer Arbeitsspeicher - RAM-Auslastung ist gering
  • Kleine Abhängigkeiten - Dateigröße des Abhängigkeits-Footprints ist klein
  • Great Fidelity - funktioniert gut mit verschiedenen Auflösungen
  • Flexibles Styling - Unterstützung für Striche, Schlagschatten, Farbverläufe
  • Unterstützt große Glyphensprachen - zB Chinesisch, Japanisch, Koreanisch
  • Abwärtskompatibel - Funktioniert mit Context2D

| | Perf | Speicher | Abhängigkeiten | Treue | Styling | CJK | Kontext2d |
|--|--|--|--|--|--|--|--|
|Text| | | | | | | | |
|BitmapText| | | | | | | |

In Ordnung.
Beschreibt fragment interpolation und alle nicht-nativen Implementierungen:

  1. Benötigt zusätzlichen Shader und zusätzliche Daten - das verhindert Batching.
  2. Bei Änderung muss Geometrie neu erstellt werden (S.3).
  3. Erfordert eine Glyphentabelle für alle Glyphen, die in der Sprache vorhanden sind, die erfordern, dass spezifisches TTF vollständig in den Speicher geladen wird, da es kein Streaming unterstützen kann, und dann parsen. Sieht aus wie als SWF.
    Da wir die Systemschriftart nicht als Form laden können, können wir sie nicht verwenden.
  4. Sprachspezifische Regeln werden vom Browser-Team in das lib-Team verschoben, das Rendering-Regeln implementiert: ltr/rtl, Regeln für die Verkettung von hindi/arabischen Glyphen usw. Unity hat es noch nicht richtig umgesetzt.
  5. Schwerer Shader mit zusätzlichen Argumenten zur Unterstützung von Stilen. Das erhöht die Renderkosten, weil wir es in Echtzeit rendern sollten.
    Und natürlich sollten wir es als Textur zwischenspeichern.

@eXponenta

  • Der Text kann gestapelt werden - jedoch nicht mit anderen Dingen wie Grafiken.

  • Die aktuelle Text-Implementierung speichert jede Glyphe mehrmals (wenn ein Buchstabe mehrmals in mehreren PIXI.Texten verwendet wird). Es ist besser, eine Geometrie pro Glyphe zu haben. Außerdem müssen Sie nicht bei unterschiedlichen Schriftgrößen zwischenspeichern.

  • Geometrie muss nicht per se neu erstellt werden - wenn sich die Buchstaben im Text ändern, müssen Sie sie erneut aus der Glyphen-Geometrietabelle abrufen. Wenn sich die Transformation ändert, müssen Sie nur eine Uniform ändern.

  • Wir können eine Bibliothek zum Parsen von Schriftarten verwenden. Die Umrechnung in Geometrie ist trivial.

  • Ich weiß nicht, was Glyphenverkettungsregeln sind. Könntest du erklären?

  • Von links nach rechts vs. von rechts nach links – wenn Sie die Buchstaben umkehren möchten, können Sie dies tun. Wenn Sie ein Spiegelbild wünschen, legen Sie intern scale.x=-1 .

  • Der Textstil fügt dem Shader keine weiteren Argumente hinzu. Es wird die Geometrie ändern. Das Speichern der Glyphe als Geometrie benötigt jetzt _weniger_ Speicher als das Zwischenspeichern in einer Textur.

  • Von APIs abgerufene Schriftdateien sollten auf dem Computer des Benutzers zwischengespeichert werden.

Du bist sehr naiv:

  1. Es sollte ein externer Batcher sein, da Glyphen zusätzliche Attribute erfordern, wie z. B. Bezier-Anker, Schattenwerte, Verlaufsanker ...
  2. von rechts nach links und von links nach rechts, und ihre Mischung ist ein sehr komplexes Problem.
    Geöffnete Probleme in der PDF-Rendering-Bibliothek:
    https://github.com/asciidoctor/asciidoctor-pdf/issues/175
  3. Hindi-Problem (und ähnliche Sprache)
    https://docs.microsoft.com/en-us/typography/opentype/spec/gsub

Wir können keine externen Abhängigkeiten verwenden, da das gleiche Problem wie bei isMobile oder resource-loader .
Kern sollte sauber sein. Minimale externe Abhängigkeiten.

@eXponenta

  • Gemischtes Layout (ltr und rtl kombiniert) hat weniger Priorität als hohe Leistung. Sie können jederzeit auf den aktuellen Algorithmus zurückgreifen. Ähnliches für Devanagari. Spezielle Funktionen wie Gradientenstopps benötigen ebenfalls einen Fallback.

  • Batching kann hier funktionieren, da es ohne Texturen einfacher ist. Kann ein Plugin wie CanvasGraphicsRenderer erstellen.

In Ordnung. Du gewinnst. Tu es. Aber ausserhalb Kern, dann werden wir es uns anschauen und entscheiden, was wir dann machen sollen.
Aber ohne starke Abhängigkeiten.

@eXponenta bitte hör auf so feindselig zu sein. Wir untersuchen Ansätze, noch ist nichts fest. Seien Sie bitte konstruktiv und verwenden Sie keine Beleidigungen.

@eXponenta Sind Sie sicher, dass wir ab sofort Text von rechts nach links unterstützen?

Ein anderer Ansatz, den wir in Betracht ziehen, besteht darin, jede Glyphe mit Canvas 2D (derselbe wie jetzt) ​​separat zu rendern und in einem Atlas zwischenzuspeichern. Der Atlas kann global für alle PIXI.Text Instanzen wiederverwendet werden. Jede Kombination aus Glyphe + Schriftgröße + Schriftstil wird separat zwischengespeichert.

Was halten Sie davon, das in den Kern aufzunehmen?

Hey Leute, es ist wirklich aufregend, diese neuen Ansätze auf dem Tisch zu hören. @eXponenta , Echo von @bigtimebuddy , lass es uns bitte konstruktiv halten. Sie haben offensichtlich einen guten Einblick in den neuen vorgeschlagenen Ansatz, aber lassen Sie uns versuchen, zu sehen, ob wir die angesprochenen Probleme mildern und freundlich bleiben können :)

Auf Text, hier meine 2 Cent (Pence?)..

Persönlich denke ich, dass der wertvollste Ansatz darin besteht, die Geschwindigkeit und Leistung von Bitmap-Text zu steigern, ohne jedoch zuvor eine Bitmap-Schrift erstellen zu müssen. Dynamische Bitmap-Texturerstellung, wenn Sie so wollen!

Dynamische Bitmap-Schriften

Profis

  • Tools zum Erstellen von Bitmap-Schriften sind rar gesät! Würde diese Barriere gerne beseitigen.
  • Wir könnten verschiedene Größen von Textgrößen-Texturen erstellen.
  • Funktioniert mit Leinwand
  • Leistung, da jede Glyphe gestapelt werden kann
  • viele coole Effekte!
  • API müsste nur geringfügig angepasst werden:
const textStyle = new TextStyle({
    font:'comic sans',
    fill:'bright green'
});


const bitmapFont = new BitmapFont(textStyle);

Nachteile

  • alle anderen Nachteile der aktuellen Bitmap-Schriftarten :P
  • würde eine dynamische Aktualisierung des Texturatlas zu einer Verlangsamung führen?

    • Obwohl sich dies nach einer Weile stabilisieren würde und möglicherweise zwischen den Sitzungen zwischengespeichert werden könnte?

    • Aktueller Text muss auch jedes Mal, wenn er den Frame ändert, eine Textur hochladen. Würde dieser Ansatz weniger bewirken?

Ideen

  • Könnte eine Cache-Textur in einem lokalen Speicher generiert werden? für Folgebesuche?
  • Fügen Sie nur Zeichen hinzu, die verwendet werden, damit die Texturen so groß sind, wie sie sein müssen. Aktualisieren Sie, während wir gehen
  • Backen Sie Filter in diese Textur für extra coole Effekte (Umriss, Schatten usw.)
  • können wir den Speicher der Bitmap-Schrift reduzieren, indem wir nicht jede Glyphe zu einem Sprite machen?

SDF
Kann das SDF eine Erweiterung des obigen Ansatzes sein? Wie kompliziert wäre es, diese Textur dynamisch zu generieren? Wäre es super janky? Reden wir davon, die Codebasis um einen großen Betrag zu erhöhen?

Die meisten Leute haben keine Ahnung, was das ist, also sollte es idealerweise versteckt werden. Wenn wir die SDF-Felder extern generieren müssen oder der zum Generieren erforderliche Code zu groß oder komplex ist, dann wäre dies zu Hause als Plugin sicher besser:

const textStyle = new TextStyle({
    font:'comic sans',
    fill:'bright green',
    sdf:true, <----- how sweet would this be, maybe rename to more user friendly like 'cleanEdges'
});

const sdfFont = new BitmapFont(textStyle);

Exaktes Bezier-Kurven-Rendering

Das ist sicher ein interessanter Ansatz! Ich hatte dies in der Vergangenheit untersucht und entschieden, dass die in die Rendering-Schleife eingeführten Shader-Schalter und die zusätzliche erforderliche Tesselation einen großen Overhead verursachen würden. @SukantPal , du bist dieser Idee näher als ich im

Trotzdem lohnt es sich vielleicht, einen Prototypen zu bauen, den wir testen und ein wenig herumschlagen können, um unser Denken zu validieren?

Spannende Zeiten für Text :D

Kann das SDF eine Erweiterung des obigen Ansatzes sein? Wie kompliziert wäre es, diese Textur dynamisch zu generieren? Wäre es super janky? Reden wir davon, die Codebasis um einen großen Betrag zu erhöhen?

Die SDF-Generierung ist teuer und es gibt eine Packzeit (wenn wir verschiedene Schriftarten in Atlas gepackt haben), aber sie kann auf dem Client zwischengespeichert werden (wie alle anderen Varianten).
Es gibt eine Canvas (hehe) Implementierung davon:
https://github.com/mapbox/tiny-sdf
Aber die SDF-Kompilierung ist nicht vollständig korrekt (Glyphenänderung beim Erhöhen/Verringern der Schriftgröße)
Sieht so nützlich aus, aber für MSDF sollten wir es dreimal (pro Kanal) ausführen.

oh wow, das ist ein kleiner Code! Sieht auch reif für einen Shader aus!

@GoodBoyDigital Das tiny-sdf-Paket generiert ein Einzelkanal-Distanzfeld. Es erzeugt keine scharfen Ecken, wenn Sie den Text mit kleineren Schriftgrößen zwischenspeichern. Dies kann durch Caching bei derselben Schriftgröße, die gerendert wird, abgemildert werden.

Die Single-Channel-SDF-Generierung sollte nicht allzu schlecht sein. Das Mehrkanal-SDF ist überlegen, außer dass es viel zu kompliziert ist. Ich konnte nicht verstehen, wie Chumskly Ecken kodierte.

Jetzt wird alles, was wir in Betracht ziehen, kein gemischtes rtl- und Ltr-Layout unterstützen (wie betont hat). Aber ich glaube auch nicht, dass wir es im Moment offiziell unterstützen.

Der genaue Ansatz hat zwei Vorteile - kleine Cachegröße (Sie cachen Scheitelpunkte, nicht alle Pixel), Antialiasing, auch wenn die Einstellung "Antialiasing" deaktiviert ist (von Text wird immer Antialiasing erwartet, denke ich. Die aktuelle Implementierung macht dies durch die Verwendung von Canvas 2D).

Was die Demo betrifft, haben Sie sich meine quadratische Bézierkurven-Demo angesehen? https://codepen.io/sukantpal/pen/GRJawBg?editors=0010

——
Eine andere Sache, die ich und @bigtimebuddy als einfachste Lösung diskutiert haben, war, weiterhin Canvas 2D zu verwenden und die Glyphen in einer Textur zwischenzuspeichern. Die Glyphen können als Quad gerendert werden. Der Cache-Atlas kann zwischen Texten wiederverwendet werden. Dies bedeutet natürlich, dass großer Text mit der gleichen Größe zwischengespeichert wird und daher viel Speicher verbraucht wird, wenn viel Text gerendert wird, aber nur ein Teil davon (wie die aktuelle Seite in PDF) sichtbar ist.

Schön,

Ja, keine Sorge über rtl oder ltr, das immer mit der aktuellen Methode verfügbar sein wird und ein Problem ist, das alle benutzerdefinierten Textwiedergabetechniken zu einem späteren Zeitpunkt lösen müssen.
Diese Entscheidungen. sollte sich idealerweise auf den Speicherverbrauch und die Laufzeitleistung konzentrieren.

Die Bezier-Demo ist cool, aber ich denke, sie reicht nicht aus, um die wahre Komplexität zu verstehen, die sich möglicherweise verbergen kann, wenn wir einen ganzen Satz wiedergeben.

Das, was ich oben über dynamische Bitmapfonts geschrieben habe, ist ziemlich genau das, was Sie über Glyphen-Caching erwähnt haben. Ich denke, das ist definitiv ein nützlicher Weg, um hinunterzugehen!

In Summe:

Die Lösungen für die Bezier-Kurve: Dies könnte eine gute Route sein, aber ich denke, dies erfordert weitere Forschung und Entwicklung, um herauszufinden, wie es in reale Produktionsanwendungsfälle passt.

Dynamische Bitmapfonts von normalen Schriftarten: Dies sollten wir auf jeden Fall erkunden, da wir wissen, dass dies eine gute Leistung bietet und gleichzeitig die API einfach bleibt. Mein Favorit :D

Einkanal-SDF Schätzen Sie, dass es nicht so gut sein wird Mehrkanal-SDF, aber die Demo sah für mich ziemlich gut aus! Wenn Text gut skalieren kann und wir eine Textur pro Schriftart haben können, dann denke ich, dass dieser Weg auch eine Untersuchung wert sein könnte!

@GoodBoyDigital Ich denke, die Demo hat einen ziemlich guten Text. Aber es gibt sichtbare Unterschiede, wenn Sie versuchen, nach Details zu suchen:

Screen Shot 2020-04-06 at 1 34 29 PM

Screen Shot 2020-04-06 at 1 34 35 PM

Der Text oben ist nicht scharf - die Kanten sind wackelig. Jede Kombination aus Schriftart+(~12-15px Unterschiede in der Schriftgröße) muss möglicherweise separat zwischengespeichert werden.

Ich bin völlig einverstanden mit SDF, wenn diese Wackeln unwichtig sind oder wenn wir mit mehreren Schriftgrößen zwischenspeichern können.


Die einfachste Lösung ist auch für mich in Ordnung 💯tbh!

Hey alle zusammen.

Ich bin ein super Laie in Sachen Pixi, aber ich bin ein Benutzer von GDevelop, das Pixi als Backend verwendet, und ich beschäftige mich seit einiger Zeit mit GDevelops Implementierung von PixiJS und Text-Rendering. Es ist tatsächlich beeindruckend für ein Spiel, an dem ich arbeite und das viel Text enthält. (Sie können meine Recherchen/Beispiele in der Ausgabe sehen, die ich in GDevelop gepostet habe: https://github.com/4ian/GDevelop/issues/1449 )

Eine der Optionen, die ich gefunden habe, konzentrierte sich darauf, die Skalierungsprobleme mit Text vollständig zu ignorieren und sie vollständig zu beseitigen, indem die Textskalierung immer auf 100 % belassen wurde, aber stattdessen die Schriftgröße des Textes skaliert wurde? Dies ist schriftunabhängig und scheint bei allen Größen zu funktionieren.

Hier ist ein Codebeispiel, in dem dies mit Pixi geschieht: https://codepen.io/Tazy/pen/wJVExB
Ich habe es in diesem Thread gefunden: https://www.html5gamedevs.com/topic/29576-scalable-text-for-pixijs/

Ich habe tatsächlich ein Kopfgeld für dieses Problem, da ich gehofft hatte, dass jemand einfach die Pixi Text-Erweiterung für GDevelop ändern könnte, aber (als Laie) war mir nicht klar, dass dies ein viel größeres Problem mit Pixi selbst war.

Keine Ahnung, ob es bei dieser Methode potenzielle Probleme gibt, aber sie scheint alle Leistungsprobleme von sdf/msdf/etc.

@Silver-Streak Wenn Sie meinen, die Schriftgröße um die auf das Textanzeigeobjekt angewendete Skalierung zu erhöhen, wie wäre dies dann in Bezug auf die Leistung besser? SDF-Sachen unterstützen die Leistung, da Sie nicht mit größeren Schriftgrößen erneut rendern.

@Silver-Streak Natürlich wird Ihr Vorschlag die _Qualität_ verbessern, aber ich sehe nicht, wie er die Leistung verbessern wird.

@Silver-Streak Natürlich wird Ihr Vorschlag die _Qualität_ verbessern, aber ich sehe nicht, wie er die Leistung verbessern wird.

Wenn ich das nicht falsch verstehe, würde das Ändern der Schriftgröße nicht weniger Ressourcen verbrauchen als das Skalieren des gesamten Objekts oder das Laden in einen anderen Renderer? Auch hier bin ich ein Super-Laie, wenn es darum geht, wie die Skalierung von Pixi tatsächlich funktioniert. Wenn das falsch ist, entschuldigen Sie die Ablenkung.

@Silver-Streak Scaling ist als Transformation implementiert. Sie haben eine Transformationsmatrix - und das Ändern der Skala in dieser Matrix ist eine triviale Operation.

Ab sofort wird der Text mit der Canvas 2D API in eine Leinwand gerendert. Dann wird es auf den Bildschirm kopiert. Das Ändern des Maßstabs ändert nur die Bildschirmkoordinaten, denen der Text in der Leinwand zugeordnet ist.

Ahh, das macht Sinn. Das ist bedauerlich, obwohl mein Problem, um fair zu sein, eher darin besteht, dass die grafische Wiedergabe von Schriftarten nach dem Skalieren unscharf wird, aber ich dachte, es wäre auch eine bessere Leistung.

Obwohl ich mich freuen würde, wenn jemand es implementiert, um die allgemeinen Probleme mit der Textqualität zu beheben, kann ich auch den Wunsch nach Verbesserung der Leistung voll und ganz verstehen.

Danke, dass Sie mit mir darüber gesprochen haben.

@Silver-Streak Kein Problem. Die Implementierung eines Quality-First-Textes sollte jedoch auch in WebGL nicht schwer sein. Einige Anwendungen implementieren Text, indem sie selbst ein Netz erstellen. Sie können die Schriftartdatei parsen, eine Liste von Scheitelpunkten erstellen und sie tessellieren. Diese Scheitelpunkte können durch ein Netz gerendert werden.

Bei hohen Skalen kann dies zu leichten "Kanten" führen - denn letztendlich rendern Sie den Text als Dreiecke. Für eine noch höhere Qualität können Sie den Shader "exact bezier curve" verwenden, über den ich in diesem Thread gesprochen habe - er rendert die Kurven als Kurven und nicht als Dreiecke.

Wenn Sie Hilfe bei der Textqualität benötigen, kann ich Ihnen helfen :)

@SukantPal Ich bin definitiv kein Mitwirkender bei GDevelop (und das würdest du auch nicht wollen. Ich bin hauptsächlich ein Business Systems Analyst/DevOps im Leben, kein Entwickler 😄), obwohl ich dieses Projekt liebe und in der Community aktiv bin . Ich weiß auch, dass andere Mitglieder der Community gerne eine Lösung für skalierte Textqualität sehen würden.

Wenn Sie jedoch einen Blick auf das Thema im Beitrag werfen möchten, habe ich auch ein Kopfgeld dafür auf Bountysource, das für alle offen ist. Ich möchte hier jedoch nicht mehr Kopfraum beanspruchen, da es offensichtlich ist, dass um Pixi im Allgemeinen eine viel tiefere Diskussion stattfindet, und mein Vorschlag war nicht so genau wie ich dachte.

@Silver-Streak Vielleicht schaue ich mal nach, da ich in der Corona-Saison nichts besseres zu tun habe

Ich weiß, dass dies ein geschlossener Thread ist, aber ich bin mir sicher, dass alle immer noch nach der besten Möglichkeit suchen, die Textwiedergabe zu verbessern. Mir ist aufgefallen, dass jemand eine msdf-Implementierung hatte, die mit Pixi v5 funktionierte. https://github.com/cjsjy123/pixi-msdf-text-v5 Ich dachte, ich würde es Interessierten erwähnen.

Dieser Thread sollte auf jeden Fall wieder geöffnet und am Leben gehalten werden - oder zumindest ab und zu ein Update erhalten, da dies eines der am häufigsten gesuchten Probleme ist.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

MRVDH picture MRVDH  ·  3Kommentare

Darker picture Darker  ·  3Kommentare

sntiagomoreno picture sntiagomoreno  ·  3Kommentare

lucap86 picture lucap86  ·  3Kommentare

gigamesh picture gigamesh  ·  3Kommentare