2012-04-22 9 views
17

Also, ich habe einen Betrüger (die echte Geometrie ist ein Würfel, möglicherweise abgeschnitten, und die Betrüger Geometrie ist ein Menger Schwamm) und ich muss seine Tiefe berechnen.GLSL gl_FragCoord.z ​​Berechnung und Einstellung gl_FragDepth

Ich kann die Menge berechnen, um im Weltbereich ziemlich leicht zu versetzen. Leider habe ich Stunden damit verbracht, die Tiefe nicht zu stören.

Die einzig richtige Ergebnisse kann ich, wenn ich gehen:

gl_FragDepth = gl_FragCoord.z 

Grundsätzlich muss ich wissen, wie gl_FragCoord.z ​​berechnet wird, so dass ich kann:

  • die inverse Transformation Nehmen von gl_FragCoord.z ​​in den Augenraum
  • Fügen Sie die Tiefenstörung hinzu
  • Transformieren Sie diese gestörte Tiefe zurück in den gleichen Raum wie das Original gl_FragCoord.z.

Ich entschuldige mich, wenn dies wie eine doppelte Frage scheint; Es gibt eine Reihe von anderen Posts, die ähnliche Dinge ansprechen. Nach der Implementierung von allen funktioniert jedoch keiner ordnungsgemäß. Anstatt zu versuchen, einen auszuwählen, um Hilfe zu bekommen, frage ich an dieser Stelle nach komplettem Code, der das tut. Es sollte nur ein paar Zeilen sein.

+0

Haben Sie auch einen Vertex-Shader geschrieben? oder nur ein Fragment-Shader? –

+2

Ich werde Ihnen keinen Code im Allgemeinen geben, aber ich kann Ihnen [diesen Link zum OpenGL Wiki] (http://www.opengl.org/wiki/Compute_eye_space_from_window_space) geben. Sowie diesen Link zu einem Tutorial von mir auf [Betrüger und Tiefe, die zeigt, wie dies auch zu tun] (http://www.arcsynthesis.org/gltut/Illumination/Tut13%20Deceit%20in%20Depth.html). Die Tiefe zurück zu transformieren ist trivial. –

+0

Michael: Ja, aber es ist nur ein Durchlauf durch Shader.Wie dem auch sei, die Berechnungen werden im Welt-Raum durchgeführt, sodass ich den Augenraum im Fragment-Programm berechnen kann. Nicol, ich hatte diese Seite schon gesehen. Ich implementiere es als: vec4 clip_pos = gl_ProjectionMatrix * vec4 (eye_pos, 1.0); float ndc_depth = clip_pos.z/clip_pos.w; gl_FragDepth = (((clip_far-clip_near) * ndc_depth) + clip_near + clip_far)/2.0; Leider scheint die Tiefe außerhalb des Tiefenbereichs zu liegen, obwohl kein Offset vorhanden ist. Danke, – imallett

Antwort

28

Für die Zukunft, der Schlüssel-Code ist:

float far=gl_DepthRange.far; float near=gl_DepthRange.near; 

vec4 eye_space_pos = gl_ModelViewMatrix * /*something*/ 
vec4 clip_space_pos = gl_ProjectionMatrix * eye_space_pos; 

float ndc_depth = clip_space_pos.z/clip_space_pos.w; 

float depth = (((far-near) * ndc_depth) + near + far)/2.0; 
gl_FragDepth = depth; 
+0

Sollte nicht "gl_DepthRange.far" und "gl_DepthRange.near;" ersetzt werden mit den Nah- und Fernbereichen der Projektionsmatrix anstelle der Clip-Ebenen-Werte? – Tara

+0

Überhaupt nicht. gl_DepthRange ist nicht dasselbe wie die Werte für die Nähe und die Ferne, die zur Berechnung der Projektionsmatrix verwendet werden. Ich könnte jedoch Ihren Standpunkt missverstehen. – Tara

+0

@Dudeson Die Clip-Ebenen bestimmen einfach über die Projektionsmatrix, welche Werte außerhalb des NDC abgebildet werden (und daher von der Hardware abgeschnitten werden). Wir sind mit ihnen fertig, nachdem die Projektionsmatrix spezifiziert wurde. "Gl_DepthRange. (Ne | f) ar" ist der Bereich des Tiefenpuffers und wird benötigt, um von NDC in den Tiefenpuffer zu konvertieren. HTH – imallett

4

Für eine andere Zukunft, das die gleiche Formel wie durch imallett gegeben, die in einer OpenGL-4.0-Anwendung für mich gearbeitet:

vec4 v_clip_coord = modelview_projection * vec4(v_position, 1.0); 
float f_ndc_depth = v_clip_coord.z/v_clip_coord.w; 
gl_FragDepth = (1.0 - 0.0) * 0.5 * f_ndc_depth + (1.0 + 0.0) * 0.5; 

Hier ist modelview_projection 4x4 modelview-projection matrix und v_position ist objektraum position des pixels gerendert (in meinem fall berechnet von einem raymarcher).

Die Gleichung stammt aus dem window coordinates Abschnitt von this manual. Beachten Sie, dass in meinem Code in der Nähe ist 0.0 und weit ist 1.0, die die Standardwerte von gl_DepthRange sind. Beachten Sie, dass gl_DepthRange ist nicht das gleiche wie die nahe/ferne Entfernung in der Formel für perspective projection matrix! Der einzige Trick ist die Verwendung der 0.0 und 1.0 (oder gl_DepthRange für den Fall, dass Sie es wirklich ändern müssen), habe ich für eine Stunde mit dem anderen Tiefenbereich gekämpft - aber das ist bereits "gebacken" in meiner (Perspektive) Projektionsmatrix .

Beachten Sie, dass auf diese Weise die Gleichung wirklich nur eine einzige Multiplikation mit einer Konstante ((far - near)/2) und eine einzelne Addition einer anderen Konstante ((far + near)/2) enthält. Vergleichen Sie das, um zu multiplizieren, addieren und dividieren (möglicherweise in eine Multiplikation mit einem optimierenden Compiler konvertiert), die im Code von imallett benötigt wird.