SSAO не показывает правильные результаты, в основном без видимой окклюзии

Я следую за уроком Джона Чепмена (http://john-chapman-graphics.blogspot.nl/2013/01/ssao-tutorial.html) реализовать SSAO в отложенном рендерере. Входные буферы для шейдеров SSAO:

  • Позиции в мировом пространстве с линеаризованной глубиной в качестве w-компонента.
  • Нормальные векторы мирового пространства
  • Шум 4х4 текстуры

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

#version 330 core
in VS_OUT {
vec2 TexCoords;
} fs_in;

uniform sampler2D texPosDepth;
uniform sampler2D texNormalSpec;
uniform sampler2D texNoise;uniform vec3 samples[64];

uniform mat4 projection;
uniform mat4 view;
uniform mat3 viewNormal; // transpose(inverse(mat3(view)))

const vec2 noiseScale = vec2(800.0f/4.0f, 600.0f/4.0f);
const float radius = 5.0;

void main( void )
{
float linearDepth = texture(texPosDepth, fs_in.TexCoords).w;

// Fragment's view space position and normal
vec3 fragPos_World = texture(texPosDepth, fs_in.TexCoords).xyz;
vec3 origin = vec3(view * vec4(fragPos_World, 1.0));
vec3 normal = texture(texNormalSpec, fs_in.TexCoords).xyz;
normal = normalize(normal * 2.0 - 1.0);
normal = normalize(viewNormal * normal); // Normal from world to view-space
// Use change-of-basis matrix to reorient sample kernel around origin's normal
vec3 rvec = texture(texNoise, fs_in.TexCoords * noiseScale).xyz;
vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 tbn = mat3(tangent, bitangent, normal);

// Loop through the sample kernel
float occlusion = 0.0;

for(int i = 0; i < 64; ++i)
{
// get sample position
vec3 sample = tbn * samples[i]; // From tangent to view-space
sample = sample * radius + origin;

// project sample position (to sample texture) (to get position on screen/texture)
vec4 offset = vec4(sample, 1.0);
offset = projection * offset;
offset.xy /= offset.w;
offset.xy = offset.xy * 0.5 + 0.5;

// get sample depth
float sampleDepth = texture(texPosDepth, offset.xy).w;

// range check & accumulate
// float rangeCheck = abs(origin.z - sampleDepth) < radius ? 1.0 : 0.0;
occlusion += (sampleDepth <= sample.z ? 1.0 : 0.0);
}
occlusion = 1.0 - (occlusion / 64.0f);

gl_FragColor = vec4(vec3(occlusion), 1.0);
}

Результат, однако, не радует. Буфер окклюзии в основном весь белый и не показывает никакой окклюзии. Однако, если я подойду очень близко к объекту, я получу странные шумоподобные результаты, как вы можете видеть ниже:

странные визуальные результаты SSAO

Это явно не правильно. Я проделал большую часть отладки и считаю, что все соответствующие переменные правильно переданы (все они визуализируются как цвета). Я делаю вычисления в view-space.

Я кратко пройдусь по шагам (и выборам), которые я предпринял на случай, если кто-то из вас поймет, что что-то пошло не так на одном из шагов.

позиции в пространстве вида / нормали
Джон Чепмен извлекает позицию в пространстве вида, используя луч обзора и линеаризованное значение глубины. Так как я использую отложенный рендер, у которого уже есть позиции в мировом пространстве на фрагмент, я просто беру их и умножаю их на матрицу вида, чтобы получить их в пространстве вида.

Я использую аналогичный подход для нормальных векторов. Я беру нормальные векторы мирового пространства из буферной текстуры, преобразую их в диапазон [-1,1] и умножаю их на транспонированную (обратную (mat3 (..))) матрицу вида.

Положение в пространстве и нормали визуализируются, как показано ниже:

пространство представления и нормали визуализируются SSAO

Это выглядит правильно для меня.

Ориентировать полушарие вокруг нормального
Шаги для создания tbn Матрица такая же, как описано в руководстве Джона Чепмена. Я создаю текстуру шума следующим образом:

std::vector<glm::vec3> ssaoNoise;
for (GLuint i = 0; i < noise_size; i++)
{
glm::vec3 noise(randomFloats(generator) * 2.0 - 1.0, randomFloats(generator) * 2.0 - 1.0, 0.0f);
noise = glm::normalize(noise);
ssaoNoise.push_back(noise);
}
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 4, 4, 0, GL_RGB, GL_FLOAT, &ssaoNoise[0]);

Я могу визуализировать шум в фрагментном шейдере, чтобы он работал.

глубина образца
Я преобразую все выборки из тангенса в пространство обзора (выборки являются случайными между [-1,1] на оси xy и [0,1] на оси z и транслирую их в текущую позицию фрагмента в пространстве вида (начало координат).

Затем я делаю выборку из линеаризованного буфера глубины (который я визуализирую ниже, если смотреть близко к объекту):

буфер глубины линеаризован

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

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

3

Решение

Задача ещё не решена.

Другие решения


По вопросам рекламы [email protected]