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