Восстановление мировых координат из буфера глубины и произвольной матрицы проекции вида

Я пытаюсь реконструировать координаты 3D-мира по значениям глубины в моем отложенном рендерере, но у меня чертовски мало времени. Большинство примеров, которые я нахожу в Интернете, предполагают стандартное преобразование перспективы, но я не хочу делать такое предположение.

В моем вершинном шейдере передачи геометрии я вычисляю gl_Position, используя:

gl_Position = wvpMatrix * vec4(vertexLocation, 1.0f);

и в моем фрагментном шейдере передачи освещения я пытаюсь получить мировые координаты, используя:

vec3 decodeLocation()
{
  vec4 clipSpaceLocation;
  clipSpaceLocation.xy = texcoord * 2.0f - 1.0f;
  clipSpaceLocation.z = texture(depthSampler, texcoord).r;
  clipSpaceLocation.w = 1.0f;
  vec4 homogenousLocation = viewProjectionInverseMatrix * clipSpaceLocation;
  return homogenousLocation.xyz / homogenousLocation.w;
}

Я думал, что угадал, и действительно, объекты рядом с камерой освещаются правильно. Но недавно я понял, что по мере того, как я удаляюсь, объекты освещаются так, как будто они находятся дальше от камеры, чем они есть на самом деле. Я поэкспериментировал со своим проходом освещения и убедился, что мои мировые координаты — единственное, что неправильно вычисляется.

Я не могу не думать, что мои clipSpaceLocation.z и clipSpaceLocation.w являются источником проблемы, но я испробовал все возможные варианты их расчета, и приведенный выше код дает наиболее правильные результаты.

Любые идеи или предложения?


person jbatez    schedule 12.03.2014    source источник
comment
как вы рассчитали матрицу проекции обратного вида? У меня проблема с захватом позиции света в пространстве, и я предполагаю, что это моя матрица проекции обратного вида.   -  person Franky Rivera    schedule 20.09.2014


Ответы (3)


Мне нужно было только сделать маленькое исправление. Линия:

clipSpaceLocation.z = texture(depthSampler, texcoord).r;

должен прочесть:

clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0f - 1.0f;

Насколько я понимаю, проекционные матрицы спроектированы таким образом, что они отображают ближнюю и дальнюю плоскости в [-1,1], а не в [0,1], как я всегда предполагал. Затем OpenGL нормализует их в диапазоне [0,1] (также известном как «Пространство окна»), поэтому мне нужно было выполнить обратную нормализацию.

Все это предполагает, что glDepthRange(0, 1) используется по умолчанию, и нет особых причин его менять.

person jbatez    schedule 12.03.2014
comment
Начиная с OpenGL 2.1 (GLSL 1.20.8). См. opengl.org/registry/doc/GLSLangSpec.Full.1.20. .8.pdf Раздел 4.1.4 - person jbatez; 28.11.2015
comment
Даже если ваш ответ опоздал более чем на год, вы правы. Похоже, проблема была только в том, что я забыл указать #version xyz в шейдерах. - person Tara; 30.11.2015

Ваш общий подход правильный, вы просто неправильно инвертировали преобразование оконного пространства. Пространство окна z (которое вы, вероятно, указали в своей текстуре глубины) равно [0,1] (по умолчанию более общим будет glDepthRange()), но пространство NDC z равно [-1,1]. Таким образом, вы можете изменить эту строку, аналогичную вашим сопоставлениям x и y, на

clipSpaceLocation.z = texture(depthSampler, texcoord).r * 2.0 - 1.0;
person derhass    schedule 12.03.2014

См. мой ответ на gamedev.stackexchange, чтобы узнать о более эффективном способе реконструкции мира и просмотра космических позиций:

https://gamedev.stackexchange.com/a/111885/24009

person Tara    schedule 30.11.2015