Глубина как расстояние до плоскости камеры в GLSL
У меня есть пара шейдеров GLSL, которые дают мне карту глубины объектов в моей сцене. Теперь я получаю расстояние от каждого пикселя до камеры. Мне нужно получить расстояние от пикселя до плоскости камеры. Позвольте мне проиллюстрировать это небольшим рисунком
* |--*
/ |
/ |
C-----* C-----*
\ |
\ |
* |--*
3 звездочки - это пиксели, а C - камера. Строки от звездочек - это "глубина". В первом случае я получаю расстояние от пикселя до камеры. Во втором я хочу получить расстояние от каждого пикселя до плоскости.
Должен быть способ сделать это, используя некоторую матрицу проекции, но я в тупике.
Вот шейдеры, которые я использую. Обратите внимание, что eyePosition - это camera_position_object_space.
Вершинный шейдер:
void main() {
position = gl_Vertex.xyz;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Пиксельный шейдер:
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);
}
3 ответа
Вы действительно пытаетесь сделать это трудным путем. Просто преобразуйте вещи в пространство камеры и работайте оттуда.
varying float distToCamera;
void main()
{
vec4 cs_position = glModelViewMatrix * gl_Vertex;
distToCamera = -cs_position.z;
gl_Position = gl_ProjectionMatrix * cs_position;
}
В пространстве камеры (пространство, где все относительно положения / ориентации камеры), плоское расстояние до вершины является просто отрицательной по координате Z (более высокий отрицательный Z находится дальше).
Так что ваш фрагментный шейдер даже не нужен eyePosition
; "Глубина" исходит непосредственно из вершинного шейдера.
Компонент W после проекции содержит ортогональную глубину в сцене. Для этого вам не нужно использовать отдельные матрицы моделей и проекций:
varying float distToCamera;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
distToCamera = gl_Position.w;
}
То, на что вы намекаете, это ортографическая проекция. Вы в настоящее время используете перспективную проекцию. На самом деле у вас нет истинного расстояния от пикселя до камеры, а скорее положение z пикселя в усечённой области. На визуализированной текстуре отображается конечная глубина z в диапазоне [-1,1], которая описывает ее компонент z в пространстве NDC.
Как вы понимаете, все ваши точки проецируются в направлении (на самом деле на ближнюю плоскость) камеры с использованием перспективной проекции. То, что вы хотите, это проецировать их орфографически на ближнюю плоскость. Эта ссылка подробно описывает обе проекционные матрицы, а окончательный результат матрицы находится внизу. Ваши шейдеры должны уметь справляться с новой проекционной матрицей. Просто убедитесь, что ваша матрица MVP рассчитана, как предложено выше.
Обратите внимание, что ортографическая проекция, вероятно, не отражает глубину вашей отрисованной сцены. Если вы визуализируете свою сцену на экране с перспективной проекцией, и вы хотите глубину каждого пикселя, вы должны соответственно использовать ту же перспективную проекцию. Таким образом, рендеринг вашей глубины с использованием ортографической проекции будет полезен только в том случае, если ваша сцена использует ту же проекцию, или если для какого-либо алгоритма требуется информация о глубине, не связанная со сценой, как видно на экране.
Кроме того, я предлагаю взглянуть на основные профили OpenGL (3.x), так как вы, кажется, используете устаревшую функциональность (gl_Vertex, gl_ModelViewProjectionMatrix и другие). Немного больше работы, чтобы настроить все буферы и шейдеры самостоятельно, но в итоге это окупается.
РЕДАКТИРОВАТЬ
Собственно, после вашего комментария я понимаю, что вы хотите. Не было ясно, что вы хотите отобразить их в одном вызове, для этого я предлагаю нечто подобное в вашем фрагментном шейдере:
uniform mat4 orthographicMatrix;
varying vec3 position;
void main(void) {
vec4 clipSpace = orthographicMatrix * vec4(position, 1.0);
gl_FragColor = vec4(clipSpace.zzz, 1.0);
}
Обратите внимание, что вам не нужно делать деление w, так как ортографическая проекция уже линейна (таким образом, w установлен в 1).