но я до сих пор не знаю, является ли 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](https://i.stack.imgur.com/qid6a.png)
Матрица ортографической проекции:
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](https://i.stack.imgur.com/oZFWt.png)
Перспективная проекция
В Перспективной проекции матрица проекции описывает отображение из трехмерных точек мира, как они видны из камеры-обскуры, в двумерные точки области просмотра.Координаты пространства глаза в усечении камеры (усеченная пирамида) отображаются в куб (нормализованные координаты устройства).
![Perspective Projection](https://i.stack.imgur.com/RYlMY.png)
Матрица перспективной проекции:
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](https://i.stack.imgur.com/C84Pz.png)
Буфер глубины
Поскольку нормализованные координаты устройства находятся в диапазоне (-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