OpenGL Как вычислить координаты мирового пространства из выровненных векторов усеченной пирамиды?

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

Идея заключалась в том, чтобы визуализировать несколько плоскостей как вертикальные срезы по усеченной области обзора, а затем использовать мировые координаты этих плоскостей для процедурных объемов.

Рендеринг срезов как 3D-модели и использование позиций вершин в качестве координат мирового пространства отлично работает:

//Vertex Shader  
gl_Position = P*V*vec4(vertexPosition_worldspace,1);
coordinates_worldspace = vertexPosition_worldspace;

Результат:

Однако рендеринг срезов в пространстве пирамиды и попытка реконструирования координат мирового пространства дают ожидаемые результаты. Самое близкое, что я получил, было это:

//Vertex Shader
gl_Position = vec4(vertexPosition_worldspace,1);
coordinates_worldspace = (inverse(V) * inverse(P) * vec4(vertexPosition_worldspace,1)).xyz;

Результат:

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


person Blendurian    schedule 11.12.2018    source источник


Ответы (1)


Что ж, не на 100% понятно, что вы подразумеваете под «усеченным пространством». Я собираюсь предположить, что это действительно относится к нормализованным координатам устройства в OpenGL, где усеченная пирамида представления (по умолчанию) является выровненным по оси кубом -1 <= x,y,z <= 1. Я также предполагаю перспективную проекцию, так что координата NDC z на самом деле является гиперболической функцией глазного пространства z.

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

Нет, стандартная перспективная матрица в OpenGL выглядит как

( sx   0   tx   0  ) 
(  0  sy   ty   0  )
(  0   0    A   B  )
(  0   0   -1   0  )

Когда вы умножаете это на вектор пространства глаз (x,y,z,1), вы получаете однородные координаты клипа. Считайте только две последние строки матрицы отдельными уравнениями:

z_clip = A * z_eye + B
w_clip = -z_eye

Поскольку мы делим перспективу на w_clip, чтобы перейти от пространства клипа к NDC, мы получаем

z_ndc = - A - B/z_eye

которая на самом деле является гиперболически переназначенной информацией о глубине, так что информация полностью сохраняется. (Также обратите внимание, что мы делаем деление также для x и y).

Когда вы вычисляете inverse(P), вы инвертируете только однородное отображение 4D -> 4D. Но вы получите результат w, который снова не 1, поэтому здесь:

coordinates_worldspace = (inverse(V) * inverse(P) * vec4(vertexPosition_worldspace,1)).xyz;
                                                                                       ^^^

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

Правильный подход - разделить на w:

vec4 coordinates_worldspace = (inverse(V) * inverse(P) * vec4(vertexPosition_worldspace,1));
coordinates_worldspace /= coordinates_worldspace.w
person derhass    schedule 11.12.2018
comment
Большое спасибо! Оно работает! Я новичок в этом и думал, что w был полезен только для различения позиций и векторов. - person Blendurian; 12.12.2018