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

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

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

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

//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;

Результат:

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

1 ответ

Решение

Ну, это не на 100% ясно, что вы подразумеваете под "Frustum Space". Я собираюсь предположить, что это относится к нормализованным координатам устройства в OpenGL, где усеченный вид является (по умолчанию) выровненным по оси кубом -1 <= x,y,z <= 1, Я также собираюсь принять перспективную проекцию, так что НДЦ 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 чтобы попасть из пространства клипа в НДЦ, мы в конечном итоге

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
Другие вопросы по тегам