Привязать предварительно визуализированную текстуру глубины к 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
координата обрабатываемого фрагмента. Это фрагмент, сгенерированный растеризатором на основе данных растеризованного примитива. Это не имеет никакого отношения к содержимому кадрового буфера.