AAA – Analytical Anti-Aliasing-Technik
(blog.frost.kiwi)- Jaggies und Pixel Crawling, die bei der Rasterisierung entstehen, fallen in Bewegung stärker auf als in Standbildern; der Artikel vergleicht mehrere Anti-Aliasing-Methoden anhand einer WebGL-Kreis-Demo
- SSAA, MSAA und FXAA haben jeweils unterschiedliche Einschränkungen: Downsampling-Kosten, Hardware-Abhängigkeit und formverzerrendes Post-Processing
- Analytical Anti-Aliasing berechnet, wenn die mathematische Grenze einer Form bekannt ist, mit einem signed distance field den Abstand zur Kante und lässt den Bereich um die Kante über 1 Pixel Breite per Alpha-Fade auslaufen
- Die Pixelgröße lässt sich in 2D direkt aus Objekt- und Rendering-Größe berechnen; bei 3D-Perspektive sind Screen-Space Derivatives wie
dFdx,dFdyundfwidthnötig - Es ist auch ohne zusätzliche Buffer oder spezielle Hardware in WebGL 1.0/OpenGLES 2.0 umsetzbar, benötigt aber das SDF der gesamten Form und stößt bei hochfrequenten Strukturen unterhalb von 1 Pixel an Grenzen
Anti-Aliasing anhand einer WebGL-Kreis-Demo
- Ziel des Artikels ist es, verschiedene Anti-Aliasing-Techniken zur Reduzierung der bei der Rasterisierung auftretenden Jaggies zu betrachten und am Ende eine Implementierung von Analytical Anti-Aliasing vorzustellen
- Verglichen werden der Reihe nach SSAA, MSAA, FXAA, die MLAA/SMAA-Familie und AAA
- Die Demo zeichnet einen bewegten Kreis auf einem WebGL-Canvas und geht davon aus, dass Anti-Aliasing eher über Bewegung als über Standbilder verstanden werden sollte
- Das Beispiel-Canvas rendert in der nativen Geräteauflösung, während die rote Box eine 4-fach vergrößerte Ansicht bietet
- Für hochauflösende Displays, auf denen Aliasing schwer zu erkennen ist, gibt es Umschaltungen zwischen den Renderauflösungen Native, 1/2, 1/4 und 1/8; dabei wird Integer Scaling verwendet
Probleme des einfachen Kreis-Renderings
- Das einfachste Kreis-Rendering gibt im Fragment Shader eine Farbe aus, wenn
length(uv) < 1.0gilt, und führt andernfallsdiscardaus - Der Kreis hängt nicht von der tatsächlichen Geometrieauflösung ab; der Shader entscheidet auf einem aus 4 Vertices gebildeten Quad, ob ein Fragment innerhalb oder außerhalb des Kreises liegt
varying vec2 uvwird pro Fragment interpoliert und liefert Koordinaten mit Zentrum 0 und einem Bereich von -1 bis +1- Diese Methode entspricht Alpha Testing; der Wert
length(uv)steht in Verbindung mit dem signed distance field, das später bei AAA verwendet wird - Bei niedriger Auflösung wirkt der Kreis blockig, und in Bewegung treten Pixel Crawling sowie starkes Wobbeln deutlich hervor, bei dem Pixelzeilen erscheinen und wieder verschwinden
- Die Auflösungen 1/4 und 1/8 dienen nicht nur als einfache Vergrößerung, sondern auch als Beispiel für kleine oder weit entfernte Elemente in 3D
SSAA: einfaches, aber teures Downsampling
- SSAA steht für Super Sampling Anti-Aliasing: Es wird in höherer Auflösung gerendert und anschließend kleiner heruntergerechnet
- Die Beispielimplementierung zeichnet den Kreis in eine Texture der Größe
(canvas.width / resDiv) * 2×(canvas.height / resDiv) * 2, sampelt sie in einen Framebuffer mit Standardauflösung herunter und blitted das Ergebnis auf den Bildschirm - Rendering mit doppelter Auflösung nutzt pro Ausgabepixel 4 Eingabepixel, wodurch Speicherbedarf und Rechenaufwand um den Faktor 4 steigen
- Im konkreten Beispiel tritt Anti-Aliasing auf, wirkt aber schwächer als erwartet
- Eigentlich sollte es 4 Transparenzstufen geben, beobachtet werden in manchen Bereichen aber nur 2 Stufen
- Bei niedriger Auflösung erscheinen die 4 Transparenzstufen vor allem in der Nähe von 45-Grad-Diagonalen
- Im achsenausgerichteten unteren Bereich sind nur vollständig deckende und 50 % transparente Pixel zu sehen; die Stufen 25 % und 75 % fehlen
- Ursache ist, dass nicht die Kreisform selbst in doppelter Auflösung gesampelt wird, sondern ein bereits quantisiertes Kreisergebnis erneut gesampelt wird
- Da die Beispielimplementierung eine 2x-Resolution-Texture und lineare Interpolation verwendet, nutzt sie tatsächlich die 5-fache Menge an VRAM
- Korrektes SSAA sampelt die Scene mehrfach ohne Zwischenbuffer und kombiniert die Ergebnisse, was eine tiefe Integration in die Rendering-Pipeline erfordert
MSAA: Vor- und Nachteile hardwarebasierter Abtastung
- MSAA ist eine Form von Supersampling, wird aber hauptsächlich bei Modellsilhouetten, überlappender Geometrie und Texture-Kanten mit aktiviertem Alpha to Coverage angewendet
- Die Implementierung hängt von GPU-Hardware und Grafikhersteller ab; der Support variiert je nach Hardware und Treiber
- WebGL 1 unterstützt kein MSAA, daher verwendet das Beispiel einen WebGL-2-Context
- Die Beispiel-UI vergleicht No MSAA, 2x, 4x, 8x, 16x, 32x und 64x sowie die Renderauflösungen Native, 1/2, 1/4 und 1/8
- Mit
gl.MAX_SAMPLESwird die maximal unterstützte Sample-Anzahl ausgelesen, und nur auswählbare Optionen werden aktiviert - Auf mobilen GPUs kann ein Aufruf von
renderbufferStorageMultisample()tatsächlich auf 4x MSAA erzwungen werden- Android erlaubt zwar die Auswahl von 2x, der Treiber erzwingt aber 4x
- Auf iPhone und iPad wird eine 2x-Auswahl zu 4x; Transparenz wird auf Werte gerundet, die nahe an Vielfachen von 50 % liegen, wodurch im Beispiel doppelte Kanten entstehen
- Da MSAA der Hardware überlassen wird, unterstützt das Gerät des Nutzers die benötigten Funktionen möglicherweise nicht
- Das Sampling-Muster kann unerwartete Ergebnisse erzeugen, und je nach Hardware können die Transparenzstufen am Kreisrand in „falscher Reihenfolge“ erscheinen
- Unter bestimmten Bedingungen bleibt MSAA dennoch leistungsfähig
- Forward Rendering
- nicht zu dichte Geometrie
- GPUs mit Tile-Based Rendering Architecture
- Rahul Prasad erklärt, dass MSAA auf Mobilgeräten nicht so teuer ist wie auf Desktops und dass 4x MSAA auf manchen mobilen GPUs kostenlos sein kann
- Als weiteres Material wird der MSAA color resolve deep-dive der KhronosGroup Vulkan-Samples erwähnt
Der Post-Processing-Pfad über MLAA, SMAA und FXAA
- Ein Paper von Alexander Reshetov aus dem Jahr 2009 stellte einen Ansatz vor, der in blockigen Aliasing-Bildern Kanten findet und blockige Kanten mithilfe von Filterregeln je nach Pixelform reduziert
- Dieser morphologiebasierte Ansatz führte zu MLAA und wurde später zu SMAA weiterentwickelt, das sich stärker auf die Entfernung von Sub-Pixel-Artefakten konzentriert
- Einige Nutzer empfanden die MLAA/SMAA-Familie als zu unscharf, woraus die Formulierung „vaseline on the screen“ entstand
- Post-Processing-Anti-Aliasing zeigt die Entwicklung weg von unsicherem Hardware-Support hin zu shaderbasiertem AA
FXAA 3.11: Struktur und Grenzen von schnellem Post-Processing-AA
- FXAA ist Timothy Lottes’ Algorithmus Fast Approximate Anti-Aliasing und wurde von MLAA inspiriert
- Die letzte veröffentlichte Version ist FXAA 3.11; die Demo basiert auf der am 12. August 2011 veröffentlichten Version
- Die Demo vergleicht die Kreisszene in den Auflösungen Native, 1/2, 1/4 und 1/8
- Die Standardeinstellungen verwenden
FXAA_PC 1,FXAA_QUALITY_PRESET 12,fxaaQualitySubpix 0.75,fxaaQualityEdgeThreshold 0.166undfxaaQualityEdgeThresholdMin 0.0833 - FXAA sampelt zunächst die Luminanz des zentralen Pixels sowie der Pixel oben, unten, links und rechts; wenn der lokale Kontrast unter dem Schwellenwert liegt, wird das ursprüngliche Pixel zurückgegeben
- Falls kein Early Exit erfolgt, werden auch die diagonalen Luminanzwerte gesampelt; anschließend wird die horizontale bzw. vertikale Kantenrichtung berechnet und in beide Richtungen gesucht, um die Enden der Kante zu finden
- Am Ende werden die Pixelkoordinaten verschoben und mit
texture2Dgesampelt; laut offiziellem Whitepaper handelt es sich nicht einfach um ein Blurring von Kanten - In der Kreis-Demo wirken die Kanten im Stand glatt, doch wenn sich der Kreis bewegt, verformt sich die Form
- An den achsenausgerichteten oberen und unteren Bereichen erscheinen und verschwinden kleine Ausbuchtungen
- Bei niedriger Auflösung verliert der Kreis seine runde Form und wackelt wie PlayStation-1-Grafik
- Da pro Pixel nur die 3x3-Nachbarschaft berücksichtigt wird, kann nicht erkannt werden, dass dieser Bereich Teil eines großen Kreises ist
- FXAA wurde entwickelt, um komplexere Szenen zu entkanten, und bietet zahlreiche Einstellungen und Presets
- Die Full Demo mit der NeoTokyo°-Szene berechnet aus dem aliased Output den Luminance Channel, wendet FXAA an und ist so aufgebaut, dass alle Presets und Settings verändert werden können
FXAA-Eingaben und Parameterbedingungen
- Wenn
FXAA_GREEN_AS_LUMAauf 1 gesetzt ist, wird statt Luma der Grünkanal verwendet; in diesem Fall muss die RGB-Eingabe in einem nichtlinearen Farbraum vorliegen - Die RGB-Eingabe für FXAA muss LDR sein; konkret sollte FXAA nach dem Tonemapping angewendet werden
- Wenn
FXAA_GREEN_AS_LUMAnicht verwendet wird, muss vor der FXAA-Ausführung im Alpha-Kanal die Luma im perceptual space gespeichert werden - Nur wenn die Luma korrekt berechnet wird, funktioniert FXAA richtig
FXAA_QUALITY_PRESETist eine Einstellung, die Performance gegen Qualität abwägt12ist der Standardwert15und29stehen für höchste Qualität39ist EXTREME QUALITY
fxaaQualitySubpixsteuert, wie stark Sub-Pixel-Aliasing entfernt wird- Der Standardwert ist
0.75 1.00ist weicher,0.50ist schärfer, entfernt aber weniger Sub-Pixel-Aliasing0.00bedeutet deaktiviert
- Der Standardwert ist
fxaaQualityEdgeThresholdlegt den minimalen lokalen Kontrast fest, der erforderlich ist, damit der Algorithmus angewendet wirdfxaaQualityEdgeThresholdMinschneidet dunkle Bereiche aus der Verarbeitung heraus- FXAA kann geringe Performance-Kosten verursachen, wenn bereits eine Post-Processing-Pipeline vorhanden ist oder Deferred Shading verwendet wird
- In mobiler Grafik sind Speicherzugriffe teuer; wenn für FXAA erst eine neue Render-to-Texture-Konfiguration aufgebaut werden muss, schrumpft der Kostenvorteil
Kern von Analytical Anti-Aliasing
- Analytical Anti-Aliasing ist ein Verfahren, bei dem man die benötigten Formen kennt und Pixel direkt in bereits anti-aliased Form zeichnet
- Beim Zeichnen von 2D- oder 3D-Formen wird die Kante der Form exakt um 1 Pixel ausgeblendet
- Die Beispiele vergleichen einen Kreis bei nativer Auflösung sowie bei 1/2, 1/4 und 1/8 der Auflösung und zeigen auch bei niedriger Auflösung Edge Smoothing und den Erhalt der Form
circle-analytical.fsberechnet mitdist = length(uv)das Signed Distance Field des Kreises- Um Pixel nahe der Kreisgrenze über eine Breite von 1 Pixel auszublenden, wird
alpha = (1.0 - dist) / pixelSizeAdjustedverwendet - Diese Methode ist ohne Artefakte weich, die Filtermenge lässt sich steuern, und sie benötigt weder zusätzliche Buffer noch zusätzliche Hardwarevoraussetzungen
- Sie läuft auch ohne Extensions in grundlegendem WebGL 1.0 oder OpenGLES 2.0
- 1-Pixel-Smoothing ist scharf, aber je nach Kombination aus Bildschirmauflösung, Größe und Kreisposition können achsenausgerichtete 90-Grad-Seiten weiterhin flach wahrgenommen werden
- Wenn auf Basis der diagonalen Pixelgröße
√2 px = 1.4142...gefiltert wird, lässt sich der flache Eindruck reduzieren, allerdings wird die Form minimal unschärfer
Bedeutung von „Analytical“ und SDF-basierte Implementierung
- In der Grafikprogrammierung bedeutet „Analytical“, dass man den Aufbau der beabsichtigten Shape im Voraus kennt und den Effekt anhand ihrer mathematischen Definition berechnet
- Der Begriff wird in der Computergrafik locker verwendet und kann je nach Kontext mehrere Bedeutungen haben
- Die Implementierung basiert auf einem Signed Distance Field und setzt voraus, dass an jedem gesampelten Punkt die Entfernung zur gewünschten Shape bekannt ist
- Diese Information kann wie beim SDF-Text-Rendering in eine Textur gebacken werden, oder bei einfachen Shapes per Pixel aus einer mathematischen Formel abgeleitet werden
- Je nach signed distance wird die Shape-Grenze ausgeblendet; wenn die Fade-Distanz auf eine Pixelgröße gesetzt wird, entsteht eine glatte Kante
- Die zentralen Implementierungsfragen sind, wie der Shader die Pixelgröße kennt und wie anhand der Distanz geblendet wird
- Dieser Ansatz liefert motion-stable Pixel-Perfection, passt aber nicht zur traditionellen Rasterization und benötigt ein Signed Distance Field für die gesamte Shape
Berechnung der Pixelgröße: vorab berechnet, dFdx/dFdy, fwidth
- Wenn die Breite des Kanten-Fades auf einen festen Wert wie 95 % des Kreisradius gesetzt wird, kann das bei einer bestimmten Größe und Auflösung gut aussehen; ändert sich die Größe, wird es jedoch übermäßig weich oder es entsteht Aliasing
- Die Pixelgröße ist eines der Probleme, die Screen Space derivatives lösen
dFdx,dFdyundfwidthermöglichen zu bestimmen, wie stark sich ein bestimmter Wert in Einheiten von Bildschirmpixeln ändert- In den Beispielen wird die Distanzänderung mit
pixelSize = fwidth(dist)oderpixelSize = length(vec2(dFdx(dist), dFdy(dist)))berechnet - Screen Space derivatives berücksichtigen Transformationen einschließlich 3D-Perspektive korrekt, sind aber im WebGL-1-Standard nicht enthalten und benötigen daher die Extension
GL_OES_standard_derivativesoder WebGL 2 - Die
length()-Methode bestimmt die Länge des von dFdx und dFdy gebildeten Vektors, währendfwidth()die Näherungabs(dFdx()) + abs(dFdy())verwendet - Die
fwidth()-Näherung skaliert in diagonaler Richtung zu stark, sodass der Fade diagonal stärker angewendet werden kann - Die Unity-Erweiterung Shapes nennt
fwidth()-basiertes AAA „Fast Local Anti-Aliasing“ und denlength()-basierten Ansatz „Corrected Local Anti-Aliasing“ - In 2D sind Rendering-Größe des Kontexts und Quad-Größe bekannt, sodass die Pixelgröße für jedes Objekt direkt berechnet werden kann
- Das Beispiel übergibt eine höhenbasierte Pixelgröße wie
gl.uniform1f(pixelSizeCircle, (2.0 / (canvas.height / resDiv))); diese Methode funktioniert auch auf älterer Hardware ohne WebGL 2 oder Extensions
Alpha Blending und Wahl der Step-Funktion
- Nachdem die Fade-Breite bestimmt wurde, muss die Deckkraft angepasst werden
- In 2D ist Alpha Blending die einfache Option
- Eine andere Option ist die Kombination von MSAA mit Alpha to Coverage; sie kann in 3D-Szenen verwendet werden, wenn für korrektes Blending Schreibzugriffe auf den Depth Buffer nötig sind
- Alpha sollte distanzbasiert ausgeblendet werden; üblicherweise wird eine Step-Funktion verwendet, die zwischen Start und Ende interpoliert
- In GLSL-Implementierungen für Anti-Aliasing wird häufig
smoothstep()genutzt, in diesem Kontext liegt die Funktion jedoch innerhalb von 1 bis 2 Pixeln, sodass kaum eine beobachtbare Kurve entsteht - Entfernt man aus
smoothstep()die Hermite-Interpolation, erhält manlinearstep(), also eine geclampte lineare Interpolation - Wenn sich auf einem Quad nur eine Shape befindet, kann auch das Clamping entfernt werden
- Das finale Alpha lässt sich mit einer einfachen Division wie
float alpha = (1.0 - dist) / (pixelSize * smoothingAmount);berechnen - Der performancekritische Teil bleibt die pro Pixel ausgeführte Division; moderne GPUs können die Multiplikationen und Additionen der Hermite-Interpolation per Fused Multiply-Add optimieren
Quad-Grenzen, MSAA, 0,5-Pixel-Korrektur
- Zwischen MSAA + Alpha to Coverage und dem Rasterizer gibt es eine Wechselwirkung, die nur auf bestimmter Hardware auftritt
- Bei Verwendung von MSAA + Alpha to Coverage kann es vorkommen, dass unabhängig von der Sample-Anzahl auf einer Seite des Quads exakt 0,5 Pixel verschwinden
- Das Beispiel fügt dem SDF als Gegenmaßnahme einen 0,5-Pixel-Spielraum in der Form
dist += pixelSizeAdjusted * 0.5hinzu - In 2D lässt sich eine Verarbeitung ähnlich
NV_conservative_raster_dilatedirekt implementieren- Im Vertex Shader wird das Quad um 0,5 Pixel vergrößert
- Im Fragment Shader wird das Signed Distance Field um 0,5 Pixel verkleinert
- Die 2D-Demos auf der Seite funktionieren auf diese Weise;
vertex *= size + pixelSizeübernimmt diese Rolle - Gamma- und Premultiplied-Alpha-Probleme sind ebenfalls bei allen Formen von AA wichtig, werden aber nicht behandelt, um den Fokus auf AAA zu legen
Mehrere Formen und 3D-Erweiterung
- Innerhalb eines Quads können mehrere Formen gezeichnet und jeweils mit Anti-Aliasing versehen werden
- Bei mehreren Formen müssen beide Formen pro Pixel ausgewertet und die Ergebnisse geclampt, gewichtet und aufsummiert werden, damit Anti-Aliasing auch an Schnittpunkten erhalten bleibt
- Es ist günstiger, die Farbe direkt bei der Ausgabe der benötigten Formen in einem Durchgang aufzutragen, als ein Farb-Overlay in einem separaten Pass zu zeichnen
- Das 3D-Beispiel verwendet eine bewegte Kamera und ein 2D-rounded square innerhalb einer perspektivischen Projektion
- Der 3D-Fragment-Shader berechnet die rounded-box-SDF mit
roundedBoxSDFund ermittelt die Pixelgröße mitlength(vec2(dFdx(dist), dFdy(dist))) - Wenn Kamera- und Perspektivmatrix multipliziert werden, ist es zuverlässig, die Pixelgröße über Screen-Space-Derivatives zu bestimmen
- Theoretisch könnte man ohne Derivatives für jedes Pixel die Fragmentkoordinaten mit der inversen Perspektivmatrix multiplizieren, doch die Performance-Kosten sind hoch
- Legt man den Fade auf die Mitte der Kante, kann das Verformungen der Form bei kleinen Größen oder starker Perspektive verringern; allerdings können die Ränder über das Quad hinausragen und Hard Edges oder Clipping verursachen
- NVIDIA hat die Erweiterung
NV_conservative_raster_dilateeingeführt, die zusätzliche Pixel am Rand bereitstellt; sie ist jedoch in WebGL nicht verfügbar und auf NVIDIA-Hardware beschränkt
Praxisbeispiele
- Freya Holmérs Unity-Erweiterung Shapes gilt als funktional ausgereifteste Umsetzung dieses Ansatzes
- SDFs werden per MSAA geglättet oder per AAA geblendet
- Enthalten sind Funktionen für Motion Blur, formtreue Farbverläufe und Opacity Fade für Linien unter 1 Pixel Breite
- Die Technik für Linien unter 1 Pixel heißt Line Thinness Fading
- Valve Software führte während der Entwicklung der Orange Box breitflächig Signed-Distance-Field-Rendering in die Source Engine ein
- Besonders sichtbar wurde es im HUD von Team Fortress 2, wo es für weiche, aber scharfe UI-Elemente genutzt wurde
- Valve entwickelte ein Line-Art-Shader-System, das auch beim Hochskalieren von Bildern mit fester Auflösung auf höhere Auflösungen glatte Silhouetten erzeugt
- Auch Outlines und Drop-Shadows werden verarbeitet; außerdem lässt sich die Technik auf World Elements wie Schilder im 3D-Raum anwenden
- Valve veröffentlichte die Implementierung in einem SIGGRAPH-2007-Paper, das auch Beispiele aus 3D-Spielwelten enthält
- Viktor Chlumskýs „Shape Decomposition for Multi-channel Distance Fields“ ist ein Beispiel für die Weiterentwicklung einer in einer Fußnote des Valve-Papers erwähnten Technik
- Zu den zugehörigen Arbeiten gehören
msdfgenundmsdf-atlas-gen
- Zu den zugehörigen Arbeiten gehören
- Der Multi-Channel-Distance-Field-Ansatz nutzt RGB und einen Median-Term, um scharfen Text zu erzeugen, und legt in den Alpha-Kanal ein klassisches SDF für Effekte wie Glow und Drop Shadow
- CJK-Zeichen benötigen wegen ihrer feinen Details größere Texturen; werden große Texturen verkleinert, können dabei eigene Artefakte entstehen
- Laut dem Hacker-News-Nutzer aappleby verwendet Google Maps für Straßensegmente AAA auf Basis von Capsule Shapes
- aappleby sagte, er habe dies vor etwa zehn Jahren selbst geschrieben
- Bei einer Prüfung mit dem WebGL-Debugger Spector.js wirke der Shader-Code des Streets-Draw-Calls so, als zeige er formenabhängiges Blended Alpha
Grenzen des SDF-Ansatzes und TAA-Diskussion
- Yakov Galka weist darauf hin, dass der SDF-Ansatz das SDF an bestimmten Punkten sampelt; enthält das SDF hochfrequente Anteile, kann Aliasing entstehen
- Wird ein Kreis gerastert, der kleiner als 1 Pixel ist, kann der Ansatz dieses Artikels Aliasing möglicherweise nicht vollständig beseitigen
- Als echte analytische Methode zum Anti-Aliasing und Rastern polygonaler und Bezier-Formen nennt Yakov Galka Wavelet Rasterization von J. Manson und S. Schaefer
- Nach Veröffentlichung des Artikels gab es in den Kommentaren das Feedback, dass die Kritik an TAA stark ausgefallen sei; der Autor räumt ein, die Probleme, die TAA lösen soll, und die Probleme, die mit anderen Techniken schwer zu lösen sind, nicht ausreichend behandelt zu haben
- Timothy Lottes sieht TAA als klare technische Weiterentwicklung, sagt aber, dass es bei Motion Clarity Grenzen habe
- FXAA 4 war ein 2-Frame-Blender und unterscheidet sich grundlegend von TXAA; TXAA enthält kein MLAA und basiert auf MSAA
- Als Material für ein besseres Verständnis von TAA wird der GDC-Vortrag Temporal Reprojection Anti-Aliasing in INSIDE von INSIDE-Entwickler Lasse Jon Fuglsang Pedersen empfohlen
- AAA gilt als Technik, mit der sich Formen unterschiedlicher Größen in nativer Auflösung weich, scharf und bewegungsstabil zeichnen lassen
1 Kommentare
Meinungen auf Hacker News
Ich bin der Autor; falls es Fragen gibt, beantworte ich sie gern.
Einerseits heißt es, Anti-Aliasing solle im linearen RGB-Raum erfolgen, nicht im sRGB-Raum [1] [2]; andererseits gibt es das Argument, dass Schriften über Jahrzehnte dafür angepasst wurden, weil man es eben nicht so gemacht hat, und dass sRGB daher manchmal besser sei [3] [4]. Ich frage mich, ob du einen Rat zu Anti-Aliasing im linearen vs. sRGB-Raum hast.
[1] https://www.puredevsoftware.com/blog/2019/01/22/sub-pixel-ga...
[2] http://hikogui.org/2022/10/24/the-trouble-with-anti-aliasing...
[3] https://news.ycombinator.com/item?id=12023985
[4] http://hikogui.org/2022/10/24/the-trouble-with-anti-aliasing...
Auch WebGL2 hat noch keine MSAA-Texturobjekte, sondern unterstützt nur MSAA-Renderbuffer, sodass man einzelne Samples im Shader nicht direkt auslesen kann. Das wäre für eigene Resolve-Render-Pässe nützlich; möglich ist es erst mit WebGPU.
Deshalb hat sich meine Sicht inzwischen von „TAA == unscharf“ eher zu „TAA + richtig eingesetztes Machine Learning ist das beste Anti-Aliasing, das in heutigen 3D-Spielen möglich ist“ verschoben. Mich würde interessieren, wie du das siehst.
[1] https://youtu.be/WG8w9Yg5B3g
Ich habe selbst ein paar Blogposts mit Echtzeit-Visualisierungen geschrieben, und das hat enorm viel Zeit gekostet. Trotzdem scheint mir das der richtige Weg zu sein. In einer Zeit, in der es Inhalte im Überfluss gibt, ist es meiner Meinung nach für alle besser, weniger, dafür aber hochwertigere Inhalte zu erstellen, auch wenn es länger dauert.
Das größere Problem ist weniger Anti-Aliasing selbst als alles drumherum. In den Spieleinstellungen gibt es viele Abkürzungen zur Auswahl, aber kaum Erklärungen dazu, worin sie sich unterscheiden; die Hälfte davon kenne ich überhaupt nicht.
Natürlich kann man es nachschlagen, aber ein bisschen mehr Nutzerfreundlichkeit wäre schön. Dieser Artikel dürfte künftig als Referenz hilfreich sein.
Auf einer Metaebene habe ich in letzter Zeit häufiger eine abkürzungskritische Stimmung wahrgenommen. Dabei war es meiner Meinung nach noch nie so einfach wie heute, Dinge nachzuschlagen. Es gibt sicher Abkürzungen, die das Lernen behindern oder eine Art Gatekeeping darstellen, aber man muss Konzepte auf einer nützlichen Ebene benennen, um arbeiten zu können; deshalb finde ich die Abkürzungen in Grafikoptionen von Spielen ziemlich vernünftig.
Die Art, Grafikprogrammierung anhand von WebGL-Beispielen zu analysieren, ist genial. Das ist Hypertext, der die Stärken des Mediums richtig ausspielt. Es erinnert an etwas, das man auf https://pudding.cool/ sehen könnte, geht aber deutlich tiefer.
Ich habe in einer Rendering-Engine eine Zeit lang MSAAx4 verwendet und zuletzt überlegt, auf eine FXAA/TAA-Implementierung umzusteigen; jetzt bin ich mir nicht mehr sicher, ob ich das tatsächlich tun werde. Ich habe hier viel gelernt und werde für UI-Elemente wohl einen analytischen Ansatz ausprobieren. Artikel über Grafikprogrammierung tauchen auf HN nicht oft auf; wer mehr Interesse daran hat, dem empfehle ich diese Ressource mit Frame-Analysis-Artikeln:
https://www.adriancourreges.com/blog/
Besonders mag ich https://acko.net/blog/how-to-fold-a-julia-fractal/. Ich habe noch keine Ressource gesehen, die so hilfreich war, um die Beziehung zwischen trigonometrischen Funktionen und komplexen Zahlen zu verstehen.
Die Frames mit den Kreisen und Vergrößerungen vermitteln die Botschaft hervorragend. Der ganze Artikel liest sich sehr gut.
SDF oder mSDF sind nicht die Zukunft, sondern bereits gut genug bewährte Klassiker.
Den Teil, dass „man für jedes Pixel alle Bézier-Kurvensegmente lösen muss und die Performance deshalb stark einbricht“, sehe ich eher als Zukunft oder Gegenwart. Slug und DirectWrite werden bereits mit guter Performance eingesetzt.
https://sluglibrary.com/
https://learn.microsoft.com/en-us/windows/win32/directwrite/...
[0]: https://www.microsoft.com/en-us/research/wp-content/uploads/...
[1]: https://patents.google.com/patent/US20070097123A1/en
Um sie produktionstauglich zu machen, war wirklich sehr viel Arbeit nötig. Die Voronoi-basierte Tessellation aus dem Paper wurde bei vielen asiatischen Schriftzeichen pathologisch schlecht.
Beim Scrollen durch den Artikel sprang mir sofort der NeoTokyo-Screenshot ins Auge. Ich bin diesen Korridor tausende Male entlanggelaufen. Ich habe jahrelang den Server für diesen Mod betrieben und hatte mit einer kleinen, aber fähigen und netten Community wirklich viel Spaß.
Als jemand, der sowohl 2D- als auch 3D-Rendering-Engines geschrieben hat, möchte ich eine kleine Einordnung geben: Die beiden sind wirklich verschieden. Es ist nicht nur eine zusätzliche Dimension; Ziele, Anwendungsfälle und Erwartungen sind völlig anders.
Deshalb würde ich nicht sagen: „Alles, was hier besprochen wurde, lässt sich auch auf 3D erweitern“, sondern eher, dass dieser ganze Artikel größtenteils über 3D-Rendering handelt, nicht über 2D-Rendering. Einen guten Artikel, der dieses Thema aus Sicht des 2D-Renderings behandelt, gibt es hier: https://ciechanow.ski/alpha-compositing/
Ein Anti-Aliasing-Kriterium, um das sich in 3D niemand kümmert, das in 2D aber sehr wichtig ist, sind Korrektheit und Bias. AAA ist zum Beispiel stark verzerrt und damit ungenau. Wenn man dieselbe Form an derselben Position mehrfach zeichnet, wird sie opaker oder dunkler. Bei MSAA passiert das nicht; der Fehler ist begrenzt und es gibt keinen Bias.
Das Zeichnen dicker Linien ist besonders interessant, weil es schwierig ist [1]. Kürzlich habe ich auch das hier gesehen [2] und mich gefragt, ob man alle Formen in quadratische Bézier-Kurvensegmente umwandeln und diese Technik dafür nutzen könnte. Mich würde interessieren, ob du das für einen Weg hältst, dem man nachgehen sollte.
[0] https://github.com/Lichtso/contrast_renderer
[1] https://mattdesl.svbtle.com/drawing-lines-is-hard
[2] https://scribe.rip/@evanwallace/easy-scalable-text-rendering...
Die vorgeschlagene Lösung stützt sich auf Signed Distance Fields, geht aber über den entscheidenden Teil — „Abstand wozu?“ — etwas hinweg. In 2D ist es klar: Man misst den Abstand zur Grenze zwischen Objekt und Hintergrund, also zur Silhouette.
In 3D wird es kompliziert, weil ein Objekt beim Rotieren Selbstverdeckung erzeugen kann. Woran misst man das SDF? Die 2D-Projektionssilhouette eines 3D-Objekts ändert sich ständig und lässt sich nicht einfach vorberechnen.
Der Captain-Disillusion-Link hat mich gefreut. Ich kannte ihn nicht, aber seine Arbeiten sind großartig. Direkter Link für alle, die sich für Videoeffekte interessieren: https://www.youtube.com/@CaptainDisillusion
Der Artikel ist gut aufgebaut, aber der Abschnitt, der TAA angreift, kann meiner Meinung nach Verwirrung stiften. SDF-Anti-Aliasing ist in keiner Weise eine Alternative zu TAA.
TAA behandelt alle Arten von Aliasing, während es hier nur um Kanten-Aliasing geht. Viele moderne Spiele verwenden Monte-Carlo-basierte Ansätze für indirekte Beleuchtung und andere Effekte, und das macht TAA praktisch erforderlich.
Die Aussage „Mobile Chips unterstützen genau MSAAx4, und die Lage ist seltsam. Unter Android kann man 2x auswählen, aber der Treiber erzwingt trotzdem 4x“ finde ich etwas fragwürdig.
Auf meinem Android-Smartphone sieht man den Unterschied zwischen 2x und 4x deutlich, aber es wirkt nicht so „abgerundet“ wie auf dem iPhone.