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