Как визуализировать глубину линейно в современном OpenGL с gl_FragCoord.z ​​во фрагментном шейдере? - PullRequest
8 голосов
/ 15 октября 2011

Я прочитал много информации о получении глубины с помощью фрагментного шейдера.

, например

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

, но я до сих пор не знаю, является ли gl_FragCoord.z является линейным.

В спецификации GLSL сказано, что его диапазон составляет [0,1] на экране, не говоря уже о том, линейный он или нет.

Я думаю, что линейность очень важна, поскольку я буду использовать визуализированную модель для сопоставления с картой глубины.из Kinect.

Тогда, если он не является линейным, как линеаризовать его в мировом пространстве?

Ответы [ 4 ]

20 голосов
/ 16 августа 2017

но я до сих пор не знаю, является ли gl_FragCoord.z ​​линейным.

Является ли gl_FragCoord.z линейным или нет, зависит от матрицы проекции.В то время как для ортогональной проекции gl_FragCoord.z является линейной, для перспективной проекции она не является линейной.

В общем, глубина (gl_FragCoord.z и gl_FragDepth) рассчитывается следующим образом (см. GLSL gl_FragCoord.z Расчет и настройка gl_FragDepth ):

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

Матрица проекции описывает отображение от трехмерных точек сцены к двухмерным точкам области просмотра.Он преобразуется из пространства глаза в пространство клипа, а координаты в пространстве клипа преобразуются в нормализованные координаты устройства (NDC) путем деления на w компонент координат клипа

ОрфографическийПроекция

При ортогональной проекции координаты в глазном пространстве линейно отображаются на нормализованные координаты устройства.

Orthographic Projection

Матрица ортографической проекции:

r = right, l = left, b = bottom, t = top, n = near, f = far 

2/(r-l)         0               0               0
0               2/(t-b)         0               0
0               0               -2/(f-n)        0
-(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1

В ортогональной проекции компонент Z вычисляется с помощью линейной функции :

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

Orthographic Z function

Перспективная проекция

В Перспективной проекции матрица проекции описывает отображение из трехмерных точек мира, как они видны из камеры-обскуры, в двумерные точки области просмотра.Координаты пространства глаза в усечении камеры (усеченная пирамида) отображаются в куб (нормализованные координаты устройства).

Perspective Projection

Матрица перспективной проекции:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0               0
0              2*n/(t-b)      0               0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)    0

При перспективной проекции компонент Z вычисляется с помощью рациональной функции :

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

Perspective Z function

Буфер глубины

Поскольку нормализованные координаты устройства находятся в диапазоне (-1, -1, -1) - (1,1,1), координата Z должна быть отображена на глубину в диапазоне [0,1]:

depth = (z_ndc + 1) / 2 

Тогда, если он не является линейным, как линеаризовать его в мировом пространстве?

Чтобы преобразовать глубину буфера глубины в исходную Z-координату,проекция (ортогональная или перспективная), а также ближняя и дальняя плоскости должны быть известны.

ортографическая проекция

n = near, f = far

z_eye = depth * (f-n) + n;

перспективная проекция

n = near, f = far

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

Если матрица перспективной проекции известна, это можно сделать следующим образом:

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

См. Также ответ на

Как восстановитьпросмотр позиции пространства с учетом значения глубины просмотра пространства и ndc xy

8 голосов
/ 17 мая 2013

Как только он спроецирован, он теряет линейность, gl_FragCoord.z не является линейным.

Чтобы вернуться к линейному режиму, необходимо выполнить 2 шага:

1) Преобразовать переменную gl_FragCoord.z внормализованные координаты устройства в диапазоне [-1, 1]

z = gl_FragCoord.z * 2.0 - 1.0 

2) Применить обратную матрицу проекции (IP).(Вы можете использовать произвольные значения для x и y) и нормализовать для последнего компонента.

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

вы получите точку в пространстве вида (или в пространстве камеры, назовите его) с линейным zмежду znear и zfar.

2 голосов
/ 16 декабря 2015

Является ли gl_FragCoord.z линейным или нет, зависит от вашей матрицы преобразования. gl_FragCoord.z определяется путем вычисления gl_Position.z / gl_Position.w для всех вершин вашего треугольника и последующей интерполяции результата по всем фрагментам этого треугольника.

Таким образом, gl_FragCoord.z является линейным, когда ваша матрица преобразования назначает постоянное значение для gl_Position.w (что обычно происходит с ortho матрицами проекций) и является нелинейной, когда gl_Position.w зависит от x, y или z координата входного вектора (что происходит с перспективными матрицами проекций).

2 голосов
/ 15 октября 2011

Вам решать, хотите ли вы линейный Z или нет, все зависит от вашей матрицы проекции. Вы можете прочитать это:

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

Что очень хорошо объясняет, как работает проекционная матрица. Может быть лучше иметь нелинейный Z, чтобы иметь лучшую точность на переднем плане и меньше на заднем плане, артефакты глубины менее заметны на большом расстоянии ...

...