OpenGL (4.2) обработка фрагментов & буфер глубины & imageLoadAndStore


У меня есть двухпроходный рендеринг. в первом проходе я визуализирую некоторую непрозрачную геометрию с помощью FBO в несколько текстур.

Во втором проходе я снова визуализирую ту же геометрию и основываюсь на различных свойствах геометрии (например, объект, нормаль и т. д.) я записываю вычисленные значения цветов из pass 1 в определенные текселы некоторых текстур с помощью imageStore () (image_load_and_store)

Я хочу, чтобы это произошло только для видимых фрагментов, однако (только те, которые соответствуют окончательному фрагментные цвета прохода 1)

Поэтому сейчас я пытаюсь взять текстуру GL_DEPTH_ATTACHMENT из прохода 1 и прикрепить ее к fbo из прохода 2 (также как GL_DEPTH_ATTACHMENT) , а затем перед прохождением рендеринга 2 я устанавливаю

glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(false);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
...render my scene...

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

Но это, кажется, не работает-скрытые фрагменты тоже обрабатываются и выполните imageStore () (и так как они используют цвета, вычисленные в pass1 для видимых фрагментов, они делают неверную вещь)

Есть идеи, почему? заставляет ли imageStore или что-то еще выполнять fragmentshader? могу ли я как-то это контролировать? это как-то связано с ранним z?

2 2

2 ответа:

Спецификация OpenGL определяет, что шейдер фрагментов выполняет перед тестом глубины. Если какое-то оборудование сначала выполняет тест глубины, то это будет только в тех случаях, когда коммутатор не заметит никаких изменений в поведении.

Ну, если вы просто не скажете шейдеру фрагментов выполнить после теста глубины, поместив эту строку в свой шейдер фрагментов:

layout(early_fragment_tests) in;

Это часть shader_image_load_store, по понятным причинам.

Поскольку early-z - это только средство оптимизации, которое не нужно делать, я думаю, что это вполне допустимое поведение.

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

Вы не сможете выполнить свой собственный тест глубины, используя текстуру глубины не как вложение глубины, а как ввод текстуры:

uniform sampler2D depth;

void main()
{
    if(gl_FragCoord.z > texture(depth, gl_FragCoord.xy / textureSize(depth))
        discard;
    ...
}