Почти все игровые ретроконсоли генерируют цвета в каком-нибудь из вариантов RGB-кодирования.
Но эти цвета пикселей часто предназначены для экранов, совершенно отличающихся от тех, на которых обычно работают эмуляторы. В этой статье я расскажу о важности эмуляции цветов, приведу несколько примеров кода и скриншоты.
Самым распространённым сегодня видом дисплеев являются ЖК-панели (LCD). Они известны тем, что имеют очень плохие уровни чёрного. Различия между TN, PVA и IPS не слишком на это влияют.
Отдельные фанаты играют на ЭЛТ-мониторах, и всё большую популярность набирают OLED-экраны, особенно на телефонах и планшетах. Но в этой статье мы в основном будем рассматривать ЖК-экраны, хотя данная методика важна для дисплеев любого типа.
Точность цвета
Первая важная деталь: большинство компьютеров работает в режиме 24-битного цвета, обеспечивающем 8-битную детализацию цветов для каналов красного, зелёного и синего. Но в большинстве старых игровых систем цвета не задаются с такой точностью.
Например, Sega Genesis кодирует 9-битные цвета, что даёт по 3 бита на канал.
Самым наивным решением было бы поместить 3 бита в самые старшие 3 бита вывода, а младшие 5 бит оставить пустыми, но при этом белый цвет становится немного серым.
Пример:
000 000 000 -> 000'00000 000'00000 000'00000 111 111 111 -> 111'00000 111'00000 111'00000
Если же заполнить их единицами, то слишком светлым становится чёрный.
Пример:
000 000 000 -> 000'11111 000'11111 000'11111 111 111 111 -> 111'11111 111'11111 111'11111
Решение заключается в том, чтобы повторять исходные биты, чтобы они заполнили все выходные биты.
Пример:
000 -> 000 000 00... 010 -> 010 010 01... 011 -> 011 011 01... 111 -> 111 111 11...
В виде кода:
uint8 red = r << 5 | r << 2 | r >> 1 //rrr00000 | 000rrr00 | 000000rr -> rrrrrrrr
Эмуляция экрана
Игровые ретросистемы не были предназначены для работы на современных ЖК-мониторах компьютеров. Обычно домашние консоли были рассчитаны на ЭЛТ-экраны, а в портативных консолях применялись гораздо более старые и менее точные ЖК-панели.
В этой статье мы не будем рассматривать артефакты экранов, такие как кривизна экрана, строки развёртки, хроматическая аберрация, межкадровое смешение, апертурные решётки и т.д.: мы сосредоточимся пока только на цветах отдельных пикселей.
Мониторы PC
В мониторах существует довольно широкий диапазон цветов, потому что только некоторые из них профессионально калибруются по стандартам наподобие SRGB, но в общем случае, лучшее, чего мы можем добиться — попытаться эмулировать цвета так, как будто мы используем правильно калиброванный SRGB-монитор.
Эмуляция ЭЛТ: Super Nintendo
Основное различие между ЭЛТ-экранами и ЖК-мониторами компьютеров заключается значительно сниженных уровнях чёрного, что можно только немного компенсировать при помощи кривой гамма-коррекции:
//SNES colors are in RGB555 format, so there are 32 levels for each channel static const uint8 gammaRamp[32] = { 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff, };
Эта таблица позаимствована у Overload of Super Sleuth / Kindred. Она затеняет нижнюю половину цветовой палитры, оставляя верхнюю часть неизменной.
Это оказывает потрясающее воздействие на изображение при эмуляции: слева показан оригинал, справа — изображение с применённой гамма-коррекцией:
Эмуляция ЖК: Game Boy Advance
Game Boy Advance имел один из худших ЖК-экранов с совершенно блеклыми цветами. Хитрые разработчики поняли, что значительно преувеличив цвета, можно получить на реальном оборудовании более приятные результаты.
Разумеется, если использовать эти цвета на стандартном ЖК-мониторе, то результат окажется пёстрым кошмаром. К счастью, мы можем компенсировать и это, создав достаточно естественные цвета:
double lcdGamma = 4.0, outGamma = 2.2; double lb = pow(B / 31.0, lcdGamma); double lg = pow(G / 31.0, lcdGamma); double lr = pow(R / 31.0, lcdGamma); r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
Этот фрагмент кода написан Talarubi.
Намного более разительный контраст по сравнению с ЭЛТ — сверху оригинал, снизу версия с цветокоррекцией:
Эмуляция ЖК: Game Boy Color
Экран Game Boy Color был на удивление лучше в воспроизведении цвета и конечной картинке может присутствовать только незначительное размытие цветов.
В эмуляторах Game Boy Color достаточно популярен такой алгоритм:
R = (r * 26 + g * 4 + b * 2); G = ( g * 24 + b * 8); B = (r * 6 + g * 4 + b * 22); R = min(960, R) >> 2; G = min(960, G) >> 2; B = min(960, B) >> 2;
К сожалению, я не знаю, кто его написал алгоритм. Если вы знаете, то сообщите мне, чтобы я мог указать авторство!
Как и раньше, оригинал слева, версия с цветокоррекцией — справа:
Этот пример был выбран специально: хотя оригинал выглядит живее и предпочительнее, если приглядеться, то заметен шахматный паттерн вокруг персонажа, который светлее фона.
Скорее всего, это был недосмотр со стороны разработчиков, потому что на реальном Game
Boy Color оттенки белого размыты и два отличающихся оттенка цвета сливаются друг с другом почти безупречно.
В заключение
Существует ещё много систем, которым пока не хватает хороших фильтров эмуляции цветов.
Их очень трудно настраивать. Из самых важных примеров можно указать WonderSwan и Neo Geo Pocket, у которых на момент написания статьи не было хороших фильтров аппроксимации цветов.
С портативными консолями всё ещё сложнее, потому что в них часто отсутствует задняя подсветка (а иногда и передняя подсветка!) и есть способы изменения контраста, благодаря чему нет какого-то истинного значения «цвета» для конкретного значения RGB.
Особо интересным пограничным случаем является WonderSwan Color, в котором есть программно устанавливаемый флаг для повышения контраста выводимого изображения.
Пока мы не знаем, как достоверно эмулировать такое поведение, и непонятно, сможем ли вообще.
Эмуляция цветов — это область, требующая больше внимания, поэтому если вы специалист в математике и анализе цветов, то ваша помощь очень бы пригодилась сцене эмуляции!