Урок №36. HDR в OpenGL

  Дмитрий Бушуев  | 

  Обновл. 14 Сен 2020  | 

 189

В этом уроке мы рассмотрим, что такое HDR, LDR и тональная компрессия в OpenGL.

HDR

По умолчанию, при хранении яркости и цвета во фреймбуфере, их значения сужаются до значений, лежащих в интервале [0.0, 1.0]. Эта, на первый взгляд, безобидная особенность побуждала нас всегда задавать параметры света и цвета значениями из данного диапазона, тем самым как бы подгоняя их под параметры сцены. Данный прием является вполне рабочим и дает достойные результаты, но что произойдет, если мы пройдемся по действительно яркой области с несколькими яркими источниками света, которые в общей сумме превышают значение 1.0? Ответ заключается в том, что все фрагменты, имеющие яркость или цветовую сумму более 1.0, сужаются до значения 1.0, что приводит к тому, что на них становится не очень приятно смотреть:

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

Одним из решений данной проблемы является уменьшение силы источников света, чтобы ни одна область фрагментов в вашей сцене не была ярче 1.0; это не очень хорошее решение, так как оно вынуждает вас использовать нереалистичные параметры освещения. Лучший подход — это разрешить цветовым значениям временно превышать границу 1.0, а затем на заключительном шаге преобразовывать их обратно в исходный диапазон [0.0, 1.0], но без потерь в детализации.

Мониторы (не поддерживающие HDR) ограничены отображением цветов в диапазоне между 0.0 и 1.0, но в уравнениях освещения такого ограничения нет. Позволяя цветам фрагментов превышать 1.0, мы получаем гораздо более высокий диапазон значений цветов, доступных для работы в так называемом расширенном динамическом диапазоне (сокр. «HDR» от «High Dynamic Range»). С расширенным динамическим диапазоном яркие вещи могут быть действительно яркими, темные вещи могут быть действительно темными, и при этом детали можно увидеть в обоих случаях.

Первоначально расширенный динамический диапазон использовался только для фотографии, где фотограф делает несколько снимков одной и той же сцены с различными уровнями экспозиции, захватывая большой диапазон цветовых значений. Сочетание этих параметров формирует HDR-изображение, в котором использование комбинированных уровней экспозиции или конкретной экспозиции помогают передать гораздо более большой диапазон деталей объекта. Например, нижеследующее изображение (моё почтение Колину Смиту) демонстрирует отображение значительного количества деталей в ярко освещенных областях с низкой экспозицией (посмотрите на окно), но эти детали пропадают на изображении с высокой экспозицией:

В свою очередь высокая экспозиция раскрывает большое количество деталей в более темных областях, которые ранее не были видны.

Принцип работы человеческого глаза является основой HDR-рендеринга. Когда света мало, человеческий глаз приспосабливается так, что более темные части становятся более заметными. Аналогичное приспособление происходит и для светлых областей. Утрируя, можно сказать, что человеческий глаз имеет автоматический регулятор экспозиции, зависящий от яркости сцены.

Рендеринг с расширенным динамическим диапазоном работает примерно так же. Мы разрешаем использование расширенного диапазона цветовых значений для рендеринга, собирая большой диапазон темных и ярких деталей сцены, и, в конце концов, преобразуем все HDR-значения обратно в низкий динамический диапазон (сокр. «LDR» от «Low Dynamic Range») — [0.0, 1.0]. Этот процесс преобразования HDR-значений в LDR-значения называется тональной компрессией, и существует большая коллекция алгоритмов тональной компрессии, направленных на сохранение в процессе преобразования значительного количества HDR-детализации. Алгоритмы тональной компрессии часто задействуют параметр экспозиции, с помощью которого можно избирательно влиять на темные или яркие области.

Когда речь заходит о рендеринге в реальном времени, расширенный динамический диапазон позволяет нам не только превысить LDR-диапазон [0.0, 1.0] и сохранить больше деталей, но и дает нам возможность указывать интенсивность источника света через его реальную интенсивность. Например, Солнце имеет гораздо более высокую интенсивность, чем какой-нибудь фонарик, так почему бы не настроить солнце должным образом (например, задать рассеянную яркость равную 100.0). Это позволяет нам более правильно настроить освещение сцены с более реалистичными параметрами освещения, что было бы невозможно при LDR-рендеринге, поскольку тогда значения были бы непосредственно сужены до 1.0.

Поскольку мониторы (не поддерживающие HDR) отображают только цвета в диапазоне от 0.0 до 1.0, то нам действительно нужно преобразовать текущий расширенный динамический диапазон значений цвета обратно в диапазон монитора. Простое обратное преобразование цветов с помощью усреднения значения не принесет нам много пользы, так как более яркие области станут намного более доминирующими. Что мы можем сделать, так это использовать различные уравнения и/или кривые для преобразования HDR-значений обратно в LDR-значения, которые дадут нам полный контроль над яркостью сцены. Данный процесс, ранее обозначенный как тональная компрессия, является заключительным этапом HDR-рендеринга.

Фреймбуферы типа с плавающей точкой


Для реализации рендеринга с расширенным динамическим диапазоном нам нужен какой-то способ предотвратить сужение цветовых значений после каждого запуска фрагментного шейдера. Когда фреймбуферы используют нормализованный с фиксированной точкой формат цвета (например, GL_RGB) в качестве внутреннего формата цветового буфера, то OpenGL, перед сохранением во фреймбуфер, автоматически сужает диапазон значений до [0.0, 1.0]. Эта операция выполняется для большинства типов форматов фреймбуфера, за исключением форматов типа с плавающей точкой.

Когда внутренний формат цветового буфера фреймбуфера задан как GL_RGB16F, GL_RGBA16F, GL_RGB32F или GL_RGBA32F, то такой фреймбуфер превращается во фреймбуфер типа с плавающей точкой, способный хранить значения типа с плавающей точкой вне заданного по умолчанию диапазона [0.0, 1.0]. Это идеально подходит для рендеринга в расширенном динамическом диапазоне!

Чтобы создать фреймбуфер типа с плавающей точкой, единственное, что нам нужно изменить — это внутренний параметр формата цветового буфера:

Стандартный OpenGL-фреймбуфер по умолчанию обеспечивает только 8 бит на каждый цветовой компонент. С помощью фреймбуфера типа с плавающей точкой, обеспечивающего 32 бита на каждый цветовой компонент (при использовании GL_RGB32F или GL_RGBA32F), мы используем в 4 раза больше памяти для хранения цветовых значений. Поскольку в 32 битах на практике нет нужды (если только вам не нужен высокий уровень точности), достаточно будет использовать GL_RGBA16F.

С помощью цветового буфера типа с плавающей точкой, подключенного к фреймбуферу, мы теперь можем рендерить сцену во фреймбуфер, зная, что значения цвета не будут зажаты между 0.0 и 1.0. В демонстрационном примере данного урока мы сначала рендерим освещенную сцену во фреймбуфер типа с плавающей точкой, а затем отображаем цветовой буфер фреймбуфера на экране; это будет выглядеть примерно так:

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

Рендеринг во фреймбуфер типа с плавающей точкой аналогичен обычному рендерингу во фреймбуфер. Что нового, так это фрагментный шейдер hdrShader, который визуализирует окончательный 2D-прямоугольник с прикрепленной к нему текстурой цветового буфера типа с плавающей точкой. Давайте сначала определим простой сквозной фрагментный шейдер:

Здесь мы используем цветовое значение буфера типа с плавающей точкой в качестве выходного сигнала фрагментного шейдера. Однако, поскольку выходные данные 2D-прямоугольника непосредственно визуализируются в заданный по умолчанию фреймбуфер, все выходные значения фрагментного шейдера все равно будут зажаты между 0.0 и 1.0, даже если у нас есть несколько значений в цветовой текстуре типа с плавающей точкой, превышающих 1.0.

Становится ясно, что значения интенсивности света в конце тоннеля сужены до 1.0, так как большая его часть полностью белая, фактически, в данном случае, теряя все детали освещения. Поскольку мы непосредственно записываем HDR-значения в выходной LDR-буфер, то это выглядит так, как если бы у нас вообще не был включен HDR. Что нам нужно сделать, так это преобразовать все значения цвета типа с плавающей точкой в диапазон [0.0, 1.0]. Нам нужно применить процесс, называемый «тональной компрессией».

Тональная компрессия

Тональная компрессия — это процесс преобразования (без существенных потерь в детализации) значений цвета типа с плавающей точкой в диапазон [0.0, 1.0] (известный как низкий динамический диапазон, часто сопровождаемый определенным стилистическим цветовым балансом).

Одним из наиболее простых алгоритмов тональной компрессии является алгоритм Рейнхарда, который включает в себя деление всех HDR-значений цвета на LDR-значения цвета. Мы добавим данный алгоритм в предыдущий фрагментный шейдер, а также для верности применим фильтр гамма-коррекции (включая использование sRGB-текстур):

С применением алгоритма тональной компрессии Рейнхарда мы больше не теряем никаких деталей в ярких областях нашей сцены. Он имеет тенденцию слегка отдавать предпочтение более ярким областям, делая более темные области менее детализированными и отчетливыми:

Здесь вы снова можете увидеть детали в конце тоннеля, так как рисунок текстуры дерева снова становится видимым. С помощью этого относительно простого алгоритма тональной компрессии мы можем правильно видеть весь диапазон HDR-значений, хранящихся во фреймбуфере типа с плавающей точкой, что дает нам более точный контроль над освещением сцены без потери в деталях.

Примечание: Обратите внимание, что мы также можем напрямую выполнять тональную компрессию в конце нашего шейдера освещения, не нуждаясь ни в каком фреймбуфере типа с плавающей точкой вообще! Однако, по мере усложнения сцен, часто возникает необходимость хранить промежуточные HDR-результаты в виде буферов типа с плавающей точкой, так что это хорошее упражнение.

Еще одно интересное применение тональной компрессии — это использование параметра экспозиции. Вы, вероятно, помните из введения, что HDR-изображения содержат много деталей, видимых на разных уровнях экспозиции. Если у нас есть сцена, которая показывает дневной и ночной цикл, то имеет смысл использовать более низкую экспозицию при дневном свете и более высокую экспозицию в ночное время, подобно тому, как адаптируется человеческий глаз. Введение дополнительного параметра экспозиции позволит нам настраивать параметры освещения, которые работают как днем, так и ночью при различных условиях освещения (поскольку нам лишь нужно будет изменить только этот параметр экспозиции).

Относительно простой алгоритм применения экспозиции к тональной компрессии выглядит следующим образом:

Здесь мы определили uniform-переменную exposure, которая по умолчанию равна 1.0 и позволяет нам более точно определить, хотим ли мы больше фокусироваться на темных или светлых областях HDR-значений цвета. Например, при высоких значениях экспозиции более темные участки тоннеля показывают значительно больше деталей. В отличие от этого, низкая экспозиция в значительной степени убирает детали темной области, но позволяет нам видеть больше деталей в светлых областях сцены. Взгляните на изображение ниже, чтобы увидеть тоннель на нескольких уровнях экспозиции:

Это изображение хорошо показывает преимущество рендеринга с расширенным динамическим диапазоном. Изменяя уровень экспозиции, мы видим множество деталей нашей сцены, которые в противном случае были бы потеряны в случае рендеринга с низким динамическим диапазоном. Возьмем, к примеру, конец тоннеля. При нормальной экспозиции структура древесины едва видна, но при низкой экспозиции отчетливо видна детализированная текстура дерева. То же самое относится и к текстуре дерева вблизи, которая более заметна при высокой экспозиции.

  Google Drive / Исходный код — Урок №36. HDR в OpenGL

  GitHub / Исходный код — Урок №36. HDR в OpenGL

Еще больше HDR

Два показанных алгоритма тональной компрессии — это лишь несколько примеров из большой коллекции (более продвинутых) алгоритмов тональной компрессии, каждый из которых имеет свои сильные и слабые стороны. Некоторые алгоритмы отдают предпочтение определенным цветам/интенсивностям над другими, другие алгоритмы отображают как низкие, так и высокие цвета экспозиции одновременно, чтобы создать более красочные и детализированные изображения. Существует также набор методов, известных как автоматическая регулировка экспозиции, которые определяют яркость сцены в предыдущем кадре и (медленно) адаптируют параметр экспозиции таким образом, что сцена становится ярче в темных областях или темнее в светлых областях, имитируя способности человеческих глаз.

Реальное преимущество HDR-рендеринга проявляется в больших и сложных сценах с тяжелыми алгоритмами освещения. Поскольку трудно создать такую сложную демонстрационную сцену для учебных целей, сохраняя её доступной, демонстрационная сцена данного урока мала и лишена деталей. Хотя она относительно простая, но при этом показывает некоторые преимущества HDR-рендеринга: никакие детали не теряются в светлых и темных областях, поскольку они могут быть восстановлены с помощью тональной компрессии; добавление нескольких источников света не вызывает проблем с сужением значений яркости областей, а значения освещенности могут быть заданы реальными значениями яркости, не ограниченными LDR-значениями. Кроме того, HDR-рендеринг также делает несколько других интересных эффектов более выполнимыми и реалистичными; один из этих эффектов — свечение, который мы обсудим в следующем уроке.

Дополнительные ресурсы


   Does HDR rendering have any benefits if bloom won’t be applied?: вопрос на stackexchange, который содержит отличный длинный ответ, описывающий некоторые преимущества HDR-рендеринга.

   What is tone mapping? How does it relate to HDR?: еще один интересный ответ на stackexchange с большими эталонными изображениями для объяснения тональной компрессии.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (4 оценок, среднее: 5,00 из 5)
Загрузка...

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *