Troika: Feature: Fügen Sie der Textgeometrie Zeichen-/Wort-/Zeilenindexattribute hinzu

Erstellt am 11. Feb. 2021  ·  18Kommentare  ·  Quelle: protectwise/troika

Benutzerdefinierte Shader, die auf Textinstanzen angewendet werden, könnten einige wirklich schöne Animationseffekte ermöglichen. Bei vielen davon möchten Sie jedes Zeichen/Glyphe unabhängig behandeln, und dafür benötigen Sie etwas im Shader, das Ihnen mitteilt, welches Zeichen gerade gerendert wird.

Theoretisch könnte dafür gl_InstanceID verwendet werden, da wir die Instanziierung für die Glyphen-Quads verwenden. Und das irgendwie funktioniert: https://codesandbox.io/s/zealous-water-m8lzq?file=/src/index.js -- aber gl_InstanceID ist nur in WebGL2 verfügbar, und es scheint so zu sein in ANGLE-Implementierungen beschädigt werden, wenn sie in anderen Funktionen als void main verwendet werden. Daher ist es derzeit nicht realistisch verwendbar.

Stattdessen könnten wir unser eigenes Instanzattribut hinzufügen, etwa attribute float charIndex; , das nur einen inkrementierenden Zeichenindex enthält. Benutzerdefinierte Shader könnten dies dann nutzen.

Ich würde es wahrscheinlich zu einer Opt-in-Funktion machen wollen, so etwas wie textmesh.includeCharIndexInShader = true , nur um zu vermeiden, dass dieses zusätzliche Attribut-Array erstellt wird, wenn es nicht benötigt wird.

Hilfreichster Kommentar

Ich muss viel aufräumen, aber ich habe einen anfänglichen POC der oben genannten Punkte. Hier sind Beispiele, die die verschiedenen Index/Gesamt-Paare verwenden, um die Farbe in einem Fragment-Shader zu ändern:

charIndex / totalChars:
Screen Shot 2021-02-18 at 7 18 56 PM

charInWordIndex / totalCharsInWord:
Screen Shot 2021-02-18 at 7 19 01 PM

charInLineIndex / totalCharsInLine:
Screen Shot 2021-02-18 at 7 19 08 PM

wordIndex / totalWords: (sieht in diesem Beispiel charIndex/totalChars sehr ähnlich, aber es gibt einen feinen Unterschied)
Screen Shot 2021-02-18 at 7 19 16 PM

wordInLineIndex / totalWordsInLine:
Screen Shot 2021-02-18 at 7 19 22 PM

lineIndex / totalLines:
Screen Shot 2021-02-18 at 7 19 29 PM

Ich habe es geschafft, alle Daten in maximal 3 Uniformen + 2 Attribute zu bekommen, was ziemlich gut ist. Ich möchte sie immer noch optional machen.

Alle 18 Kommentare

Vielleicht auch: wordIndex , lineIndex ...?

Wort und Zeile würden pro Zeile und pro Wort Animation aktiviert, ähnlich wie https://greensock.com/splittext/ (was wir als gutes Beispiel dafür betrachten können, was diese Änderung ermöglichen würde)

Gehe ich richtig davon aus, dass dies auch Änderungen pro Token (Zeichen, Wort, Zeile) im Fragment-Shader ermöglichen würde?

Gehe ich richtig davon aus, dass dies auch Änderungen pro Token (Zeichen, Wort, Zeile) im Fragment-Shader ermöglichen würde?

Sie müssten es von Scheitelpunkt zu Fragment als Variation übergeben, aber ja. :)

Wir gehen in den Kaninchenbau ...

Ich kann mir Verwendungen für alle folgenden Indizes vorstellen, plus eine Gesamtzahl für jeden:

  • charIndex, totalChars
  • wordIndex, totalWörter
  • lineIndex, totalLines
  • charInWordIndex, totalCharsInWord
  • charInLineIndex, totalCharsInLine
  • wordInLineIndex, totalWordsInLine

Wir möchten all diese Opt-Ins machen und einige intelligente Verpackungen vornehmen, um die Anzahl der neuen glsl-Attribute, die wir einführen, zu minimieren. Über die API muss ich mir da noch Gedanken machen.

wir könnten Benutzer ALLE mit Flags auswählen lassen, also

{
aufgeteilt: { Wörter: wahr, Zeichen: wahr, Zeilen: wahr }
}

etwas kluges Packen tun

Möchtest du das erweitern? Ich bin gespannt 👐

Ich mag diese Idee, Benutzer die Aufteilung(en) wählen zu lassen.

Mit Packen meine ich nur, dass wir nicht 12 neue attribute float foo -Deklarationen hinzufügen wollen, sonst stoßen wir ans Limit (ich glaube, es sind insgesamt 16 Attribute in Webgl), aber wir könnten diese in maximal 3 neue packen attribute vec4 foo -Deklarationen und entpacken Sie sie dann in schöner aussehende float -Variablen innerhalb des Shaders.

Oh ja, macht sehr viel Sinn, danke!

Sollte charIndex Leerzeichen in seine Inkrementierung einbeziehen? Oder nur für sichtbare Glyphen inkrementieren? Ich tendiere zu nur sichtbaren Glyphen.

Das Zählen von Leerzeichen würde beim Animieren nach Index zu seltsamen Staffelungen führen, daher würde ich mich auch in Richtung sichtbar lehnen

Ich muss viel aufräumen, aber ich habe einen anfänglichen POC der oben genannten Punkte. Hier sind Beispiele, die die verschiedenen Index/Gesamt-Paare verwenden, um die Farbe in einem Fragment-Shader zu ändern:

charIndex / totalChars:
Screen Shot 2021-02-18 at 7 18 56 PM

charInWordIndex / totalCharsInWord:
Screen Shot 2021-02-18 at 7 19 01 PM

charInLineIndex / totalCharsInLine:
Screen Shot 2021-02-18 at 7 19 08 PM

wordIndex / totalWords: (sieht in diesem Beispiel charIndex/totalChars sehr ähnlich, aber es gibt einen feinen Unterschied)
Screen Shot 2021-02-18 at 7 19 16 PM

wordInLineIndex / totalWordsInLine:
Screen Shot 2021-02-18 at 7 19 22 PM

lineIndex / totalLines:
Screen Shot 2021-02-18 at 7 19 29 PM

Ich habe es geschafft, alle Daten in maximal 3 Uniformen + 2 Attribute zu bekommen, was ziemlich gut ist. Ich möchte sie immer noch optional machen.

Tolle! Lass es mich wissen, wenn du eine Testversion fertig hast 😄

Ich suchte nach einer Funktion, die dies ansprechen könnte. Ich habe ein paar 3-Buchstaben-Etiketten, die ich um eine Kugel legen kann. Ich lasse sie immer dem Betrachter zugewandt sein und nehme Anpassungen vor, damit sie auf dem Bildschirm immer dieselbe Größe haben, unabhängig von der Skalierung, die in der Ansichtsmatrix oder der Modellierungsmatrix angewendet wird.
Im Moment erstelle ich ein Text -Objekt pro Etikett und wende eine Transformation an.
Ich dachte, ich könnte eine viel bessere Leistung erzielen, indem ich alle Labels in einen einzigen Text packe und ein Attribut habe, das die Position auf der Kugel jedes Labels hat, um die richtigen Transformationen im Vertex-Shader durchzuführen.
@lojjic kannst du dokumentieren, wie man benutzerdefinierte Shader erstellt? Ich denke, das Hinzufügen des Attributs sollte nicht schwierig sein, wie es die vorhandene Methode setAttribute von BufferGeometry tun sollte.

Die andere Option, die ich in Betracht gezogen habe, wäre das instanzierte Rendern, da alle meine Labels alle 3 Buchstaben haben. Aber das würde sicherlich WebGL 2 erfordern und könnte zu komplex sein, um sich zumindest am Anfang zu lohnen.

@FunMiles Ich denke, du hast Recht, das könnte so etwas erleichtern. Wenn ich es richtig verstehe, könnte die Optimierung zwei Teile umfassen:

  1. Verschieben der Rotations-/Skalierungslogik von CPU-seitigem JS zu GPU-seitiger Vertex-Shader-Logik
  2. Dieses _plus_ kombiniert mehrere Textstücke zu einem einzigen Ziehungsaufruf

Zu 1, schau dir diesen Kommentar an, das könnte für deine Bedürfnisse eigentlich schon ausreichen. Das ist auch eine gute Demonstration dafür, wie man einen benutzerdefinierten Shader anwendet, indem man ihn im Grunde nur als material zuweist. Ich habe dort das Dienstprogramm createDerivedMaterial von Troika verwendet, aber Sie könnten auf ähnliche Weise jedes ShaderMaterial oder ein Material mit seinen eigenen onBeforeCompile -Modifikationen übergeben.

Für 2, ich denke, Sie haben Recht, Sie könnten einen einzelnen Text rendern und dann _some_-Attribut verwenden, um einzelne Zeichen um Ihre Kugel zu verschieben. Die neuen char/word-Indexattribute, die in dieser Ausgabe beschrieben werden, können hilfreich sein, aber ich bin mir nicht sicher, ob sie überhaupt notwendig sind. Sie könnten diese Verschiebungen wahrscheinlich einfach in ein neues InstancedBufferAttribute codieren, wobei jeder seiner Vektoren die Verschiebung für ein Zeichen enthält (die Geometrie des Texts ist ein einfaches Quad, das für jede Glyphe instanziiert wird, sodass zusätzliche InstancedBufferAttributes für jede Glyphe durchlaufen werden.)

Ich bin gespannt, ob du dabei Glück hast!

@lojjic Du hast richtig verstanden. Und der von Ihnen verlinkte Code macht 90% von dem, was ich brauche (1). Ihre Demo passt auf unheimliche Weise zu meinem Anwendungsfall.
Wenn ich Sie bitten darf, mein Verständnis zu korrigieren, so sehe ich, was Sie tun:

  • mvPosition wird mit der Referenzpunktposition im Modellansichtsraum initialisiert. Ich nehme an, dass dieser Referenzpunkt der Ankerpunkt ist. Ist das richtig?
  • position ist der Versatz von diesem Referenzpunkt und ich nehme an, es hat nur x- und y-Koordinaten ungleich Null. (Was mich denken lässt, dass Sie die Berechnung der Z-Komponente der Skala überspringen können?) (PS: Wenn Sie sich den Vertex-Shader-Code für das instanzierte Rendering ansehen, scheint es, dass man den Text drehen kann, in diesem Fall ist die Z-Komponente nicht Null.)
  • Die Skalierung in jeder Richtung wird unter der Annahme wiederhergestellt, dass der 3x3-Block nur eine Zusammensetzung aus Skalierung und Drehungen enthält.
  • Das skalierte position wird hinzugefügt, und wenn die z-Komponente Null ist, hält dieser Beitrag die Position in einer Ebene parallel zur Projektionsebene.

Die Änderungen für mich an diesem Code, um nur (1) zu tun, würden hauptsächlich in der Skalierung und einer leichten Koordinatenverschiebung liegen, damit der Text außerhalb der Sphäre bleibt, die ich habe.

2 hast du auch verstanden. Allerdings bin ich etwas verwirrt, wenn ich den Code lese. Ich hatte nicht bemerkt, dass das Text-Rendering bereits Instanz-Rendering ist. Was mich verwirrt, ist, dass GlyphsGeometry von InstancedBufferAttribute ist und dennoch Text eine Unterklasse von Mesh und nicht von InstancedMesh ist. Ich denke, ich muss tiefer in Three.js graben.
Da jedes Zeichen instanziiert ist, bräuchte ich andernfalls nur ein Attribut mit einem Vektor, um position für jede Glypheninstanz auszugleichen. Ist das richtig?

Davon musste ich eine Weile Abstand nehmen, aber hier ist ein kurzes Status-Update:

Die PR #109 fühlt sich ziemlich solide an, wenn es darum geht, die verschiedenen Zählungen zu sammeln und aufzudecken. Ich möchte sie dazu bringen, sich anzumelden, aber ansonsten bin ich zufrieden damit, wo es ist.

Ich habe jedoch eine starke Vermutung, dass Shader-basierte Animationen nicht nur diese neuen Zählwerte erfordern werden, sondern vielleicht auch Zugriff auf einige andere Daten wie:

  • Die Quad-Grenzen der aktuellen Glyphe
  • Gesamtblockgrenzen
  • Font-Metrik-Informationen wie Grundlinie/Oberlänge/Unterlänge, die nicht aus dem Quad abgeleitet werden können
  • Andere?

Einige davon sind technisch bereits im Shader vorhanden, aber wenn Benutzer sich auf sie verlassen wollen, müssen sie mit freundlichen Namen verfügbar gemacht und als zuverlässiger Vertrag dokumentiert werden.

Wenn jemand Zeit hat, mit diesem PR-Zweig zu spielen und zu versuchen, einige Shader-Animationen zu implementieren, und mich wissen lassen, welche Informationen fehlen, wäre das eine große Hilfe.

@lojjic möchte nur mein Interesse an dieser Funktion bekunden 😺

Ich habe einige Zusammenführungskonflikte mit dem neuesten Master hier gelöst: https://github.com/canadaduane/troika/tree/char-indices

Ich hatte noch keine Gelegenheit, es zu testen, habe es aber in den nächsten Tagen vor.

Ich habe mich lange von dieser Diskussion ferngehalten. Ich wurde jedoch gerade daran erinnert, dass ich wieder darauf zurückkommen möchte.
Am Ende dieses Beitrags ist ein Beispiel für etwas, das ich mit createDerivedMaterial gemacht habe.
Im Moment gibt es jedoch ein Mesh pro Label, und wenn die Anzahl der Labels sehr groß wird, wird das Rendering auf Low-End-Telefonen stark ruckelig. Ich gehe davon aus, dass es an den CPU-Aufrufen für jedes Label liegt. Um dies zu beheben, möchte ich die mehreren Meshes durch ein einziges mit allen Labels ersetzen und einen verbesserten Vertex-Shader verwenden, um den Rest zu erledigen.

Ich denke, dass ich, wie @lojjic erwähnte, einige Grenzen für die Wörter benötigen würde. Oder zumindest, für meinen Gebrauch, das Zentrum jedes Wortes.
Irgendwelche anderen Vorschläge, wie man es anders macht oder wie man dieses Zentrum bekommt?

https://flightlog-beta.vercel.app/circles?route=BRU-HER-ATH-IST-AMM-CAI-TUN-CMN-RAK-MAD-LIS-ZRH-GVA-NCE-CDG-DUS-FRA- MUC-LHR-LCY-LGW-DUB-HBA-SYD-MEL-CNS-KTM-DEL-BLR-COK-MAA-CMB-MLE-HKG-HND-NRT-KIX-ICN-GMP-MNL-DPS-JOG- CGK-SIN-KUL-PEN-LGK-BKK-SGN-HAN-LPQ-CNX-DOH-AUH-DXB-JNB-CPT-LVI-ZNZ-JRO-DAR-SSH-BUD-OTP-IPC-SCL-PMC- GRU-EZE-GIG-BSB-LIM-LPB-BOG-PTY-SJO-SJU-CUN-ACA-MEX-MTY-JFK-BOS-PHL-DCA-IAD-BWI-CLT-ATL-MSP-MIA-DFW- DTW-ORD-IAH-COS-DEN-PHX-SAN-LAX-SJC-SFO-SEA-PDX-YVR-YYZ-YUL-LGA-EWR-ASP-BNE-AKL-CHC-ZQN-VIE-SJJ-VCE- MXP-FCO-BCN-PEK-PVG-HNL-OGG-KOA-HIJ-RGN-PBH-TIP-AMS-CPH-SLC-CVG-GSP-TPE-ULN-PNH-VTE-ABQ-BUF-MCO-HKT- MDL-

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

asbjornlystrup picture asbjornlystrup  ·  7Kommentare

drcmda picture drcmda  ·  11Kommentare

lojjic picture lojjic  ·  11Kommentare

atlmtw picture atlmtw  ·  47Kommentare

Ocelyn picture Ocelyn  ·  13Kommentare