Как преобразовать в средство визуализации HDR?

Я в процессе преобразования моего отложенного рендерера webgl в тот, который использует расширенный динамический диапазон. Я много читал на эту тему из различных источников в Интернете, и у меня есть несколько вопросов, которые, надеюсь, можно прояснить. Большая часть прочитанного мною касается рендеринга изображений HDR, но мои вопросы касаются того, как рендерер, возможно, придется изменить для поддержки HDR.

Насколько я понимаю, HDR, по сути, пытается захватить более высокие световые диапазоны, чтобы мы могли видеть детали как в очень освещенных, так и в темных сценах. Обычно в играх мы используем интенсивность 1 для представления белого света и 0 для черного. Но в HDR / реальном мире диапазоны гораздо более разнообразны. Т.е. Солнце в двигателе может быть в 10000 раз ярче, чем лампочка в 10 раз.

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

Мой первый вопрос по освещению. Помимо целей рендеринга с плавающей запятой, означает ли это, что если раньше у меня был свет, представляющий солнце с интенсивностью 1, то теперь он мог бы / должен быть представлен как 10000? Т.е.

float spec = calcSpec();
vec4 diff = texture2D( sampler, uv );
vec4 color = diff * max(0.0, dot( N, L )) * lightIntensity + spec; //Where lightIntensity  is now 10000?
return color;

Есть ли какие-либо другие фундаментальные изменения в системе освещения (кроме плавающих текстур и более высоких диапазонов)?

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

Итак, для фазы тонального отображения я бы предположительно использовал пост-процесс, а затем, используя формулу тонального отображения, преобразовал освещение HDR в низкий динамический диапазон. Я выбрал технику Джона Хейблса из Uncharted 2:

const float A = 0.15;
const float B = 0.50;
const float C = 0.10;
const float D = 0.20;
const float E = 0.02;
const float F = 0.30;
const float W = 11.2;

vec3 Uncharted2Tonemap(vec3 x)
{
    return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
}

... // in main pixel shader

vec4 texColor = texture2D(lightSample, texCoord );
texColor *= 16;  // Hardcoded Exposure Adjustment 
float ExposureBias = 2.0;
vec3 curr = Uncharted2Tonemap( ExposureBias * texColor.xyz );
vec3 whiteScale = 1.0 / Uncharted2Tonemap(W);
vec3 color = curr * whiteScale;
 // Gama correction
color.x = pow( color.x, 1.0 /2.2 );
color.y = pow( color.y, 1.0 /2.2 );
color.z = pow( color.z, 1.0 /2.2 );
return vec4( color, 1.0 );

Статья о тональном сопоставлении

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

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

vec4 diff = pow( texture2D( sampler, uv), 2.2 );

Затем в вышеупомянутой технике тонального отображения коррекция вывода выполняется с помощью:

pow(color,1/2.2);

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

Мой третий вопрос касается этой коррекции гаммы. Это необходимо для работы? Означает ли это, что я должен менять свой движок во всех местах, где читаются диффузные карты?

Это мое текущее понимание того, что нужно для этого преобразования. Правильно ли это, и есть ли что-то, что я неправильно понял или ошибся?


person Mat    schedule 14.01.2015    source источник
comment
На самом деле вам не нужна цель рендеринга с плавающей запятой для рендеринга HDR (в любом случае в настольной GL). Целочисленный HDR также возможен с использованием таких форматов, как GL_RGB10_A2, если вы можете пожертвовать альфой (что часто имеет место при отложенном затенении). Существует аналогичный небольшой упакованный формат с плавающей запятой (GL_R11F_G11F_B10F), который даст вам действительно хорошую производительность, если вы пожертвуете точностью в одном цветовом канале и исключите альфа-канал. Они обеспечат вам примерно такую ​​же производительность на современном оборудовании, и обычно предпочтительнее использовать упакованный формат с плавающей запятой (через GL_APPLE_texture_packed_float в ES 2.0).   -  person Andon M. Coleman    schedule 14.01.2015


Ответы (1)


Расчет / накопление освещенности. Да, как правило, расчет молнии остается неизменным, и увеличение, скажем, интенсивности направленного света выше 1,0, безусловно, приемлемо. Другой способ, которым значение может превысить единицу, - просто сложить вместе несколько источников света.

Tone Mapping

Вы, конечно, поняли концепцию. Есть довольно много разных способов сделать фактическое сопоставление, от более простого / наивного color = clamp(hdrColor * exposure) до более сложного (и лучшего), который вы опубликовали.

Адаптивное отображение тонов может быстро усложниться. Опять же, наивный способ - просто нормализовать цвета путем погружения в самый яркий пиксель, что, безусловно, сделает трудным / невозможным восприятие деталей в более темных частях изображения. Еще можно усреднить яркость и зажать. Или вы можете сохранить гистограммы нескольких последних кадров целиком и использовать их при отображении.

Другой метод - нормализовать каждый пиксель только значениями соседних пикселей, то есть «локальное отображение тонов». Обычно это не делается при рендеринге в реальном времени.

Хотя это может показаться сложным, опубликованная вами формула даст очень хорошие результаты, поэтому ее можно использовать. Если у вас есть рабочая реализация, не стесняйтесь экспериментировать здесь. Также доступны отличные статьи :)

Гамма. Сейчас важна гамма-коррекция, даже если вы не используете HDR-рендеринг. Но не волнуйтесь, это несложно.

Самое главное - всегда быть в курсе, в каком цветовом пространстве вы работаете. Как и число без единицы, цвет без цветового пространства редко имеет смысл. Теперь нам нравится работать в наших шейдерах в линейном цветовом пространстве (rgb), то есть цвет с удвоенными значениями rgb должен быть вдвое ярче. Однако мониторы работают не так.

Камеры и программы для редактирования фотографий часто просто скрывают все это от нас и просто сохраняют изображения в формате, который нравится монитору (так называемый sRGB).

У sRGB есть дополнительное преимущество - сжатие. Обычно мы сохраняем изображение с 8/16/32 бит на пиксель на канал. Если вы сохраняете изображения в линейном пространстве и у вас есть небольшие, но очень яркие пятна на изображении, ваш бит 8/16/32 может быть недостаточно точным, чтобы сохранить разницу яркости в более темных частях изображения, и если вы снова их отображаете (из конечно гамма правильная) детали могут теряться в темноте.

Вы можете изменить цветовое пространство, в котором ваши изображения сохраняются во многих камерах и программах, даже если оно иногда немного скрыто. Поэтому, если вы говорите своим художникам сохранять все изображения в линейном цветовом пространстве (RGB), вам вообще не нужно делать гамма-коррекцию изображений. Поскольку большинство программ, таких как sRGB и sRGB, обеспечивают лучшее сжатие, как правило, рекомендуется сохранять изображения, описывающие цвет, в sRGB, поэтому для них необходимо выполнить гамма-коррекцию. Изображения, которые описывают значения / данные, такие как карты нормалей или карты рельефа, обычно сохраняются в линейном цветовом пространстве (если ваш нормальный [1.0, 0.5, 0.0] просто не имеет угла 45 градусов, все будут сбиты с толку; преимущество сжатия также сводится к нулю с нецветными изображениями).

Если вы хотите использовать текстуру sRGB, просто сообщите об этом OpenGL, и он преобразует ее в линейное цветовое пространство без снижения производительности.

void glTexImage2D(  GLenum target,
  GLint level,
  GLint internalFormat,  // Use **GL_SRGB** here
  GLsizei width,
  GLsizei height,
  GLint border,
  GLenum format,
  GLenum type,
  const GLvoid * data);

О, и, конечно же, вы должны гамма-корректировать все, что вы отправляете на свой дисплей (так что переходите с линейного на sRGB или гамму 2.2). Вы можете сделать это в тональной карте или на другом этапе постобработки. Или позвольте OpenGL сделать это за вас; см. glEnable(GL_FRAMEBUFFER_SRGB)

person Bithurler    schedule 03.04.2015