Hald CLUT

В Dagon появилась поддержка 3D-текстур, что позволило реализовать цветокоррекцию с использованием цветовых таблиц формата Hald CLUT. CLUT расшифровывается как color lookup table – таблица поиска цвета: в памяти хранится текстура, в которой стандартным цветам sRGB сопоставлены какие-то другие цвета – вместо оригинальных цветов пикселей на вывод идут значения, прочитанные из 3D-таблицы. Принцип примерно тот же, что использовался в индексированных цветовых режимах, только в данном случае таблица охватывает более широкий диапазон RGB. Чаще всего CLUT используется для имитации характерной «пленочной» цветовой гаммы на цифровых снимках, но ее возможности гораздо шире. В таблице цвета могут быть абсолютно любые – с математической точки зрения, она является функцией, которая переносит цвет из одного пространства в другое. Чем больше таблица, тем точнее ее охват.

Оргинал таблицы в формате Hald CLUT выглядит следующим образом (PNG можно скачать тут):

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

Преимущество Hald CLUT состоит в эффективном расположении значений – таблица размером 4096×4096 охватывает весь 24-битный диапазон sRGB (16777216 цветов) и при этом отлично сжимается в PNG. Для хранения таблицы важно использовать lossless-формат, так как сжатие с потерями вносит мелкие искажения в цвета, а в данном случае важно сохранить точность информации.

Еще одна немаловажная фича формата – прямая совместимость с 3D-текстурами OpenGL. Достаточно просто декодировать картинку в буфер RGB и создать из этого буфера текстуру функцией glTexImage3D – никаких промежуточных конвертаций не требуется. Эта текстура затем передается в шейдер постобработки, который выглядит совсем элементарно:

vec3 inputColor = texture(colorBuffer, texCoord).rgb;
vec3 outputColor = texture(lookupTable, inputColor).rgb;

В Dagon поддержка создания 3D-текстуры из двумерного буфера встроена в класс Texture. Нужно загрузить таблицу как ассет ImageAsset, создать текстуру и проинициализировать ее методом createHaldCLUT. Результат передается в стандартный стек постобработки (game.postProcessingRenderer):

ImageAsset aCLUT;

override void beforeLoad()
{
    aCLUT = addImageAsset("data/food.png");
}

override void afterLoad()
{
    Texture clut = New!Texture(assetManager);
    clut.createHaldCLUT(aCLUT.image, 256);
    game.postProcessingRenderer.colorLookupTable = clut;
    game.postProcessingRenderer.lutEnabled = true;
}

Поддерживаются таблицы любых разрешений, но вы должны сами правильно вычислить размер 3D-текстуры, соответствующей вашей CLUT. Например, для таблицы 4096×4096 это будет 256x256x256, как в моем примере. Если в этот параметр передать неправильное значение, то будет построена некорректная текстура (в релизе обязательно добавлю валидацию).

Пример использования на основе демки с автомобильной физикой – обработанное изображение и соответствующая таблица:

Итоги 2022 года

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

  • Вышли Dagon 0.13 и 0.14. В этих версиях были исправлены многие баги рендер-движка, улучшен загрузчик OBJ (добавлена поддержка квадов), произведен рефакторинг системы текстур, ускорена загрузка текстур через dlib. stb_image теперь опционален и используется как расширение dagon:stbi. Появилась поддержка формата сжатия ASTC. Изменены свойства материалов для достижения прямой совместимости с glTF. Появилась новая система текстурирования ландшафта. Добавлена поддержка радиального размытия. Удалено расширение dagon.ext.physics, так как теперь полноценно поддерживается физический движок Newton (расширение dagon.ext.newton). Добавлена экспериментальная интеграция UI-тулкита ImGui, а также поддержка валидации состояния OpenGL и более информативные отладочные сообщения.
  • Наконец-то выпустил dlib 1.0. В этой версии ускорена загрузка изображений, добавлена валидация при создании POSIX-потоков, улучшен модуль dlib.math.interpolation.hermite – добавлена функция вычисления производной для сплайна Эрмита. Исправлено несколько важных багов в математическом и геометрическом пакетах. Также вышло обновление dlib 1.1.0, в котором я добавил алгоритм обнаружения пересечения выпуклых тел MPR, а также исправил некоторые баги.
  • Я портировал игру DagoBan Матеуша Мушинского на актуальную версию Dagon. Этот клон Sokoban, написанный в качестве демонстрации возможностей тулкита Nuklear, является первой законченной игрой на основе Dagon.
  • Я написал три новые статьи на Medium: Almighty Alias, Metaprogramming with Alias Sequences, Game UI with Nuklear.
  • За этот год мне удалось собрать донатов на сумму $34.04 – они частично покрыли оплату хостинга и домена для сайта timurgafarov.ru. Огромное спасибо всем, кто перечислил деньги!

Ну и, конечно, не могу не назвать самые значимые для меня события в мире CG, СПО и геймдева:

  • Выход Unreal Engine 5 с очень впечатляющими фичами – особенно Lumen, технологией динамического глобального освещения. Но, каким бы крутым ни был UE, я не собираюсь отказываться от собственного движка)
  • Выход Newton 4, новой версии моего любимого физического движка. Жду теперь C API для создания привязки к D
  • Stable Diffusion – нейросеть, генерирующая изображения по текстовому описанию с пугающей реалистичностью.

10 лет на GitHub

В этом декабре исполняется ровно 10 лет с тех пор, как я зарегистрировался на GitHub! Хороший повод рассказать о своем опыте работы с платформой, порассуждать о системах контроля версий и, в целом, о том, как они повлияли на современное состояние IT.

(далее…)

Физика автомобиля

Демка с физикой автомобиля, которую я разработал в начале этого года для Patreon Sponsor Folder, теперь доступна на GitHub в репозитории https://github.com/gecko0307/vehicle-demo – с многочисленными улучшениями, которые я сделал за последние месяцы (в частности, появилась поддержка модели трения колес Pacejka Magic Formula). Пруф того, что на основе связки Dagon + Newton вполне можно написать гоночную игру. Как-нибудь, возможно, напишу подробную статью на эту тему.

10 лет блогу

Сегодня мой блог о разработке игр на языке D отмечает 10-летний юбилей! 30 сентября 2012 года я опубликовал первый пост, в котором поставил задачу написать 3D-игру на D с использованием OpenGL. С тех пор утекло много воды, я несколько раз переписывал заново свой движок, перешел с 32-битной на 64-битную архитектуру, сменил несколько операционных систем и версий OpenGL, но изначальная цель не поменялась.

В 2015 году блог привлек внимание русскоязычного филиала журнала PC Magazine, который проводил опрос, посвященный разработке игр: как устроены игры изнутри, как программируются серверы, как моделируется игровой мир, какие используются средства разработки. Материал по результатам опроса – в котором, в числе прочего, упоминается и мой движок – был опубликован на сайте журнала, но, к сожалению, теперь не доступен в связи с уходом PC Magazine из России. В 2019 году, спустя 7 лет со дня открытия блога https://dlanggamedev.blogspot.com, я переехал на коммерческий хостинг и личный WordPress. Администрирование собственного WP-сайта было для меня совершенно новым опытом, я изучил PHP и улучшил навыки верстальщика – однажды даже написал свой спам-фильтр для комментариев, но в этом оказалось мало смысла после перехода на reCAPTCHA v3.

За эти годы инди-геймдев, к сожалению, так и не стал для меня коммерчески выгодным занятием. Скажу прямо: работа над Electronvolt непомерно затянулась, и вряд ли ее выпуск как-то финансово оправдает вложенные усилия и время. Доход, который я получаю от всех моих хобби-проектов, основан на донатах через Patreon и PayPal. Но это не значит, что я разочарован – наоборот, в процессе я написал кучу полезного кода, который мне постоянно пригождается в других сферах деятельности. За эти 10 лет я глубоко погрузился в профессию графического разработчика и изучил множество технологий: в 2016 году даже рассматривал возможность стажировки в NVIDIA, но раздумал, так как не захотел переезжать в Москву. Позднее мне довелось четыре года проработать в цифровой рекламе в продакшн-компании SmartHead, где я сделал множество интерактивных баннеров и несколько рекламных игр. Самыми интересными проектами были игры “Привидения и котики” для Google и “Food Box Killer” для Ehrmann (вторая примечательна использованием движка Phaser 3), а также брендинг Forbes для BMW с анимацией на основе шейдерного эффекта WebGL. К сожалению, выложить эти проекты на сайт не могу из-за NDA, но вы можете их увидеть на сайте баннерного отдела SmartHead. Знания, которые я приобрел благодаря своему хобби, очень помогли в работе, и я даже как-то раз использовал D для одной специфической задачи – а именно, для написания генератора выпуклых оболочек для спрайтов под физический движок Matter.js.

Сегодня я занимаюсь, в основном, веб-разработкой и графическим дизайном на фрилансе. Много пишу на JS (браузерный код и Node.js), а D так и остался языком “для души”. Но, может, это и к лучшему – ведь должно же быть у человека чисто творческое занятие, в котором он полностью свободен и независим от чужих задач и потребностей: по образованию я художник, и к программированию отношусь как к отдельному виду искусства. На D легко и приятно писать, и я все еще считаю его лучшим из всех компилируемых языков – ни на минуту не пожалел, что вложил столько сил в код на нишевом языке с небольшим сообществом. Хотя часто жалею, что в сутках всего 24 часа – не успеваю отслеживать все интересные мне новые технологии. OpenCL, CUDA, Vulkan, WebGPU, аппаратная трассировка лучей – что-то прошло мимо меня, что-то я изучил лишь на самом базовом уровне. Но надеюсь, что смогу углубляться в эту сферу и дальше – и, конечно, вести блог еще 10 лет, минимум!