Warum teilen GPUs den Clipraum Z durch W für die Position?

8

Hintergrund:
Ich fand, dass es sehr einfach ist, einen linearen Tiefenpuffer zu verwenden, wobei nur eine geringfügige Modifikation der kanonischen Scheitelpunkttransformation verwendet wird. Die einfachste Methode finden Sie am Ende von https://www.mvps.org/directx/articles/linear_z/linearz.htm .

Die Einschränkung ist jedoch, dass es nur für Dreiecke funktioniert, die nicht gegen die nahen oder fernen Ebenen geklippt werden müssen. (Und eine alternative Lösung, die Perspektiventeilung im Vertex-Shader durchzuführen, ergibt ein ähnliches Problem für die anderen vier Kegelstumpf-Ebenen.)

Da das Abschneiden eine lineare Interpolation erfordert, um über alle vier Clipraumkoordinaten zu arbeiten, ist es meines Erachtens unmöglich, mit linearer Tiefe nur mit einem Vertex-Shader zu arbeiten. Aber der Grund dafür ist, dass Z durch W geteilt wird.

Warum wird das gemacht? X und Y müssen durch den Abstand von der Kamera geteilt werden, die Z-Koordinate jedoch nicht, um perfekt in die NDC-Box zu passen.

Jessy
quelle

Antworten:

13

Wenn Sie ein perspektivisches Bild erstellen und Ihr Modell implizite Schnittpunkte hat, werden diese Schnittpunkte bei Verwendung von "linearem Z" an den falschen Stellen angezeigt.

Stellen Sie sich zum Beispiel eine einfache Grundebene mit einer Reihe von Telefonmasten vor, die in die Ferne rücken und den Boden durchbohren (und weiter unten fortfahren). Die impliziten Schnittpunkte werden durch die interpolierten Tiefenwerte bestimmt. Wenn diese nicht interpoliert 1/Zwerden, sieht das Bild falsch aus, wenn die projizierten Scheitelpunkte mit Perspektive berechnet wurden.

Ich entschuldige mich für die nicht-ästhetische Qualität der folgenden Abbildungen, aber ich habe sie bereits 1997 gemacht.

Das erste Bild zeigt den erforderlichen Rendering-Effekt. (Beachten Sie, dass die blauen "Pylone" ziemlich weit unter der Grundebene liegen und daher am unteren Rand der Bilder abgeschnitten sind.)

Geben Sie hier die Bildbeschreibung ein

Dieses zweite Bild zeigt das Ergebnis der Verwendung eines nicht reziproken Tiefenpuffers: (Entschuldigung für die Änderung der Skalierung - diese wurden aus einem alten MS Word-Dokument kopiert und ich habe keine Ahnung, was mit der Skalierung passiert ist.)

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, sind die Ergebnisse falsch.

Möchten Sie wirklich eine lineare Z-Darstellung? Wenn Sie eine Perspektive rendern, möchten Sie sicher mehr Präzision näher an der Kamera als in der Ferne?

Zu Ihrem späteren Kommentar:

"Wenn diese nicht mit 1 / Z interpoliert sind", die ich nicht verstehe. Welche Interpolation ist das?

Das erste, was zu beachten ist, ist, dass bei einer standardmäßigen perspektivischen Projektion gerade Linien im Weltraum gerade Linien im perspektivischen Raum bleiben. Abstände / Längen bleiben jedoch nicht erhalten.

Nehmen wir der Einfachheit halber an, dass eine triviale Perspektiventransformation verwendet wird, um die Eckpunkte zu projizieren, dh Wir sollten auch eine reziproke Bildschirmraumtiefe berechnen, z. B. aber lineares Z im Tiefenpuffer würde für mich Folgendes erfordern: (Wir können hier annehmen, dass scale = 1 ist)

XScreen=XWorldZWorld
YScreen=YWorldZWorld
ZScreen=1ZWorld
ZScreen=scaleZWorld

Nehmen wir an, wir haben eine Linie mit den Endpunkten des Weltraums Mit der perspektivischen Zuordnung dieser Karte zu Bildschirmraumkoordinaten

[001]and[200010]
[001]and[2000.1]

Das Rendering-System / die Rendering-Hardware interpoliert den Bildschirmraum z linear, sodass am 1/2 Wegpunkt der Linie, wie er auf dem Bildschirm erscheint, dh bei Pixel (10, 0), ein projiziertes (inverses) Z erhalten wird Wert von 0,55, was einem Weltraum-Z-Wert von ~ 1,818 entspricht. Bei den Start- und End-Z-Werten beträgt dies ungefähr 20% entlang der Länge der Linie.

Wenn wir stattdessen versuchen würden, mit den ursprünglichen Z-Werten zu interpolieren, würden wir Z erhalten, das einem Weltraumwert von 5,5 entspricht. Solange nichts schneidet, könnten Sie in Ordnung sein (ich habe darüber auch nicht gründlich gedacht) , aber nichts mit impliziten Kreuzungen wird falsch sein.

Was ich nicht erwähnt habe, ist, dass Sie, sobald Sie eine perspektivisch korrekte Texturierung (oder sogar eine perspektivisch korrekte Schattierung) eingeführt haben, eine Interpolation pro Pixel von 1 / w durchführen und zusätzlich auch den Kehrwert dieses interpolierten Werts pro Pixel berechnen müssen.

Simon F.
quelle
Ich glaube nicht, dass ich diese Antwort ohne weitere Mathematik / Diagramme verstehen kann. Und ja, mehr Präzision, näher, macht wahrscheinlich Sinn, aber eine Skalierung von linear nach far / z, was Standard ist, macht keinen Sinn. Es ergibt sich ein Tiefenpuffer, der linearer wird, je näher die beiden Clip-Ebenen beieinander liegen. Es scheint eine Verschmelzung zweier Konzepte zu sein: bildschirmraumlineares Z und eine nicht konstante Tiefenpufferzuordnung für einen Performance-Hack.
Jessy
Insbesondere ist es das "wenn diese nicht mit 1 / Z interpoliert werden", das ich nicht verstehe. Welche Interpolation ist das?
Jessy
1
Ich werde einen zusätzlichen Text hinzufügen, um ihn hoffentlich zu erklären
Simon F
Vielen Dank! Ich denke, das Problem liegt in "Das Rendering-System / die Hardware interpoliert den Bildschirmbereich z linear". Ich hatte den Eindruck, dass die NDC-Position als (x, y, z) / wFragment berechnet würde , aber anscheinend müssen wir uns stattdessen mit einer linear interpolierten Version von (x/w, y/w, z/w)? Das erscheint mir 2018 nicht vernünftig, aber es wäre gut zu wissen, ob das der Hack ist, mit dem wir jetzt sowieso leben müssen!
Jessy
Um eine perspektivisch korrekte Texturierung / Schattierung / was auch immer durchzuführen, müssen Sie die Werte (Val / w) linear interpolieren und dann pro Fragment eine Division durch das linear interpolierte 1 / w durchführen. Es ist ein bisschen schwierig, es nur in einem Kommentar zu erklären, aber es gibt ein bisschen eine Erklärung in computergraphics.stackexchange.com/a/4799/209 . Alternativ können Sie nach Jim Blinns Artikel "Hyperbolic Interpolation"
Simon F vom
6

Die Verwendung von Z / W für den Tiefenpuffer geht tiefer als nur das Abschneiden gegen die nahen und fernen Ebenen. Wie Simon angedeutet hat, hat dies mit der Interpolation zwischen den Eckpunkten eines Dreiecks während der Rasterung zu tun.

Z / W ist die einzigartige Option, mit der NDC-Tiefenwerte für Punkte im Inneren des Dreiecks korrekt berechnet werden können, indem die NDC-Tiefenwerte aus den Scheitelpunkten einfach linear im Bildschirmbereich interpoliert werden . Im Prinzip könnten wir jede Funktion verwenden, die wir möchten, um den Kameraraum Z auf den Tiefenpufferwert abzubilden - aber jede andere Wahl als Z / W würde eine kompliziertere Berechnung pro Pixel erfordern, was langsamer und schwieriger wäre Hardware einbauen.

Beachten Sie, dass , wenn Sie einen linearen Tiefenpuffer verwenden, dann natürlich linear Tiefenwerte interpoliert wird in korrekt seinen Weltraum ... aber nicht im allgemeinen im Bildraum! Und es ist der Bildschirmbereich, der für die Rasterung wichtig ist, da wir in der Lage sein müssen, perspektivisch korrekte Tiefenwerte (und andere Attributwerte wie UVs) für jedes Pixelzentrum oder jeden anderen Abtastpunkt innerhalb der Bildschirmbereichsgrenzen von a zu generieren Dreieck wird gerastert.

Nathan Reed
quelle
Ich weiß nicht, wie man eine GPU entwirft, aber es scheint mir, dass alles, was benötigt wird, ist, Z anstelle von Z / W für die lineare Tiefe zu interpolieren, und die Z / W-Interpolation könnte danach für alles Sichtbare noch passieren. Ich kann immer noch nicht sagen, ob dies eine gute Argumentation ist oder eine Frage von "Niemand kümmert sich darum, damit wir uns nicht um die Aktualisierung kümmern".
Jessy
Das Interpolieren von Z anstelle von Z / W führt nicht zu korrekten Ergebnissen im Bildschirmbereich. Z / W tut.
Nathan Reed
Recht. Wenn der Tiefenpuffer jedoch mit einer geringeren Genauigkeit als die Position quantisiert wird, ist es nicht nur eine gute Idee, einen skalierten Teil des Bildschirmbereichs Z zu speichern, sondern auch, wenn nur lineare Interpolation erforderlich ist im Sichtraum passieren. Und Z muss vor der Division durch W für den Tiefenpuffer und danach für das, was Sie durchlaufen haben, interpoliert werden. Ist also die Antwort auf meine Frage: "Weil GPUs immer nur im Clip-Bereich interpoliert haben, weil es die einzige praktische Lösung für die ersten GPUs war und seitdem gut genug funktioniert hat"?
Jessy
Ich folge nicht dem, was Sie mit "mit einer geringeren Genauigkeit als der Position quantisiert" oder "Speichern eines skalierten Teils des Bildschirmbereichs Z" meinen.
Nathan Reed
1
Außerdem muss "Z vor der Division durch W für den Tiefenpuffer interpoliert werden" - nein. Das habe ich versucht zu erklären. Sie erhalten die falschen Antworten, wenn Sie Z (oder etwas anderes) im Bildschirmbereich interpolieren, ohne es zuerst durch W zu teilen. Sie scheinen an dieser Idee festzuhalten, dass ein linearer Z-Puffer nur funktionieren würde, wenn wir nicht durch W teilen würden. Aber es wird nicht funktionieren - es wird nicht richtig im Bildschirmbereich interpolieren.
Nathan Reed