Вот моя проблема, когда я загружаю текстуры, я загружаю их как SRGB, чтобы преобразовать их в линейное пространство. Когда я выполнял запись в буфер кадров по умолчанию, предоставляемый системой управления окнами, я включил GL_FRAMEBUFFER_SRGB, чтобы при записи в буфер кадров преобразовывались цвета из линейного пространства в пространство SRGB.
Проблема сейчас в том, что я рендерил в FBO вне экрана, а затем вставлял его в стандартный кадровый буфер. При этом включение или отключение GL_FRAMEBUFFER_SRGB не имеет никакого эффекта. Я попытался включить GL_FRAMEBUFFER_SRGB как с привязкой кадрового буфера по умолчанию, так и с привязкой закадрового FBO, они не работают.
Что работает, однако, если я указываю GL_SRGB в качестве внутреннего формата текстуры, которую я связываю как буфер цвета внеэкранного FBO. Я предполагаю, что в этом случае, когда GL_FRAMEBUFFER_SRGB включен, записи из фрагментного шейдера в текстуру преобразуют его из линейного пространства в пространство SRGB.
Мне было интересно, кажется, что переход от FBO к кадровому буферу по умолчанию преобразования GL_FRAMEBUFFER_SRGB не применяется. Поскольку я хотел бы работать в линейном пространстве до окончательной передачи в буферный буфер стандартного кадрового буфера, как я могу применить преобразование при перетаскивании внеэкранного FBO в стандартный кадровый буфер? Я предполагаю, что выборка закадрового FBO в качестве текстуры и рендеринг четырехугольника в кадровом буфере по умолчанию применили бы преобразование SRGB, но нет ли способа сделать это преобразование с помощью кадрового буфера?
Делая этот поворот
GL_FRAMEBUFFER_SRGB
вкл или выкл не имеет никакого эффекта. Я пытался включитьGL_FRAMEBUFFER_SRGB
как с привязанным по умолчанию кадровым буфером, так и с закадровым ограничением FBO, они не работают.
GL_FRAMEBUFFER_SRGB
не то, что вы думаете, что делает: не превратить любого мошенника формат от RGB до sRGB.
GL_FRAMEBUFFER_SRGB
будет иметь эффект только тогда, когда формат кадрового буфера уже указан sRGB
например, прикрепив текстуру с internalFormat
из GL_SRGB8
или же GL_SRGB8_ALPHA8
в качестве цветного буфера для FBO. Если вы хотите преобразование sRGB для буфера кадров по умолчанию, вы должны использовать специальные API оконной системы, чтобы явно создать PixelFormat / Visual / FBConfig / что угодно с поддержкой sRGB. Посмотрите на GL / GLX / WGL _ARB_FRAMEBUFFER_SRGB
расширение спецификации о том, как это сделать.
Что работает, однако, если я укажу
GL_SRGB
в качестве внутреннего формата текстуры, которую я связываю как буфер цвета внеэкранного FBO. Я предполагаю в этом случае, когдаGL_FRAMEBUFFER_SRGB
включается запись из фрагмента шейдера в текстуру, преобразование его из линейного пространства в пространство SRGB.
Да, именно так и должно работать. GL_FRAMEBUFFER_SRGB
включить бит это только средство запрещать преобразования SRGB в форматах, которые обычно делают их, а не наоборот.
Мне было интересно, кажется, что переход от FBO к кадровому буферу по умолчанию преобразования GL_FRAMEBUFFER_SRGB не применяется.
Давайте посмотрим на самую последнюю спецификацию OpenGL на сегодняшний день: Спецификация профиля ядра OpenGL 4.6, раздел 18.3.1 «Прямоугольники блицующих пикселей» (выделено мной):
Когда значения взяты из буфера чтения, если
FRAMEBUFFER_SRGB
включен и значение
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
для вложения кадрового буфера, соответствующего буферу чтения
SRGB
(см. раздел 9.2.3), красный, зеленый и синий компоненты преобразованы из нелинейного цвета sRGB
пространство в соответствии с уравнением 8.17.Когда значения записываются в буферы рисования, блиц-операции обходят большинство
фрагмент трубопровода. Единственные операции фрагмента, которые влияют на блиц, являются пикселем
тест собственности, тест ножниц, и преобразование sRGB (см. раздел 17.3.7). Цвет,
глубина и трафаретные маски (см. раздел 17.4.2) игнорируются
с разделом 17.3.7 «Преобразование sRGB» с указанием:
Если
FRAMEBUFFER_SRGB
включен и значение
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
для вложения кадрового буфера, соответствующего буферу назначения
SRGB
(см. раздел 9.2.3), значения R, G и B после
смешивание преобразуется в нелинейное цветовое пространство sRGB [формула следует …]
Обратите внимание, что в разделе 17.3.7 будет ясно, что при записи в цветной буфер преобразование линейного в sRGB будет применяться только в том случае, если GL_FRAMEBUFFER_SRGB
включен.
Так что это оставляет нам следующие возможности:
И исходный, и целевой цветовой буфер имеют стандартный формат NON-sRGB: блиц будет копировать значения пикселей, преобразования sRGB не могут произойти, независимо от того, как GL_FRAMEBUFFER_SRGB
установлено.
Исходный буфер имеет формат sRGB, пункт назначения имеет формат NON-sRGB. Преобразование из sRGB в линейное будет сделано если и только если GL_FRAMEBUFFER_SRGB
включен.
Исходный буфер имеет формат NON-sRGB, пункт назначения имеет формат sRGB. Преобразование из линейного в sRGB будет сделано если и только если GL_FRAMEBUFFER_SRGB
включен.
И источник, и пункт назначения имеют форматы sRGB. Будет выполнено преобразование из sRGB в линейный И линейный в sRGB если и только если GL_FRAMEBUFFER_SRGB
включен. Обратите внимание, что преобразование может сводиться к неработоспособности здесь. Это относится и к случаям с билинейной фильтрацией: спецификация GL не требует применения билинейной фильтрации к источникам sRGB в линейном пространстве после преобразования, ее также можно применять и раньше.
Теперь история может быть здесь. Но это не так. Поведение кадровых буферов в форматах sRGB претерпело ряд изменений в истории GL.
Раздел 18.3.1 Спецификация профиля ядра OpenGL 4.3 заявляет:
Когда значения взяты из буфера чтения, если значение
[Второй абзац такой же, как предыдущий цитата из 4.6]
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
для вложения кадрового буфера, соответствующего буферу чтения
SRGB
(см. раздел 9.2.3), красный, зеленый и синий компоненты преобразуются из нелинейного цветового пространства sRGB в соответствии с уравнением
Это означает, что до GL 4.3, преобразование источник буфер всегда выполнялся, когда он имел формат sRGB, независимо от того, GL_FRAMEBUFFER_SRGB
включить. Однако для буфера назначения этот параметр все еще актуален.
Сейчас в OpenGL 3.3, нет никакого упоминания о поведении при блиттинге с форматами sRGB. Соответствующий раздел 4.3.2 «Копирование пикселей» и только утверждает:
Блит-операции обходят фрагмент конвейера. Единственный фрагмент операции
на блиц влияют тест владения пикселем и ножницы.
Это означает, что он также будет обходить линейное преобразование в sRGB для целевого буфера и не будет делать никаких заявлений об исходном преобразовании вообще.
Кроме того, исторически сложилось так, что драйверы также игнорировали спецификации и делали то, что, по их мнению, лучше всего, когда дело доходит до преобразований sRGB. Смотри например статья «Состояние драйверов OpenGL за март 2015 года и конверсии FB sRGB». Существует также этот хороший патч к тестовому пакету OpenGL для поросят говорить о проблемах и выдвигать несколько печальные выводы:
Я думаю, что краткая сводка такова: sRGB в OpenGL настолько сломан, насколько это возможно. 🙁 По крайней мере, каждый разработчик игр, с которым я когда-либо общался, говорит мне об этом. Тьфу.
Однако, по моему опыту, большинство современных драйверов GL> = 4.4 выполняют преобразования в соответствии с указаниями, поэтому ситуация уже не так уж и плоха. Но я бы не стал ставить на это свою жизнь.
Других решений пока нет …