Scharfe Ecken mit vorzeichenbehafteten Abstandsfeldern


49

Signed Distance Fields (SDFs) wurden in diesem Artikel als schnelle Lösung vorgestellt, um eine auflösungsunabhängige Schriftwiedergabe durch Valve zu erzielen .

Ich habe bereits die Valve-Lösung im Einsatz, möchte aber die Schärfe um Ecken erhalten. Valve gibt an, dass mit seiner Methode scharfe Ecken erzielt werden können, indem zweite Texturkanäle UND-verknüpft mit dem Basiskanal verwendet werden. Es fehlt jedoch eine Erläuterung, wie dieser zweite Kanal erzeugt werden würde.

Tatsächlich wurden in diesem Dokument viele Implementierungsdetails ausgelassen.

Ich würde gerne wissen, ob jemand von Ihnen mir eine Anweisung geben kann, wie man SDFs mit scharfen Ecken rendern kann.


Tatsächlich hat Adam bereits Quellcode auf shadertoy gepostet. Hier ist der Link: shadertoy.com/view/ltXSDB
Felipe Lira

Du hattest mich aufgeregt. Er hat das Bezier-Zeug auf Shadertoy gepostet, aber nicht das Texture-Distance-Field-Zeug!
Alan Wolfe

@AlanWolfe Ich denke, er hat nur für prozedural eingestellte Bezierkurven getan. Ich bin mir nicht sicher, wie viel Aufwand erforderlich ist, um dies in eine ttf render lib zu integrieren. Wenn ich etwas Zeit habe, werde ich es mir ansehen.
Felipe Lira

Es sieht so aus, als hätte er eine magische Sauce, um die Entfernungen von einer Textur tatsächlich zu speichern und abzurufen. Ohne eine Textur im Spiel fehlt in den Shadertoy-Beispielen dieser Teil der Gleichung.
Alan Wolfe

Etwas zu spät zur Party, aber dieser ältere Thread von reddit bietet eine Menge
Necrolis

Antworten:


7

Adam Simmons hat in diesem Bereich interessante Arbeit geleistet. Ich weiß nicht genau, wie er es erreicht, aber sein SDF-basiertes Vektor-Rendering ist das schärfste, das ich außerhalb von Valve in der Praxis gesehen habe. http://twitter.com/adamjsimmons/status/611677036545863680


Natürlich habe ich nicht alle Details, aber es scheint mir, dass diese Person lediglich ein Pseudodistanzfeld anstelle eines regulären verwendet hat, was bereits in einem Artikel von Qin, McCool und Kaplan aus dem Jahr 2006 gezeigt wurde. " Echtzeit-Textur-gemappte Vektor-Glyphen ", auf die auch im Valve-Artikel verwiesen wird. Es wirkt sich nur auf die Gehrungen von Konturen aus und trägt nicht zur Verbesserung des Erscheinungsbilds von Ecken bei. Ich vermute, der Grund, warum es scharf aussieht, ist, dass er unpraktisch große Abstandsfeldtexturen verwendet. Ich könnte mich jedoch irren.
Detheroc

69

EDIT: Bitte sehen Sie meine andere Antwort mit einer konkreten Lösung.

Genau dieses Problem habe ich vor über einem Jahr für meine Masterarbeit gelöst. Im Valve-Artikel wird gezeigt, dass Sie zwei Distanzfelder UND-verknüpfen können, um dies zu erreichen. Dies funktioniert, solange Sie nur eine konvexe Ecke haben. Für konkave Ecken benötigen Sie auch die ODER-Operation. Dieser Typ hat tatsächlich ein undurchsichtiges System entwickelt, um mit vier Texturkanälen zwischen den beiden Operationen umzuschalten.

Es gibt jedoch eine viel einfachere Operation, die je nach Situation UND und ODER erleichtert, und dies ist die Grundidee meiner These: der Median von drei . Im Grunde genommen verwenden Sie genau drei Kanäle (ideal für RGB), die vollständig austauschbar sind, und kombinieren sie mithilfe der Median-Operation (wählen Sie den Mittelwert aus den drei).

Um Antialiasing zu ermöglichen, arbeiten wir nicht nur mit Booleschen Werten, sondern mit Gleitkommawerten. Die UND-Verknüpfung wird zum Minimum und das ODER zum Maximum von zwei Werten. Der Median von drei kann in der Tat beides: Wenn a < b für ( a , a , b ) ist, ist der Median das Minimum und für ( a , b , b ) das Maximum.

Der Rendering-Prozess ist immer noch extrem einfach. Der gesamte Fragment-Shader einschließlich Antialiasing kann ungefähr so ​​aussehen:

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);
}

Der einzige Unterschied zur ursprünglichen Methode besteht also darin, den Median direkt nach dem Abtasten der Textur zu berechnen. Sie müssen jedoch die Medianfunktion implementieren, die mit nur 4 min / max-Operationen durchgeführt werden kann .

Nun ist natürlich die Frage, wie ich ein solches dreikanaliges Distanzfeld aufbaue.Und das ist der schwierige Teil. Der naheliegendste Ansatz, den ich am Anfang gewählt habe, war, eine Zerlegung der Eingabeform / Glyphe in drei Komponenten durchzuführen und dann aus jeder ein herkömmliches Distanzfeld zu erzeugen. Die Regeln für diese Zerlegung sind nicht so kompliziert. Erstens ist der Bereich mit mindestens 2 von 3 Kanälen innen. Wenn Sie sich dies als RGB-Farbkanäle vorstellen, müssen die konvexen Ecken aus einer Sekundärfarbe bestehen und die beiden Primärkomponenten nach außen fortgesetzt werden. Konkave Ecken sind die Umkehrung: Zwei Sekundärfarben umschließen ihre gemeinsame Primärfarbe, und der Keil zwischen den beiden nach innen verlaufenden Kanten ist weiß. Ich habe auch festgestellt, dass eine gewisse Polsterung erforderlich ist, wenn sich zwei Primär- oder zwei Sekundärfarben berühren würden, um Artefakte zu vermeiden (z. B. im mittleren Strich des "N").

Das folgende Bild ist eine Beispielzerlegung, die vom Programm aus meiner Diplomarbeit generiert wurde:

Mehrkanalzerlegung von Glyphen

Dieser Ansatz hat jedoch einige Nachteile. Eine davon ist, dass die Spezialeffekte wie Konturen und Schatten nicht mehr richtig funktionieren. Glücklicherweise habe ich mir auch eine zweite, viel elegantere Methode ausgedacht, die die Distanzfelder direkt generiert und sogar alle grafischen Effekte unterstützt. Es ist auch in meiner Diplomarbeit enthalten und somit auch über ein Jahr alt. Ich werde im Moment keine weiteren Details angeben, da ich gerade einen Artikel schreibe, der diese zweite Technik ausführlich beschreibt, aber ich werde ihn hier veröffentlichen, sobald er fertig ist.

Hier ist ein Beispiel für den Qualitätsunterschied. Die Texturauflösung ist in jedem Bild gleich, aber das linke verwendet eine reguläre Textur, das mittlere ein normales Distanzfeld und das rechte mein dreikanaliges Distanzfeld. Der Leistungsaufwand ist nur der Unterschied zwischen dem Abtasten einer RGB-Textur und einer monochromen Textur.

Bildbeschreibung hier eingeben


5
Tolle erste Antwort, willkommen bei der Computer Graphics SE! :) Ist Ihre Arbeit öffentlich zugänglich? (Oder wird es sein, nachdem Sie das Paper fertiggestellt haben?) Wenn ja, wäre es wahrscheinlich sehr hilfreich, auch darauf zu verlinken.
Martin Ender

Es soll öffentlich verfügbar sein, aber es scheint, dass die Schule es noch nicht eingerichtet hat. Wie auch immer, ich würde es vorziehen, es jetzt nicht zu verbreiten, da der Artikel, den ich schreibe, die wichtigen Teile viel besser erklärt und sich darauf konzentriert, wie man es implementiert, und es sollte sehr bald fertig sein.
Detheroc

@Detheroc Bitte benachrichtige hier und auf dem gamedev Q, wenn du mit dem Artikel fertig bist. Die Erklärung ist für mich immer noch nicht 100% klar. Ich würde vorschlagen, die Komposition schrittweise in Bildern darzustellen.
Ingenieur

1
Ich würde gerne in der Lage sein, Ihre aktuellen Ergebnisse zu replizieren, auch wenn sie nicht so gut sind wie Ihre zukünftigen Ergebnisse. sehr aufregend. Haben Sie die Anwendung einer der beiden Techniken für das Strahlenmarschieren (Sphere Tracing) in Betracht gezogen? In Volumen Texturen oder ähnliches ...
Alan Wolfe

4
Die Dissertation ist hier öffentlich verfügbar: dspace.cvut.cz/bitstream/handle/10467/62770/…
Romain Guy

43

Entschuldigen Sie das lange Warten, aber es hat sich gezeigt, dass der Veröffentlichungsprozess einige Zeit in Anspruch nehmen wird, obwohl der Artikel, den ich versprochen habe, im Grunde genommen vollständig ist. Daher habe ich stattdessen ein Open-Source-Programm mit meinem neuen Mehrkanal-Entfernungsfeldkonstruktionsalgorithmus msdfgen erstellt , das Sie jetzt ausprobieren können.

Es ist auf GitHub verfügbar: https://github.com/Chlumsky/msdfgen

(Ich bin neu in diesem Bereich, also lass es mich bitte wissen, wenn irgendetwas mit dem Repository nicht stimmt.)

Jemand fragte auch, wie es sich mit einem größeren monochromen Distanzfeld vergleichen lässt. Hier ist ein Anhaltspunkt für den Qualitätsunterschied. Es hängt jedoch wirklich von der jeweiligen Schriftart ab, und ich würde nicht sagen, dass es die zusätzlichen Daten immer wert ist.

Mehrkanal-Distanzfeld 16x16 Monochromes Distanzfeld 32x32


3

Ziemlich interessant! Ich bin der Autor des von Ventilen signierten Distanzpapiers. Es tut uns leid, dass die Implementierungsdetails etwas spärlich sind. Ich habe nur das Zweikanal-Beispiel als zukünftige Arbeit aufgenommen - ich hatte keinen Generator. Ich dachte, es wäre eine vernünftige Taktik, eine hochauflösende SDF zu generieren und dann basierend auf dem Gradientenwinkel der SDF zu segmentieren. Aber ich bin nie dazu gekommen. Jedes Mehrkanalschema muss gegen die Verwendung von Einzelkanaldaten mit höherer Auflösung und gleichem Speicherbedarf abgewogen werden, um die Vergrößerungsverhältnisse zu erzielen, die Ihre App benötigt.


0

Ich bin kein Experte auf diesem Gebiet, aber Sie könnten zumindest theoretisch in der Lage sein, scharfe Ecken in einem monochromatischen Pseudo-SDF beizubehalten, wenn Sie entweder einen bilateralen Filter oder einen direktionalen bikubischen Filter anstelle eines standardmäßigen bilinearen Filters verwenden. Neben dem offensichtlichen Vorteil, Speicherplatz zu sparen, können Sie auch mehrere Kanäle für mehrfarbige SDF-Abziehbilder verwenden.

Wenn es Ihnen nichts ausmacht, einen zweiten Kanal zu verwenden, können Sie auch versuchen, einen Kanal für die horizontale Entfernung und einen anderen für die vertikale Entfernung zu verwenden und die Textur mithilfe einer Laplace-Energiepyramide (Difference of Laplacean, DoL) so zu komprimieren, dass redundante Informationen verloren gehen nicht aufgezeichnet werden.

Eine dritte und letzte theoretische Lösung wäre das Experimentieren mit einer hexagonal abgetasteten Textur über Array-Set-Adressierung.

Leider habe ich derzeit keine Möglichkeit, meine Ideen zu testen, und konnte keine Dokumente finden, die etwas Ähnliches zu meinen Ideen beschreiben oder testen. Ich werde in Kürze alle relevanten Artikel verlinken, in denen ich meine Informationen / Ideen erhalten habe.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.