glReadPixels на DEPTH_COMPONENT выбрасывает GL_INVALID_OPERATION

У меня проблема с чтением буфера глубины этапа рендеринга закадрового буфера кадра. При использовании OpenGL 4.5 он работает так, как задумано, но в OpenGL ES 2.0 (Angle) я получаю сообщение об ошибке при вызове glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthBuffer). Ошибка 0x502, это код ошибки GL_INVALID_OPERATION.

Еще немного предыстории. Я работаю в среде Qt, в которой есть основная процедура рендеринга, и теперь я занимаюсь неким закадровым рендерингом. Обычно мы используем настольную реализацию opengl, но на некоторых машинах у нас возникают проблемы с плохими версиями opengl. Поэтому я сейчас работаю над тем, чтобы сделать всю установку более надежной. Одна вещь, которую я сделал, - это вместо этого использовал угол. Итак, я просто пытаюсь получить работу под углом, который ДОЛЖЕН соответствовать использованию OpenGL ES 2.0.

Ну вот создание фреймбуфера:

glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glGenRenderbuffers(1, &cboId);
glBindRenderbuffer(GL_RENDERBUFFER, cboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);    
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cboId);    
glGenRenderbuffers(1, &dboId);
glBindRenderbuffer(GL_RENDERBUFFER, dboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dboId);

Буфер кадра заполнен, и ошибок не возникает. Код между предыдущим и последующим заключительным фрагментом также не вызывает ошибок.

glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, colorData);
//No error up to this point
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthData));
//This call throws 0x502 (GL_INVALID_OPERATION)

Обычно я использую GL_DEPTH_COMPONENT24, который по какой-то причине не работает. Поэтому вместо этого я использовал GL_DEPTH_COMPONENT16. Может это намек на то, что не так. К вашему сведению, основной буфер кадра использует трафарет с глубиной 24 бита и трафаретом 8 бит. (Я пытался использовать формат GL_DEPTH24_STENCIL8, но безуспешно при вызове glReadPixels).

Использование текстуры вместо этого или pbuffer не работает, потому что необходимые функции для этого обходного пути (glGetTexImage(...), glMapBuffer(...)) не реализованы в версии GL, с которой я застрял.


person xeed    schedule 27.09.2017    source источник


Ответы (2)


Согласно спецификации Khronos:

формат Определяет формат данных пикселей. Допускаются следующие символические значения: GL_ALPHA, GL_RGB и GL_RGBA.

type Определяет тип данных пикселей. Должен быть одним из GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4 или GL_UNSIGNED_SHORT_5_5_5_1.

GL_INVALID_OPERATION создается, если тип - GL_UNSIGNED_SHORT_5_6_5, а формат - не GL_RGB.

GL_INVALID_OPERATION создается, если тип - GL_UNSIGNED_SHORT_4_4_4_4 или GL_UNSIGNED_SHORT_5_5_5_1, а формат - не GL_RGBA.

GL_INVALID_OPERATION создается, если формат и тип не являются ни GL_RGBA и GL_UNSIGNED_BYTE, соответственно, ни парой формат / тип, возвращаемой запросом GL_IMPLEMENTATION_COLOR_READ_FORMAT и GL_IMPLEMENTATION_COLOR_READ_TYPE.

Ни format, ни type в вашем коде не соответствуют этим требованиям.

person Reaper    schedule 27.09.2017
comment
@ Rabbid76 На самом деле здесь нет четко сформулированного вопроса. - person Reaper; 28.09.2017
comment
Хорошо, это на самом деле уже довольно полезно. Он отвечает на вопрос, почему. Есть ли другой способ доступа к буферу глубины, кроме glReadPixels, PBuffers и текстур? - person xeed; 28.09.2017

Как уже отмечал @xeed, @Reaper ответила на часть вопроса, почему. Что касается того, как получить информацию о глубине в OpenGL ES, после долгого поиска в Интернете, а также разговоров с некоторыми коллегами, я увидел только два предложенных метода:

  1. (Только для ES 3+) Прикрепите текстуру глубины к фреймбуферу, в котором вы визуализируете свою сцену. Затем выполните рендеринг полноэкранного четырехугольника, сэмплируйте текстуру глубины во фрагментном шейдере для этого четырехугольника и выведите значения текстуры глубины в качестве значений вашего цвета, например в вашем красном канале. Наконец, используйте glReadPixels для этой информации о цвете, чтобы вернуть значения глубины. См. https://stackoverflow.com/a/35041374/11295586

  2. Получите значения с помощью gl_FragCoord.z. См .: https://stackoverflow.com/a/6140714/11295586

Я пробовал оба варианта, и оба, похоже, работают, хотя у меня все еще есть проблема с инверсией глубины со вторым, который, хотя его легко исправить (просто вычтите значение из 1.0f), я пытаюсь расшифровать причину. Кроме того, детали для второго варианта зависят от того, когда вам нужны значения и какая информация о цвете вам нужна для исходной сцены. Например. в моем случае я могу просто указать gl_FragCoord.z ​​в качестве значения моего альфа-канала, потому что я фактически не показываю свой результат рендеринга. Если вам действительно нужен неповрежденный альфа-канал исходного рендера, возможно, решением будет несколько целей рендеринга, одна из которых получает значение gl_FragCoord.z?

person FilmCoder    schedule 12.08.2020