2013-04-21 6 views
5

Ich habe ein Paar GLSL Shader, die mir die Tiefenkarte der Objekte in meiner Szene geben. Was ich jetzt bekomme, ist die Entfernung von jedem Pixel zur Kamera. Was ich brauche, ist die Entfernung vom Pixel zur Kameraebene. Lassen Sie mich mit einer kleinen Zeichnung veranschaulichenTiefe als Abstand zur Kameraebene in GLSL

*   |--* 
/   | 
/   | 
C-----*  C-----* 
\   | 
    \   | 
    *   |--* 

Die 3 Sterne sind Pixel und das C ist die Kamera. Die Linien von den Sternchen sind die "Tiefe". Im ersten Fall erhalte ich den Abstand vom Pixel zur Kamera. In der zweiten möchte ich die Entfernung von jedem Pixel zum Flugzeug erhalten.

Es muss einen Weg geben, dies zu tun, indem Sie eine Projektionsmatrix verwenden, aber ich bin ratlos.

Hier sind die Shader, die ich benutze. Beachten Sie, dass eyePosition camera_position_object_space ist.

Vertex Shader:

void main() { 
    position = gl_Vertex.xyz; 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
} 

Pixel Shader:

uniform vec3 eyePosition; 
varying vec3 position; 


void main(void) { 
     vec3 temp = vec3(1.0,1.0,1.0); 
     float depth = (length(eyePosition - position*temp) - 1.0)/49.0; 
     gl_FragColor = vec4(depth, depth, depth, 1.0); 
} 
+0

Welche Art von Projektion verwenden Sie? Wenn Sie beim Rendern der Tiefenkarte eine orthographische Projektion verwenden, sollten Sie alles, was Sie benötigen, ohne Berechnungen erhalten. – Ani

+0

Ich mache perspektivische Projektion beim Rendern, aber ich brauche die Tiefenwerte von der orthographischen Projektion. – Lucian

Antwort

9

Sie versuchen wirklich, dies auf die harte Tour zu tun. Verwandle einfach Dinge in den Kameraraum und arbeite von dort aus.

varying float distToCamera; 

void main() 
{ 
    vec4 cs_position = glModelViewMatrix * gl_Vertex; 
    distToCamera = -cs_position.z; 
    gl_Position = gl_ProjectionMatrix * cs_position; 
} 

In Kameraraum (der Raum, in dem alles auf die Position/Orientierung der Kamera relativ ist), der planare Abstand zu einem Scheitelpunkt ist nur das Negativ der Z-Koordinate (höhere negative Z weiter entfernt ist).

So benötigt Ihr Fragment Shader nicht einmal eyePosition; Die "Tiefe" kommt direkt vom Vertex-Shader.

+0

Du hast Recht, ich habe es irgendwie auf die harte Tour gemacht. Außerdem nehme ich an, dass -cs.z -cs_position.z ist. Danke für das Code-Snippet! – Lucian

1

Was Sie anspielend auf ist orthographische Projektion. Sie verwenden derzeit die perspektivische Projektion. Tatsächlich haben Sie nicht den wahren Abstand vom Pixel zur Kamera, sondern die z-Position des Pixels im Kegelstumpf. Auf der gerenderten Textur wird die endgültige z-Tiefe im Bereich von [-1,1] gerendert, die ihre z-Komponente im NDC-Raum beschreibt.

Wie Sie verstehen, werden alle Ihre Punkte mit einer perspektivischen Projektion "auf" (wirklich auf die nahe Ebene) projiziert. Sie wollen sie orthographisch auf die nahe Ebene projizieren. This link beschreibt beide Projektionsmatrizen im Detail, und das Endergebnis der Matrizen ist unten. Ihre Shader sollten mit der neuen Projektionsmatrix gut umgehen können. Stellen Sie nur sicher, dass Ihre MVP-Matrix wie oben vorgeschlagen berechnet wird.

Hinweis: Die orthografische Projektion repräsentiert wahrscheinlich nicht die Tiefe Ihrer gerenderten Szene. Wenn Sie Ihre Szene mit einer perspektivischen Projektion auf den Bildschirm rendern und die Tiefe jedes Pixels festlegen möchten, sollten Sie die gleiche perspektivische Projektion entsprechend verwenden. Das Rendern mit der orthografischen Projektion wäre also nur dann sinnvoll, wenn Ihre Szene die gleiche Projektion verwendet oder wenn ein Algorithmus Tiefeninformationen benötigt, die nicht mit der auf dem Bildschirm angezeigten Szene zusammenhängen.

Ich schlage außerdem vor, Kern OpenGL-Profile (3.x) zu betrachten, wie Sie scheinen, veraltete Funktionalität (gl_Vertex, gl_ModelViewProjectionMatrix und ähnliche) zu verwenden. Es ist etwas mehr Arbeit, alle Puffer und Shader selbst einzurichten, aber es zahlt sich am Ende aus.

EDIT

Eigentlich nach dem Kommentar, verstehe ich, was Sie wollen. Es war nicht klar, dass man sie in dem gleichen Anruf machen wollte, denn das ich so etwas wie diesen Shader in Ihrem Fragmente vorschlagen:

uniform mat4 orthographicMatrix; 
varying vec3 position; 

void main(void) { 
     vec4 clipSpace = orthographicMatrix * vec4(position, 1.0); 
     gl_FragColor = vec4(clipSpace.zzz, 1.0); 
} 

Hinweis Sie müssen nicht die w divide tun, wie die Orthogonalprojektion ist linear bereits (also wird w auf 1 gesetzt).

+0

Danke für die ausführliche Antwort. Ich versuche, die Tiefe zu erhalten, die der orthogonalen Projektion entspricht, während sie entsprechend der perspektivischen Projektion rendert. Das mag merkwürdig erscheinen, aber das muss ich tun. – Lucian

+0

Oh, ich verstehe, ich verstehe, was du meintest. Hat meinen Beitrag bearbeitet. – Invalid

1

W-Komponente nach Projektion enthält die orthogonale Tiefe in die Szene. Sie müssen dazu keine separaten Modellansichten und Projektionsmatrizen verwenden:

varying float distToCamera; 

void main() 
{ 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
    distToCamera = gl_Position.w; 
} 
+0

Tut es? Ist es nicht 'gl_Position.z/gl_Position.w'? – RecursiveExceptionException