Troika: Schnelle Idee zur Verbesserung des Text-Antialiasing

Erstellt am 17. Juni 2021  ·  7Kommentare  ·  Quelle: protectwise/troika

Ich bin mir nicht sicher, ob Sie den Antialiasing-Code kürzlich aktualisiert haben, da ich eine ältere Version verwende, aber nachdem ich einen guten Weg gefunden hatte, Antialiasing von Shader-gezeichneten Kreisen durchzuführen, wollte ich es auch an Ihrem Text ausprobieren , da der Text SDF-basiert ist und das Antialiasing des Kreises ebenfalls entfernungsbasiert ist.

In meiner aktuellen Version von Troika machst du return length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.5; für die Distanz aa. Dies hat das Artefakt, dass bei schräger Betrachtung die Ränder ganz links und ganz rechts eine etwas sichtbare Unschärfe erhalten:
image

Ich habe es in einen Skalar geändert; die Entfernung, genau wie in meinem Kreiscode: return fwidth(distance) * 0.5; Mit der von troikaGetFragDistValue übergebenen Entfernung so: float distance = troikaGetFragDistValue(); float aaDist = troikaGetAADist(distance);
Wenn ich es so mache, bekomme ich das Unschärfeartefakt nicht:
image

Der Faktor 0.5 kann für ein glatteres Antialiasing erhöht werden. Beispiel 0.8 :
image

Ich dachte, vielleicht kennen Sie diese Methode genauso wenig wie ich, also dachte ich, ich würde sie teilen. Meine "Implementierung" hat jedoch einige seltsame Artefakte (siehe unten), und vielleicht haben Sie sich deshalb für die andere Methode entschieden. Außerdem bin ich mir nicht ganz sicher, wie Sie die aaDist-Variable im Shader-Code verwenden, daher sind Sie möglicherweise besser dafür gerüstet, dies zu implementieren. Vielleicht gibt es Code, der aufgrund dieser Änderung geändert oder entfernt werden sollte, zum Beispiel, der meine "Implementierung" weiter verbessern könnte.

image

Ich habe diese Methode in bgolus 'Beitrag hier gefunden: https://forum.unity.com/threads/antialiasing-circle-shader.432119/ wo es weitere Informationen gibt. Er sagt auch, dass Sie beispielsweise length(vec2(dFdx(distance), dFdy(distance))) anstelle von fwidth(distance) für eine noch größere Genauigkeit verwenden können, obwohl ich mir nicht sicher bin, ob dies vernachlässigbar ist oder nicht.

Alle 7 Kommentare

Danke für den Vorschlag! Ich werde das auf jeden Fall untersuchen, da ich diese unscharfen Kanten auch bei schrägen Winkeln bemerkt habe und sie gerne beseitigen würde.

Theoretisch denke ich, dass sowohl die Änderung in distance als auch die Änderung in vTroikaGlyphUV * vTroikaGlyphDimensions äquivalent sein sollten, da sie beide einen Abstand in Font-Space-Einheiten darstellen, aber es muss einen subtilen Unterschied geben, den ich habe übersehen. Wenn ich die von Ihnen gezeigten Artefakte vermeiden kann, werde ich Ihre Änderung gerne integrieren. :)

Toll! Die Änderung ist so einfach wie diese eine Zeile (und das Übergeben dieses Abstandsarguments, um es aufzunehmen). Wenn Sie immer noch den Rohcode möchten, kann ich ihn morgen senden, wenn ich arbeite.

Theoretisch denke ich, dass sowohl die Änderung der Entfernung als auch die Änderung der vTroikaGlyphUV * vTroikaGlyphDimensions äquivalent sein sollten, da sie beide eine Entfernung in Font-Space-Einheiten darstellen

Ich verstehe nicht genau, wie die Derivate gleich sein sollen. distance ist die SDF-Distanz, denke ich, aber die andere ist eine skalierte UV-Position. Ich habe mir den Code nicht angesehen und wie sie sich vergleichen, aber es fühlt sich an, als ob ihre Ableitungen anders sein sollten. Soweit ich weiß, nimmt fwidth nur die Differenz des als Argument übergebenen spezifischen Eingabewerts mit denselben spezifischen Eingabewerten in den Nachbarfragmenten, was möglich ist, weil die Nachbarfragmente gleichzeitig parallel ausgeführt werden. Ich habe heute früher einen Test mit gl_FragColor.rgb = vec3(fwidth(gl_FragColor.x + gl_FragColor.g + gl_FragColor.b)); durchgeführt, um zu sehen, ob es Kanten wie bei der Kantenerkennung/einem Sobel-Filter gerendert hat, um zu versuchen, diese Tatsache ein wenig zu bestätigen, und das tat es.

Danke für die Diskussion, dieses Zeug bricht mir manchmal das Gehirn. ;)

Als ich sagte, dass sie "äquivalent" sind, meinte ich, dass sie beide eine Entfernung in denselben Einheiten darstellen, aber Sie haben Recht, sie sind nicht genau gleich.

Sichern, was wir hier wollen, ist die _potenzielle_ Änderungsrate zwischen Fragmenten. Die Verwendung der Änderung in der distance -Variablen, wie Sie vorschlagen, ist dafür oft genau, aber in einigen Fällen ist sie sehr ungenau. Dies liegt daran, dass die SDF, aus der dieser Wert abgetastet wird, _nicht einheitlich_ ist; es krümmt sich und ändert seine Änderungsrichtung über die Glyphe. Daher kann die Ableitung von distance zwischen benachbarten Fragmenten viel zu klein werden, sogar Null, wie wenn das Abstandsfeld auf halber Strecke zwischen Glyphenpfaden von zunehmend zu abnehmend wechselt, oder viel zu groß, wie wenn der Text angezeigt wird bei kleinen Größen und das Fragmentgitter überlagert die SDF an unvorhersehbaren Stellen. Ich vermute, das erklärt zumindest einige der Artefakte, die Sie sehen.

Wie können wir also die _potenzielle_ Änderungsrate bestimmen, ohne distance zu verwenden? Nun, diese "skalierte UV-Position", wie Sie sie nennen, ist im Wesentlichen eine x/y-Koordinate innerhalb des Rechtecks ​​der Glyphe, die dieselben Einheiten wie distance verwendet. Die Ableitung dieses x/y gibt uns eine potenzielle Reiserate zwischen Fragmenten. Insgesamt ergibt dies ein besseres Ergebnis als die Verwendung distance , da es auf einer _einheitlichen_ Änderungsrate über die Glyphe basiert und wir daher keine Artefakte erhalten und es bei kleinen Größen genauer ist.

Aber wie Sie gesehen haben, bricht es in schrägen Winkeln zusammen; In diesen Fällen unterscheidet sich die Rate der möglichen x/y-Änderung in der Vertikalen erheblich von der in der Horizontalen. Und so verwenden wir am Ende einen einzelnen Wert für die potenzielle Änderungsrate, der in einer Richtung zu groß und in der anderen zu klein ist, was je nach der tatsächlichen Änderungsrichtung der SDF an diesem Fragment verschwommene und/oder abgehackte Linien ergibt.

Also ja, es gibt definitiv Raum für Verbesserungen im schrägen Fall, aber die Verwendung der Ableitung von distance allein reicht nicht aus. Für Verbesserungsvorschläge bin ich natürlich offen. Eine Möglichkeit könnte sein, zu versuchen, das Szenario zu erkennen (große Textgröße in einem schrägen Winkel, in der Nähe eines Pfads) und die Ableitung distance nur in diesem einen Fall zu verwenden.

Ja, es ist verwirrend, über dieses Zeug nachzudenken, haha. Ich kann sehen, dass das Distanzfeld weniger glatt ist, ja.

Diese fehlerhaften Pixel könnten nur daran liegen, dass die Fragmente da draußen einige seltsame Entfernungswerte haben.

Aus der Ferne ist es nicht unglaublich abgehackt, aber man kann definitiv sehen, dass die UVs besser sind. Vielleicht würde eine Interpolation zwischen der Entfernungsvariablen und den von der Kameraentfernung abhängigen UVs gut funktionieren; Wählen Sie beispielsweise mehr fwidth (Distanz) in der Nähe und mehr fwidth (UV) in der Ferne.

Zum Vergleich (habe die beiden nicht an genau derselben Kameraposition und -ausrichtung aufgenommen, aber ich denke, es zeigt den Unterschied trotzdem gut):
Entfernung (Faktor 0,8):
image
UVs:
image

Ich stelle fest, dass diese Änderung das Ergebnis für benutzerdefinierte Texttransformationen erheblich verbessert. Hier ist etwas Text, der so modifiziert wurde, dass er einer Kurve mit createDerivedMaterial folgt ( siehe diese Technik ). Dies verwendet aktuelle Troika-Drei-Text-Shader:

image

Hier ist der gleiche Screenshot, aber mit der Änderung von @asbjornlystrup zu troikaGetAADist :

image

In der zweiten Einstellung sieht man das extrem gestreckte "GREAT!" ist um einiges schärfer.

Anekdotisch: Ich habe auch festgestellt, dass das Anpassen der Konstante auf 0,25 (von 0,5) auch eine schöne scharfe Kante ergibt:

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

Danke @canadaduane , ich kann definitiv die Verbesserung in den gestreckten Teilen sehen. Ich kann auch die hässlichen Artefakte sehen, die dort zwischen den Ls in HELLO auftauchen, was wir definitiv herausfinden müssten, bevor wir diese Änderung übernehmen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

stephencorwin picture stephencorwin  ·  39Kommentare

Ocelyn picture Ocelyn  ·  13Kommentare

arpu picture arpu  ·  43Kommentare

drcmda picture drcmda  ·  11Kommentare

atlmtw picture atlmtw  ·  47Kommentare