¿Cómo se puede representar la profundidad de forma lineal en OpenGL moderno con gl_FragCoord.z ​​en fragment shader?

Leí mucha información sobre cómo obtener profundidad con el sombreador de fragmentos.

como

http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=234519

pero todavía no sé si el gl_FragCoord.z es lineal.

La especificación GLSL dice que su rango es [0,1] en tamaño de pantalla sin mencionar que es lineal o no.

Creo que la linealidad es vital ya que usaré el modelo renderizado para unir el mapa de profundidad de Kinect.

Entonces, si no es lineal, ¿cómo linearizarlo en el espacio del mundo?

pero todavía no sé si el gl_FragCoord.z ​​es lineal.

Si gl_FragCoord.z es lineal o no, depende de la matriz de proyección. Mientras que para la proyección ortográfica, gl_FragCoord.z es lineal, para la proyección de perspectiva no es lineal.

En general, la profundidad ( gl_FragCoord.z y gl_FragDepth ) se calcula de la siguiente manera (ver GLSL gl_FragCoord.z ​​Cálculo y configuración gl_FragDepth ):

 float ndc_depth = clip_space_pos.z / clip_space_pos.w; float depth = (((farZ-nearZ) * ndc_depth) + nearZ + farZ) / 2.0; 

La matriz de proyección describe el mapeo de los puntos 3D de una escena, a los puntos 2D de la ventana gráfica. Se transforma del espacio visual al espacio del clip, y las coordenadas en el espacio del clip se transforman en las coordenadas del dispositivo normalizado (NDC) dividiendo con el componente w de las coordenadas del clip

Proyección ortográfica

En la proyección ortográfica, las coordenadas en el espacio del ojo se mapean linealmente a las coordenadas del dispositivo normalizado.

Proyección ortográfica

Matriz de proyección ortográfica:

 r = right, l = left, b = bottom, t = top, n = near, f = far 2/(rl) 0 0 0 0 2/(tb) 0 0 0 0 -2/(fn) 0 -(r+l)/(rl) -(t+b)/(tb) -(f+n)/(fn) 1 

En la proyección ortográfica, el componente Z se calcula mediante la función lineal :

 z_ndc = z_eye * -2/(fn) - (f+n)/(fn) 

Función ortográfica Z

Proyección de perspectiva

En Perspective Projection, la matriz de proyección describe el mapeo de los puntos 3D en el mundo tal como se ven desde una cámara estenopeica, hasta los puntos 2D de la ventana gráfica.
Las coordenadas del espacio visual en la cámara troncocónica (una pirámide truncada) se asignan a un cubo (las coordenadas del dispositivo normalizado).

Proyección de perspectiva

Matriz de proyección de perspectiva:

 r = right, l = left, b = bottom, t = top, n = near, f = far 2*n/(rl) 0 0 0 0 2*n/(tb) 0 0 (r+l)/(rl) (t+b)/(tb) -(f+n)/(fn) -1 0 0 -2*f*n/(fn) 0 

En Perspective Projection, el componente Z se calcula mediante la función racional :

 z_ndc = ( -z_eye * (f+n)/(fn) - 2*f*n/(fn) ) / -z_eye 

Función de perspectiva Z

Buffer de profundidad

Como las coordenadas del dispositivo normalizado están en el rango (-1, -1, -1) a (1,1,1), la coordenada Z debe asignarse a la profundidad de la memoria en el rango [0,1]:

 depth = (z_ndc + 1) / 2 

Entonces, si no es lineal, ¿cómo linealizarlo en el espacio del mundo?

Para convertir desde la profundidad del búfer de profundidad a la coordenada Z original, debe conocerse la proyección (ortográfica o perspectiva), y el plano cercano y el plano lejano.

Proyección ortográfica

 n = near, f = far z_eye = depth * (fn) + n; 

Proyección de perspectiva

 n = near, f = far z_ndc = 2.0 * depth - 1.0; z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n)); 

Si se conoce la matriz de proyección en perspectiva, esto se puede hacer de la siguiente manera:

 A = prj_mat[2][2] B = prj_mat[3][2] z_eye = B / (A + z_ndc) 

Ver también la respuesta a

Cómo recuperar la posición del espacio de visualización dado el valor de la profundidad del espacio de visualización y ndc xy

Una vez que se proyecta pierde su linealidad, gl_FragCoord.z no es lineal.

Para volver a lineal, debe realizar 2 pasos:

1) Transforma la variable gl_FragCoord.z a las coordenadas de los dispositivos normalizados en el rango [-1, 1]

 z = gl_FragCoord.z * 2.0 - 1.0 

2) Aplicar el inverso de la matriz de proyección (IP). (Puede usar valores arbitrarios para xey) y normalizar para el último componente.

 unprojected = IP * vec4(0, 0, z, 1.0) unprojected /= unprojected.w 

obtendrá un punto en el espacio de vista (o espacio de cámara, lo que quiera) que tenga una z lineal entre znear y zfar.

Depende de usted decidir si quiere Z lineal o no, todo se basa en su matriz de proyección. Puedes leer esto:

http://www.songho.ca/opengl/gl_projectionmatrix.html

Lo que explica muy bien cómo funcionan las matrices de proyección. Puede ser mejor tener Z no lineal para tener una mejor precisión en primer plano y menos en los fondos, los artefactos de profundidad son menos visibles cuando está lejos …

Si gl_FragCoord.z es lineal o no depende de su matriz de transformación. gl_FragCoord.z se determina calculando gl_Position.z / gl_Position.w para todos los vértices de tu triángulo y luego interpolando el resultado sobre todos los fragmentos de ese triángulo.

Entonces gl_FragCoord.z es lineal cuando su matriz de transformación asigna un valor constante a gl_Position.w (que generalmente ocurre con las matrices de orto proyección) y no es lineal cuando gl_Position.w depende de la coordenada x , y , o z de su vector de entrada (lo que sucede con las matrices de proyección en perspectiva ).

Intereting Posts