Wie kann man Alpha-Blending in einer komplexen 3D-Szene richtig implementieren?

11

Ich weiß, dass diese Frage ein bisschen einfach zu beantworten klingt, aber sie macht mich verrückt. Es gibt zu viele mögliche Situationen, die ein guter Alpha-Mischmechanismus bewältigen sollte, und für jeden Algorithmus, den ich mir vorstellen kann, fehlt etwas.

Dies sind die Methoden, über die ich bisher nachgedacht habe:

  • Als erstes dachte ich über das Sortieren von Objekten nach Tiefe nach. Dieses schlägt einfach fehl, weil Objekte keine einfachen Formen sind, sondern Kurven haben und sich ineinander schleifen können. Ich kann also nicht immer sagen, welches näher an der Kamera ist.

  • Dann habe ich darüber nachgedacht, Dreiecke zu sortieren, aber dieses könnte auch fehlschlagen. Ich bin mir nicht sicher, wie ich es implementieren soll. Es gibt einen seltenen Fall, der erneut ein Problem verursachen könnte, bei dem zwei Dreiecke sich gegenseitig passieren. Wieder kann niemand sagen, welcher näher ist.

  • Das nächste war die Verwendung von Tiefenpuffer. Zumindest der Hauptgrund, warum wir Tiefenpuffer haben, sind die Probleme beim Sortieren, die ich erwähnt habe, aber jetzt bekommen wir ein anderes Problem. Da Objekte transparent sein können, ist in einem einzelnen Pixel möglicherweise mehr als ein Objekt sichtbar. Für welches Objekt soll ich also die Pixeltiefe speichern?

  • Ich dachte dann, ich kann vielleicht nur die vorderste Objekttiefe speichern und damit bestimmen, wie ich die nächsten Zeichenaufrufe an diesem Pixel mischen soll. Aber auch hier gab es ein Problem. Denken Sie an zwei halbtransparente Ebenen mit einer festen Ebene in der Mitte. Ich wollte die feste Ebene am Ende rendern, man kann die am weitesten entfernte Ebene sehen. Beachten Sie, dass ich alle zwei Ebenen zusammenführen wollte, bis nur noch eine Farbe für dieses Pixel übrig ist. Natürlich kann ich aus den gleichen Gründen, die ich oben erklärt habe, auch Sortiermethoden verwenden.

  • Schließlich kann ich mir nur vorstellen, dass alle Objekte in verschiedene Renderziele gerendert werden können. Anschließend werden diese Ebenen sortiert und die endgültige Ausgabe angezeigt. Aber diesmal weiß ich nicht, wie ich diesen Algorithmus implementieren kann.

Ali1S232
quelle

Antworten:

11

Kurze Antwort

Schauen Sie in die Tiefe Peeling . Aus meiner Forschung scheint es die beste Alternative zu sein, obwohl es rechenintensiv ist, weil es mehrere Rendering-Durchgänge erfordert. Hier ist eine weitere neuere und schnellere Implementierung , ebenfalls von NVIDIA.

Lange Antwort

Das ist eine schwierige Frage. Die meisten Bücher, die ich gelesen habe, überfliegen das Thema und belassen es bei:

Rendern Sie zunächst alle undurchsichtigen Objekte und mischen Sie dann die transparenten Objekte in der Reihenfolge von hinten nach vorne darüber.

Leichter gesagt als getan, weil der offensichtliche Ansatz, Objekte nach ihren Schwerpunkten zu sortieren, dies tut sortieren, nicht die richtige Sortierreihenfolge garantiert.

Es ist genau das gleiche Problem, warum der Algorithmus des Malers für den allgemeinen Fall nicht funktioniert und a Tiefenpuffer benötigt wird.

In einem der Bücher, die ich habe, werden einige Lösungen erwähnt:

  • Tiefenschälen - eine Multi-Pass-Lösung, die die Tiefenpufferbegrenzung überwindet, indem sie uns das n-te nächstgelegene Fragment gibt, nicht nur das nächstgelegene. Der größte Vorteil ist, dass Sie die transparenten Objekte in beliebiger Reihenfolge rendern können und keine Sortierung erforderlich ist. Es kann wegen der mehreren Durchgänge teuer sein, aber der Link, den ich oben angegeben habe, scheint die Leistung zu verbessern.

  • Schablonen-gerouteter K-Puffer - Verwenden Sie das Schablonen-Routing, um mehrere Schichten von Fragmenten pro Pixel und Geometriedurchlauf zu erfassen. Der Hauptnachteil besteht darin, dass Fragmente in einem Nachbearbeitungsdurchlauf sortiert werden müssen.

Es wird auch eine Hardwarelösung für das Problem erwähnt, aber ich glaube nicht, dass sie tatsächlich verfügbar ist:

  • F-Puffer - Ein FIFO-Puffer in Rasterisierungsreihenfolge für das Rendern in mehreren Durchgängen. Trotzdem eine gute Lektüre und die Einführung spricht auch ein wenig über das Problem der Transparenz-Sortierreihenfolge und die aktuellen Lösungen.

Andere Problemumgehungen, die keine perfekten Ergebnisse liefern, aber besser als nichts sind:

  • Verwenden Sie nach dem Rendern aller undurchsichtigen Objekte weiterhin den Z-Puffer-Test für transparente Objekte, deaktivieren Sie jedoch das Schreiben des Z-Puffers . Möglicherweise erhalten Sie durch falsche Sortierung einige Artefakte, aber zumindest alle transparenten Objekte sind sichtbar.

Und zitieren Sie das F-Puffer-Whitepaper oben:

Die einfachste Lösung besteht darin, jedes teilweise transparente Polygon vollständig unabhängig zu rendern (dh alle Durchgänge zu rendern, bevor mit dem nächsten Polygon fortgefahren wird). Diese Lösung ist aufgrund der anfallenden Zustandsänderungskosten in der Regel unerschwinglich teuer. Alternativ kann die Anwendungs- oder Schattierungsbibliothek Polygone gruppieren, um sicherzustellen, dass nur nicht überlappende Polygone zusammen gerendert werden. In den meisten Fällen ist diese Lösung auch nicht attraktiv, da die Software eine Bildschirmraumanalyse von Polygonen durchführen muss.

David Gouveia
quelle
11

Die richtige Antwort lautet # 1: Sortieren Sie alle Ihre Dinge nach Tiefe und rendern Sie sie (deaktivieren Sie natürlich das Tiefenschreiben, aber nicht das Testen). Was ist ein "Ding"?

Jedes "Ding" muss ein konvexes Objekt sein; es kann sich nicht selbst überlappen. Wenn Sie ein Objekt haben, das konkav ist, muss es daher in konvexe Teile zerlegt werden.

Das ist der Standardmethode zum Rendern einer transparenten Szene. Löst es durchdringende Fälle? Löst es Fälle, in denen Sie 3 Objekte haben, bei denen keine Tiefenreihenfolge bestimmt werden kann? Löst es Fälle, in denen Sie ein langes Objekt haben, das sich mit einem kleinen Objekt überlappt, dessen Mitteltiefe näher liegt? Nein.

Aber es funktioniert gut genug . Spiele verwenden kein Tiefenpeeling. Sie verwenden keine schablonengesteuerten K-Puffer. Sie verwenden keine F-Puffer. Warum? Weil diese Dinge unglaublich langsam sind.

Mit der Standardmethode erhalten Sie möglicherweise Artefakte. Aber zumindest läuft dein Spiel ziemlich schnell.

Wenn Sie bereit sind, sich auf DX11 oder bessere Hardware zu beschränken, gibt es Möglichkeiten, das Mischen mit der richtigen Sortierung zu implementieren. Sie sind langsamer, aber bei weitem nicht so langsam wie die vorherigen Techniken. Und im Gegensatz zum Tiefenpeeling, das Artefakte verursachen kann, ist dieses probengenau. Außerdem ist die Leistung des Algorithmus im Allgemeinen pro Fragment (und bis zu einem gewissen Grad pro Überlappung innerhalb jedes Fragments). Wenn Sie also nicht viel transparentes Material gezeichnet haben, ist die Leistung minimal.

Ich weiß nicht, ob die Technik einen schicken Namen hat, aber eine Implementierung für Pre-GL4.2 finden Sie hier. Eine D3D11-Version finden Sie hier (Powerpoint, PPSX, Libre-kompatibel).

Nicol Bolas
quelle
Gute Punkte zu dieser Antwort. Ich persönlich würde mich auch mit gut genug zufrieden geben (was ich in meiner Antwort als Problemumgehung beschrieben habe), da die meisten der von mir aufgelisteten Techniken wahrscheinlich mehr Probleme bereiten als sie wert sind. Interessante Technik am Ende, ich glaube nicht, dass sie im Echtzeit-Rendering aufgeführt war, auf das ich meine Antwort recherchiert habe. Ich bin ein absoluter Neuling, wenn es um Funktionen auf DX11-Ebene geht.
David Gouveia
"Eine Implementierung für Pre-GL4.2 finden Sie hier" 404
Jeroen van Langen