Привязать предварительно визуализированную текстуру глубины к fbo или к фрагментному шейдеру?

В структуре отложенного затенения я использую различные объекты кадрового буфера для выполнения различных проходов рендеринга. В первом проходе я пишу DEPTH_STENCIL_ATTACHMENT для всей сцены в текстуру, давайте назовем это DepthStencilTexture, Для доступа к информации о глубине, хранящейся в DepthStencilTexture из разных проходов рендеринга, для которых я использую разные объекты кадрового буфера, я знаю два способа:
1) Я связываю DepthStencilTexture к шейдеру, и я получаю доступ к нему в фрагментном шейдере, где я делаю глубину вручную, как это

uniform vec2 WinSize; //windows dimensions
vec2 uv=gl_FragCoord.st/WinSize;
float depth=texture(DepthStencilTexture ,uv).r;
if(gl_FragCoord.z>depth) discard;

Я тоже поставил glDisable(GL_DEPTH_TEST) а также glDepthMask(GL_FALSE)

2) Я связываю DepthStencilTexture к объекту кадрового буфера как DEPTH_STENCIL_ATTACHMENT и установить glEnable(GL_DEPTH_TEST) а также glDepthMask(GL_FALSE) (редактировать: в этом случае я не буду связывать DepthStencilTexture чтобы избежать шейдерной обратной связи, посмотрите ответ Николя Боласа, и я, если мне понадобится глубина в фрагментном шейдере, я буду использовать gl_FragCorrd.z)

В определенных ситуациях, таких как рисование легких объемов, для которых мне нужен тест трафарета и запись в буфер трафарета, я иду к решению 2). В других ситуациях, в которых я полностью игнорирую трафарет, и просто нуждаюсь в глубине, сохраненной в DepthStencilTexture, дает ли вариант 1) какие-либо преимущества перед более "естественным" вариантом 2)?

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

uniform mat4 invPV; //inverse PV matrix 
vec2 uv=gl_FragCoord.st/WinSize;
vec4 WorldPosition=invPV*vec4(uv, texture(DepthStencilTexture ,uv).r ,1.0f );
WorldPosition=WorldPosition/WorldPosition.w;

В случае 2) это будет так (правка: это неправильно, gl_FragCoord.z ​​- это глубина текущего фрагмента, а не фактическая глубина, сохраненная в текстуре)

uniform mat4 invPV; //inverse PV matrix 
vec2 uv=gl_FragCoord.st/WinSize;
vec4 WorldPosition=invPV*vec4(uv, gl_FragCoord.z, 1.0f );
WorldPosition=WorldPosition/WorldPosition.w;

Я предполагаю что gl_FragCoord.z в случае 2) будет таким же, как texture(DepthStencilTexture ,uv).r в случае 1) или, другими словами, глубина, хранящаяся в DepthStencilTexture, Это правда? Является gl_FragCoord.z читать из текущей привязки DEPTH_STENCIL_ATTACHMENT также с glDisable(GL_DEPTH_TEST) а также glDepthMask(GL_FALSE)?

1 ответ

Решение

Строго следуя спецификации OpenGL, вариант 2 не допускается. Нет, если вы также читаете с этой текстуры.

Да, я понимаю, что вы используете маски записи для предотвращения глубокой записи. Это не имеет значения; спецификация OpenGL вполне понятна. В соответствии с 9.3.1 OpenGL 4.4 петля обратной связи устанавливается, когда:

  • изображение из объекта текстуры T присоединяется к текущему связанному объекту кадрового буфера рисования в точке присоединения A

  • объект текстуры T в настоящее время связан с единицей текстуры U, и

  • текущее программируемое состояние обработки вершины и / или фрагмента делает возможным (см. ниже) выборку из объекта текстуры T, привязанного к единице текстуры U

Это случай в вашем коде. Таким образом, у вас есть неопределенное поведение.

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

При этом, вы можете обойтись без варианта 2, если вы используете NV_texture_barrier. Который, несмотря на название, довольно широко доступен на аппаратном обеспечении AMD. Главное, что здесь нужно сделать - это поставить барьер после того, как вы выполните все ваши глубокие записи, чтобы гарантировалось, что все последующие чтения будут работать. Барьер выполнит всю очистку кеша и тому подобное, что вам нужно.

В противном случае вариант 1 является единственным выбором: выполнить тест глубины вручную.

Я предполагаю, что gl_FragCoord.z ​​в случае 2) будет таким же, как текстура (DepthStencilTexture,uv).r в случае 1) или, другими словами, глубина, хранящаяся в DepthStencilTexture. Это правда?

Ни то, ни другое gl_FragCoord координата обрабатываемого фрагмента. Это фрагмент, сгенерированный растеризатором на основе данных растеризованного примитива. Это не имеет никакого отношения к содержимому кадрового буфера.

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