iOS Металл. Почему простое изменение colorPixelFormat приводит к более ярким изображениям?

В Metal на iOS по умолчанию colorPixelFormat имеет вид bgra8Unorm, Когда я меняю формат на rgba16Float все образы сияют. Зачем?

Пример:

произведение искусства

MTKView с форматом bgra8Unorm, Текстурный четырехугольник. Текстура создана с SRGB=false,

MTKView с форматом rgba16Float, Текстурный четырехугольник. Текстура создана с SRGB=false,

Почему все ярче с rgba16Float, Я понимаю, что SRGB=false подразумевает, что при импорте иллюстраций гамма-коррекция не выполняется. Предполагается, что произведение искусства не применяет гамму.

Что здесь происходит?

2 ответа

Если ваша работа имеет гамму (она соответствует первому загруженному изображению), вы должны преобразовать ее в линейную гамму, если хотите использовать ее в линейном пространстве.

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

НО: Читая некоторые ваши комментарии, текстура - это не изображение, а.svg?? Вы преобразовали свои значения цвета в линейное пространство?

Вот в чем дело: значения RGB являются бессмысленными числами, если только вы не определите, как эти значения RGB относятся к заданному пространству.

#00FF00 в sRGB, например, отличается от #00FF00 в Adobe98. В твоем случае ты идешь линейно, но какие праймериз? Все еще используете праймериз sRGB? P3 Primaries? Я не вижу реального смещения оттенка, поэтому я предполагаю, что вы используете основные цвета sRGB и линейную кривую передачи для второго примера.

ЭТО СКАЗАЛ, что значение RGB зеленой рубашки верхнего среднего ребенка равно #8DB54F, нормализовано до 0-1, то есть 0,553 0,710 0,310 . Эти числа сами по себе не знают, закодированы ли они гамма-кодировкой.

ОТНОШЕНИЯ МЕЖДУ sRGB, Y и Light:

Для целей этого обсуждения мы будем считать простую гамму sRGB 1/2.2, а не кусочную версию. То же самое для L*

В sRGB, #8DB54F при отображении на мониторе sRGB с гамма-кривой sRGB яркость (Y) равна 39

Это может быть найдено

(0.553^2.2)*0.2126 + (0.710^2.2)*0.7152 + (0.310^2.2)*0.0722

или же 0.057 + 0.33 + 0.0061 = 0.39 and 0.39 * 100 = 39 (Y)

Но если управление цветом говорит, что значения линейны, то гамма-коррекция отбрасывается и (более или менее):

0.553*0.2126 + 0.710*0.7152 + 0.310*0.0722

или же 0.1175 + 0.5078 + 0.0223 = 0.65 and 0.65 * 100 = 65 (Y)

(Предполагая, что используются одинаковые коэффициенты.)

Яркость (Y) линейна, как свет. Но человеческое восприятие не таково, равно как и ценности sRGB.

Y - это линейная яркость от CIEXYZ, в то время как она спектрально взвешена на основе реакции глаза на разные длины волн, она НЕ однородна с точки зрения яркости. По шкале от 0 до 100 18,4 воспринимается как середина.

L* - легкость восприятия от CIELAB (L* a* b*), это (упрощенная кривая):

L* = Y^0.42 По шкале от 0 до 100 L* 50 - это "воспринимаемое среднее" значение. Таким образом, зеленая рубашка для Y 39 - это L* 69, когда интерпретируется и отображается как sRGB, а Y 65 - около L* 84 (эти числа основаны на математике, вот значения для средства выбора цвета на моем MacBook):

sRGB - это гамма-кодированный сигнал, созданный для наилучшего использования ограниченной битовой глубины 8 бит на канал. Эффективная гамма-кривая аналогична человеческому восприятию, поэтому для определения более темных областей используется больше битов, поскольку человеческое восприятие более чувствительно к изменениям яркости в темных областях. Как отмечено выше, это упрощенная кривая:

sRGB_Video = Linear_Video^0.455(И следует отметить, что МОНИТОР добавляет показатель около 1,1)

Таким образом, если 0% является черным, а 100% - белым, то средний серый, точка, которую большинство людей скажет, находится между 0% и 100%:

Y 18.4%. = L* 50% = sRGB 46.7%

То есть шестнадцатеричное значение sRGB #777777 будет отображать яркость 18,4 Y, что эквивалентно воспринимаемой яркости 50 л *. Средний серый.

НО ЖДУ, ТАМ БОЛЬШЕ

Итак, что происходит, выговоритеMTKViewчто вы отправляете ему данные изображения, которые ссылаются налинейные значения. Но вы на самом деле отправляете ему значения sRGB, которые легче из-за примененной гамма-коррекции. А затем управление цветом принимает линейные значения и преобразует их в необходимые значения для вывода на дисплей.

Управление цветом должно знать, чтоозначают значения, к какому цветовому пространству они относятся. Когда вы установите SRGB=falseзатем вы говорите, что отправляете линейные значения, а не значения, закодированные с помощью гаммы.

НО вы явно отправляете гамма-кодированные значения в линейное пространство без преобразования / декодирования значений в линейное. Линеаризация не произойдет, если вы не сделаете это неявно.

РЕШЕНИЕ

Линеаризовать данные изображения ИЛИ установить флагSRGB=true

Пожалуйста, дайте мне знать, если у вас есть дополнительные вопросы. Но вы также можете посмотреть часто задаваемые вопросы о Poynton Gamma или также часто задаваемые вопросы о цвете.

Кроме того, для вашего серого: линейное значение 0,216 эквивалентно значению sRGB (0-1) 0,500

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

Недостающий фрагмент — это то, как Core Animation объединяет CAMetalLayer, когда не указано no . Если формат пикселейbgra8Unorm, Core Animation предполагает, что ваши пиксельные данные находятся в нелинейном пространстве sRGB. Если формат пикселейrgba16Float, Core Animation предполагает, что ваши пиксельные данные находятся в линейном пространстве. Вот почему все ваши цвета кажутся ярче. Цвета кажутся слишком яркими и размытыми — это типичный признак того, что цвета sRGB интерпретируются как цвета в линейном пространстве.

На самом деле исправить это довольно просто. Просто установитеcolorspaceпринадлежащийCAMetalLayerчтобы соответствовать цветовому пространству вашего контента (обычно sRGB):

      layer.colorspace = CGColorSpace(name: CGColorSpace.sRGB)!

и ваш контент должен выглядеть одинаково независимо от формата пикселей.

Другие вопросы по тегам