OpenGL Как рассчитать координаты мирового пространства из выровненных векторов усеченного конуса? - PullRequest
0 голосов
/ 11 декабря 2018

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

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

Визуализация срезов в качестве 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;

Результат:

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

1 Ответ

0 голосов
/ 11 декабря 2018

Ну, не совсем понятно, что вы имеете в виду под "пространством усеченного конуса".Я собираюсь предположить, что это относится к нормализованным координатам устройства в 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, чтобы добраться от пространства клипа до НДЦ, мы получаем

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, как если бы это были декартовы трехмерные координаты, но они являются 4D-однородными координатами, представляющими некоторую трехмерную точку.

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

vec4 coordinates_worldspace = (inverse(V) * inverse(P) * vec4(vertexPosition_worldspace,1));
coordinates_worldspace /= coordinates_worldspace.w
...