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

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

В моем геометрическом проходном вершинном шейдере я вычисляю 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 являются источником проблемы, но я попробовал все варианты, которые я могу придумать, чтобы рассчитать их, и приведенный выше код приводит к наиболее корректным результатам.

Есть идеи или предложения?

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), который является по умолчанию, и нет особых оснований для его изменения.

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

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

Смотрите мой ответ на gamedev.stackexchange для более эффективного способа воссоздания мира и просмотра космических позиций:

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

Другие вопросы по тегам