Lineare Z-Werte in Render-Target schreiben

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Stefan Zerbst
Moderator
Beiträge: 189
Registriert: 25.02.2009, 19:54

Lineare Z-Werte in Render-Target schreiben

Beitrag von Stefan Zerbst »

Hi,

die Frage steht schon in der Überschrift. Ich möchte mir eine Textur mit den linearen Z-Werten meiner Szene im View-Space schreiben. Je mehr ich danach google desto mehr bin ich aber verwirrt. Die dort zu findenden Lösungen reichen von "teile einfach das transformierte z durch w" über "addiere Z-Near zu transformiertem z und teile durch (Z-Far - Z-Near)" bis hin zu noch komplexeren Formeln wo das Produkt aus Z-Near und Z-Far durch (Z-Far - z * (Z-Far - Z-Near)) geteilt wird.

Daher die Frage wie macht man das richtig? Warum gibt es so viele verschiedene Formen? ... ich bin verwirrt :o

Ciao,
Stefan
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Krishty »

Warum denn? Für Postprocessing eignen sich Distanzwerte deutlich besser als Z-Werte …

ZNear aufzuaddieren und durch (Z-Far - Z-Near) zu teilen klingt am plausibelsten, da die Far-Clipping-Plane auf eins und die Near-Clipping-Plane auf Null abgebildet werden und man dabei ja quasi genau die Projektionsmatrix rückgängig macht. Was die übrigen Formeln sollen erschließt sich mir auch nicht.

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Zudomon
Establishment
Beiträge: 2253
Registriert: 25.03.2009, 07:20
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Zudomon »

Ich bin mir nicht sicher, aber ich habe da noch sowas im Hinterkopf, das die Werte nach der ViewMatrix erstmal alle in einem Würfel abgebildet werden, dessen Werte von -1 bis 1 gehen. Bin mir aber absolut nicht sicher ;)
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Jörg »

Es gibt verschiedene Formeln, je nach Aufbau deiner Projektions-Matrix.
Moechtest Du den Z-Buffer wiederverwenden? Dann schau Dir zur Mathematik einfach den Abschnitt im DX-SDK uebe die Projektionsmatrix an, wen Du diese Formel verwendest. Wenn Dich diese Werte nicht interessieren, kannst Du einfach im Pixelshader die von Krishty beschriebene Methode verwenden, es um pro Pixel auszurechnen.
-1...1 ist die OpenGL-Notation.
Stefan Zerbst
Moderator
Beiträge: 189
Registriert: 25.02.2009, 19:54

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Stefan Zerbst »

Hi,

Danke für die Antworten. Ich wollte mal SSAO ausprobieren und wenn ich die Artikel dazu richtig verstanden habe arbeiten die mit einem linearen Depth-Buffer von 0.0 bis 1.0 als Input? Vorerst hat mich nur mal interessiert warum man so viele verschiedene Ergebnisse findet wenn man nach dem Schreiben der Depth-Werte per Shader sucht.

Ciao,
Stefan
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Jörg »

Ganz einfach: Solange die Relation zwischen Z-Werten durch die Art der Abbildung nicht gestoert wird, funktioniert der ZBuffer immer. Mathematisch gesehen. Leider machen einem die wert-begrenzten Darstellungen einen Strich durch die Rechnung. In gewissen Massen kann man mit verschiedenen Formeln fuer "Z nach der Projektion" Darstellungsfehler vermeiden bzw. in andere Bereiche schieben, in denen sie nicht so stark auffallen.
Extrembeispiel: Mathematisch ist es ja wurscht, ob ich einen invertierten Z-Buffer habe oder nicht (solange ich die Relation entsprechend aendere, die ich beim Einzeichnen verwende). Bezogen auf visuelle Artefakte kann das schon einen Unterschied machen.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Schrompf »

Nach der Projektionsmatrix ist z doch linear im Bereich 0 bis 1. Du musst es nur vor der perspektivischen Division abgreifen. Wenn Du Z von Znear bis ZFar brauchst, greifst Du es halt schon nach der ViewMatrix ab. Eine Normierung würde ich aber empfehlen, zumindest eine Division durch ZFar. Evtl. noch aufspreizen auf (-1, +1), um bei Fließkommaformaten noch ein Bit Genauigkeit hinzuzubekommen, aber dadurch bekommst Du dann auch eine etwas krumme Genauigkeitsverteilung, die ihr Maximum ausgerechnet in der Mitte des Wertebereichs hat... evtl. nicht ganz das, was man für SSAO braucht :-)

Wenn Du auch hier mit fp32 arbeitest, kann Dir das sowieso alles schnuppe sein. In dem Fall würde ich auf jede Normierung verzichten, damit die Zahlen beim Debuggen vorstellbar bleiben.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Jörg »

Nach der Projektionsmatrix ist z doch linear im Bereich 0 bis 1. Du musst es nur vor der perspektivischen Division abgreifen.
Nur teilweise korrekt. Freilich ist es linear vor der Division, aber nicht nur im Bereich 0..1. Ohne Division hast Du den vollen World-Space-Bereich fuer Z. Nach der Division ist es nicht mehr linear, aber 0...1 (bei DX) entsprechen dem Bereich zwischen near- und far-Plane. Da liegt der Unterschied zwischen selbst pro Pixel ausrechnen (da kann man es linear auf 0..1 skalieren) oder dem verwenden der Hardware-Puffer, welche es nicht-linear speichern (man schlage mich jetzt nicht mit W-Buffern ;) , die habe ich lange nicht angefasst).
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Schrompf »

Stimmt, mein Fehler: Post-Projection-Z wird erst durch die perspektivische Divison in den Bereich (0,+1) abgebildet.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Stefan Zerbst
Moderator
Beiträge: 189
Registriert: 25.02.2009, 19:54

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Stefan Zerbst »

Hi,

erstmal wieder ein fettes Danke für die weitere Aufklärungsarbeit. Ich glaube ich bin der grafischen Front etwas zu lange abtrünnig gewesen, jedenfalls auf dieser Ebene :)

Wenn ich also im Vertex-Shader mit World-View-Projection multipliziere habe ich in z des transformierten Vertex die Tiefenwerte von der Near-Plane bis zu dem transformierten Vertex in Weltkoordinaten wenn ich das jetzt richtig sehe. Die Spielchen mit Addieren von Z-Near und teilen durch Differenz von Z-Far und Z-Near dient also dazu diesen Wert auf den Bereich [0,1] zu bringen und zwar im Vertex-Shader.

Der Pespective Divide folgt erst zwischen Vertex-Shader und Pixel-Shader. Das heisst wenn ich die Position aus dem Vertex- an den Pixel-Shader als Position gebe kommt dort der nicht-lineare Z-Wert an? Ich müsste mir den Wert aus dem Vertex-Shader also in einem anderen Register als Depth speichern wenn ich ihn linear in den Pixel-Shader retten möchte?

Danke für Eure Gedult.

Ciao,
Stefan
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Jörg »

Korrekt, wenn Du im Vertex-Shader (z-zNear)/(zFar-zNear) an den Pixelshader weiterreichst, erhaeltst Du dort lineare, normierte Z-Werte, anhand derer Du ohne Division jederzeit die Kamera-bezogene Tiefe zurueckrechnen kannst.
Ist am Ende nur ein Trade-Off, den einen Wert bekommst Du 'gratis', dafuer ist die Rueckrechnung etwas umstaendlicher, den anderen Wert nur, wenn Du noch Pixel-Inputs frei hast und mit mehr an Interpolator-Rechenleistung leben willst.
Stefan Zerbst
Moderator
Beiträge: 189
Registriert: 25.02.2009, 19:54

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Stefan Zerbst »

Wenn ich das im Vertex-Shader entsprechend normiere dann brauche ich den Pixel-Input und Interpolator Power, wobei sich letztere nicht so dramatisch bemerkbar machen dürfte, oder? Ist ja nur eine lineare Inteprolation. Zwar pro Pixel aber wenn ich statt dessen im Pixel-Shader etwas ausrechnen würde wäre das vom Speed her sicherlich langsamer.

Was wäre denn die Alternative um im Pixel-Shader aus dem "normalen" Z-Wert, also dem nicht-linearen, den linearen Wert zurückzurechnen. Die eigentliche Distanz brauche ich nicht, das normierte reicht (zumindest vorerst) weil es beim SSAO ja nur darum geht die Tiefenwerte benachbarter Pixel zu vergleichen. Eventuell kann man noch die Normale eines Pixels mit einbeziehen. Auf Deferred Shading wollte ich mich später erst werfen, dabei braucht man glaube ich die tatsächlichen Distanzen im View-Space im Pixel-Shader?!

Ciao,
Stefan
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Krishty »

Stefan Zerbst hat geschrieben:Wenn ich das im Vertex-Shader entsprechend normiere dann brauche ich den Pixel-Input und Interpolator Power, wobei sich letztere nicht so dramatisch bemerkbar machen dürfte, oder? Ist ja nur eine lineare Inteprolation. Zwar pro Pixel aber wenn ich statt dessen im Pixel-Shader etwas ausrechnen würde wäre das vom Speed her sicherlich langsamer.
Nein - AMD empfiehlt ab der HD-2000-Reihe sogar, im Pixel-Shader SV_Position mit invertierter Projektion zurückzutransformieren falls man auf die Weltkoordinate angewiesen ist, weil es immernoch schneller ist als einen weiteren Vektor zu interpolieren.

Das hier kann von Interesse sein.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Jörg »

Krishty hat geschrieben:AMD empfiehlt ab der HD-2000-Reihe sogar, im Pixel-Shader SV_Position mit invertierter Projektion zurückzutransformieren
Ich dachte, das bezog sich nur auf den Throughput in Verbindung mit einem akiven Geometrie-Shader....hast Du einen Link?
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Krishty »

Ja, den heißgeliebten ATI Radeon HD 2000 Programming Guide („Keep data small“), aber jetzt wo ich es mir nochmal ansehe hast du (wieder mal :D) völlig Recht:
This wisdom still holds true if you’re using a vertex and pixel shader only.
Der Absatz hatte wohl, zusammen mit ein ständigen Interpolator-Bottlenecks im GPU Shader Analyzer, in meinem Kopf ein falsches Bild über Interpolatoren geformt …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Stefan Zerbst
Moderator
Beiträge: 189
Registriert: 25.02.2009, 19:54

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Stefan Zerbst »

Hi,

also ich vergaß zu erwähnen, dass ich noch im DX9 Bereich bin. Das gibt es das SV_Position.z gar nicht :)

Performance ist im Moment auch nicht mein oberstes Ziel. Ich möchte es erstmal am Laufen haben (wenn ich denn mal Zeit finde was umzusetzen *g*). Aber gut zu wissen ist es trotzdem wo es zu Bottlenecks kommen kann. Ich hätte nicht erwartet, dass Berechnungen im Pixel Shader effizienter sein können als einmal float Daten zu interpolieren. Aber wenn sich das erstmal nur auf die Kombination mit Geometry-Shadern bezieht dann bin ich beruhigt. :)

Ciao,
Stefan
Stefan Zerbst
Moderator
Beiträge: 189
Registriert: 25.02.2009, 19:54

Re: Lineare Z-Werte in Render-Target schreiben

Beitrag von Stefan Zerbst »

Hi,

nun habe ich endlich mal drei Stündchen Zeit gefunden wenigstens den linearen Depth-Buffer in Angriff zu nehmen und wollte euch das Ergebnis nicht vorenthalten. Die Interfaces meiner Engine musste ich dazu noch etwas pimpen, aber das Ergebnis scheint so weit richtig zu sein. Mein Fokus liegt im Moment auf der Simplizität des Interfaces für mein HDR-Rendering. Das folgende Bild zeigt oben den linearen Depth-Buffer und darunter die zugehörige Szene im Endergebnis, wobei die lineare Depth noch zu gar nix in der HDR Pipeline benutzt wird. Die Szene besteht aus wahllos verteilten und gestrechten Würfeln mit dezent grellem Material und einem rotierenden Würfel im Vordergrund mit mega-übertrieben grellem Material :mrgreen:

Bild

Ciao,
Stefan
Antworten