Vermeiden von Z-Fighting mit zusammenfallenden Oberflächen

26

Beim Rendern von zwei sich überlappenden koplanaren Oberflächen tritt häufig das Problem "Z-Fighting" auf, bei dem der Renderer nicht entscheiden kann, welche der beiden Oberflächen sich näher an der Kamera befindet. Dadurch entstehen visuelle Artefakte im Überlappungsbereich.

Die Standardlösung besteht darin, den Oberflächen beim Entwerfen des Modells einen leichten Versatz zu geben. Gibt es eine andere Lösung?

Kennzeichen
quelle
2
Sie können logarithmische Tiefenpuffer auschecken. Es gibt einen Artikel über Gamasutra
Soapy
1
Wenn Sie "koplanar" sagen, meinen Sie "fast" oder "genau" koplanar, und wenn letztere, sind diese Flächen jemals identische Flächen / Dreiecke? Die Rendering-Hardware sollte für den letzten Fall deterministisch sein (vorausgesetzt, Sie senden nicht in zufälliger Reihenfolge) und keine Kämpfe haben. Wenn es sich um nicht identische, aber exakt koplanare Flächen handelt, können Sie das Modell aktualisieren, um die Flächen in überlappende und nicht überlappende Bereiche zu unterteilen?
Simon F
@ SimonF, mit "koplanar" meine ich "genau koplanar". Soapys Lösung funktioniert nur im "fast koplanaren" Fall.
Mark
Können Sie ein Beispiel für Ihre Oberflächen geben? Das Einzige, was mir auf den ersten Blick einfällt, sind doppelte Dreiecke, wie bei @SimonF erwähnt.
RichieSams
@RichieSams Der häufigste Fall, an den ich denken kann, sind Abziehbilder, bei denen Sie nicht genau doppelte Dreiecke benötigen.
rys

Antworten:

10

Wenn die Oberflächen exakt koplaner sind, liegt Ihr Schicksal bei den FPU-Göttern. Sie werden höchstwahrscheinlich Z-Kämpfe haben. Wenn die Dreiecke sind identisch , und Sie tun , um die genaue gleiche Mathematik zu jeder, Sie werden mit den gleichen Z-Werte für beide am Ende. Aber auch dies wird nur passieren, wenn Ihre mathematischen Operationen für beide identisch sind. (Da FPU-Operationen im Allgemeinen nicht kommutativ sind)

Eine mögliche Lösung besteht darin, den Z-Puffer überhaupt nicht zu verwenden. Sie können stattdessen den Algorithmus des Malers verwenden . Zugegeben, damit sind auch alle Probleme des Maleralgorithmus verbunden. Aber es würde den Z-Kampf lösen.

In Ihrem Beispielfall von SSDs (Screen Space Decals) besteht die häufigste Lösung in der Verwendung eines Versatzes, auch bekannt als einfacher dünner Würfel. Weitere Informationen finden Sie in der Präsentation von Warhammer 40k zu SSDs. Oder Bart Wronskis Post, der einige andere Probleme mit Abziehbildern behandelt, aber auch Links zu einigen anderen Präsentationen über SSDs enthält

RichieSams
quelle
5
Durch erneutes Rendern derselben Geometrie mit denselben Transformationen werden jedes Mal zuverlässig dieselben Tiefenwerte generiert. (Dh es ist keine Macht , es ist ein Wille ). So funktioniert beispielsweise die Multi-Pass-Vorwärtsbeleuchtung.
Nathan Reed
@ NathanReed Korrigiert. Vielen Dank für die Klarstellung
RichieSams
1
Um diese Funktionalität zu erhalten, müssen Sie das unveränderliche Qualifikationsmerkmal in glsl verwenden: opengl.org/wiki/Type_Qualifier_%28GLSL%29#Invariance_qualifiers
ashleysmithgpu
Beachten Sie, dass identische Shader-Ausdrücke (und natürlich Eingaben) bei der Auswertung der Scheitelpunktpositionen möglicherweise nicht ausreichen, um identische Ergebnisse zu erzielen, da einige Optimierungen vom Rest des Shaders abhängen können. GLSL hat das Schlüsselwort "invariant", um Shader-Ausgaben zu deklarieren, die in verschiedenen Shadern identisch ausgewertet werden müssen.
Firadeoclus
2

So habe ich das in der Vergangenheit gelöst:

  1. Zeichnen Sie das erste Objekt (das Objekt, das hinter dem anderen Objekt erscheinen soll) durch Tiefenprüfung, jedoch nicht durch Tiefenschreiben
  2. Zeichnen Sie das zweite Objekt durch Tiefenprüfung und Tiefenschreiben. Dies wird keine Z-Kämpfe verursachen, da wir in Schritt 1 keine Tiefe geschrieben haben.
  3. Zeichnen Sie das erste Objekt, indem Sie nur in den Tiefenpuffer und nicht in den Farbpuffer schreiben . Dies stellt sicher, dass der Tiefenpuffer für alle Pixel, die von Objekt 1, aber nicht von Objekt 2 abgedeckt werden, auf dem neuesten Stand ist.

Beachten Sie, dass die Objekte nacheinander gezeichnet werden müssen, damit dies funktioniert.

Standard
quelle
0

Abhängig von Ihrem Renderer können Sie die Oberflächen mit einem rauschähnlichen Algorithmus "verschwommener" machen, indem Sie einen winzigen Versatz in der Multisampling-Tiefe anwenden. Dies sollte zu einer Art Mischeffekt für Oberflächen in unmittelbarer Nähe der Tiefe führen. Soweit ich weiß, ist die Einstellung der Sample-Tiefe in Fragment Shader in OpenGL relativ neu und nur als Erweiterung.

OpenGL verfügt über das PolygonOffset, es muss jedoch im Voraus bekannt sein, dass Sie im Begriff sind, etwas koplanar zu rendern. Obwohl es für Flächen innerhalb eines einzelnen Modells nicht machbar ist, kann es beispielsweise gut funktionieren, wenn eine Straße auf einem Grundstück überlagert wird.

Andreas
quelle