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:
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.