Crytek SSAO Алгоритм OpenGL

Я пытаюсь реализовать простой вариант алгоритма окклюзии окружающего пространства Crytek.

Алгоритм, насколько я понимаю;

  1. Для пикселя п, образец вокруг п в сфере в пространстве зрения.
  2. Спроектировать точку отбора проб зр экранировать пространство.
  3. Сравните глубину выбранной точки с глубиной текущего пикселя.

Это должно быть все, что нужно сделать. Если глубина выбранной точки выше (она лежит за пределами геометрии), она не перекрывает текущий пиксель (п).

float z = gl_FragCoord.z; // depth-buffer value for the current pixel
int occluding_points = 0;
vec4 fPosition = model_transformation * vec4(position, 1.0f); // Really from vertex shader
#ifdef CRYTEK_AO
const int NUM_SAMPLES = 10;
float R = 3.0f;
const float[10] steps = float[](0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f);
for (int sample_id = 0; sample_id < NUM_SAMPLES; sample_id++) {
// 1. Generate sample point in world space.
float ang = steps[sample_id];
vec4 sample_point = vec4(R * cos(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.x,
R * sin(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.y,
R * sin(M_PI * ang) + fPosition.z,
1.0f);
// 2. Transform sample point from view space to screen space to get its depth value.
sample_point = projection * camera_view * sample_point; // Clip space
sample_point = sample_point / sample_point.w;           // Perspective division - Normalized device coordinate
float sample_depth = 0.5f * (sample_point.z + 1.0f);    // Viewport transform for z - window space

// 3. Check whether sample_point is behind current pixel depth.
if (sample_depth > z) { occluding_points++; }
}
occlusion_factor = occluding_points / float(NUM_SAMPLES);
// Diffuse, specular components removed
total_light += vec3(ambient_intensity) * (1.0f - occlusion_factor); // Ambient factor
outColor = total_light;
#endif

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

Окружающая окклюзия пошла не так ...

Если смотреть в основном под любым другим углом, похоже, что вы ожидаете установить коэффициент окклюзии равным 0,5 (что даст вам серый цвет во всех цветовых каналах).

Ничего ненормального

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

Добавлено видео Вот мерцания

Есть какие-нибудь подсказки?

РЕДАКТИРОВАТЬ: одна проблема была обнаружена с округлением.
РЕДАКТИРОВАТЬ: Добавлена ​​видео ссылка на артефакт при перемещении по оси Z.

1

Решение

В вашем коде есть две подозрительные вещи.

Целочисленное деление

occlusion_factor = occluding_points / NUM_SAMPLES;

Просто измените тип occlusion_points на float, и все будет в порядке.

отбор проб

    vec4 sample_point = vec4(R * cos(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.x,
R * sin(2 * M_PI * ang) * sin(M_PI * ang) + fPosition.y,
R * sin(M_PI * ang) + fPosition.z,
1.0f);

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

2

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

Других решений пока нет …

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