Thunder Engine Development
35 subscribers
19 photos
13 links
Записки разработчика игрового движка. Чат канала @thunderengine_chat
Download Telegram
На этой неделе занимался улучшением пайплайна рендеринга. Было сделано много, всего и не упомнить.

Основной упор сделал на улучшение Indirect Lighting составляющей изображения. IBL имеет огромное влияние на финальную картинку. Оценить разницу вы можете на скриншотах.

Так-же немного прокачал сохранение динамических свойств. И исправил тени.

#thunderengine
👍2🔥2
Еще одна визуальная фича заезжает в графический пайплайн.

Корректировка яркости - позволяет преобразовать HDR цветовое пространство в LDR. Без ее использования расширенный цветовой диапазон отрезается до диапазона 0-1 (0-255) и могут потеряться некоторые детали. Тонмапинг немного сжимает диапазон позволяя сохранить больше деталей.

Так-же теперь движок поддерживает базовую цветокоррекцию основанную на Color Grading LUT. Данная фича позволяет художнику контролировать и подстраивать цветовое пространство и настроение сцены под свои нужды. Пример вы можете наблюдать на скриншоте.

#thunderengine
🔥4
Внезапное прозрение. Формат текстур RGB10A2, который, как я думал, является HDR форматом, оказывается, таковым не является. Хотите хранить значения больше пространства 0...1 используйте форматы с плавающей точкой. К примеру RGBA16Float, который теперь будет использоваться у меня для Emissive буфера.

#thunderengine
🔥3👍2
Вот уже как пару недель я продолжаю ковырять графический пайплайн. Сегодня у нас на очереди эффект Depth of Field. Другими словами Глубина Резкости.

Этот эффект симулирует поведение камеры при максимально открытой диафрагме. Либо человека с очень плохим зрением.

Обратите внимание, что присутствует даже эффект Боке на источниках освещения. Радует то, что удалось все это запихнуть в один фрагментный шейдер. А значит оно будет доступно даже на простых устройствах (возможно с некоторыми изменениями в шейдере).

#thunderengine
👍2🔥2
Некоторое время назад, перебирая графический пайплайн, я заметил у себя одну закономерность. Очистка Render Target практически всегда идет за подключением этого самого Render Target.

Примерно так:
buffer->setRenderTarget(shadowTarget);
buffer->clearRenderTarget();


Более того, я помню, что в Vulkan можно было очищать буфер в момент его подключения. Без необходимости вызова дополнительных команд. И тут возникла мысль добавить в класс RenderTarget опции, определяющие поведение при его подключении. Посмотрел в UE5 и понял, что они делают примерно то-же самое.

Значит и мне нужен подобный рефакторинг. Сегодня, потратив совсем немного времени, запилил это удобство к себе. Теперь стратегия очистки определяется на стадии инициализации с помощью метода RenderTarget::setClearFlags. Так-же добавлена возможность определять регион очистки с помощью RenderTarget::setClearRegion (возможно переименую потом в setDrawRegion).

#thunderengine
🔥2
Важнейшей новостью уходящей недели, по моему мнению, является новость о том, что VK передает разработку NauEngine в руки "сообщества". Курировать разработку будет Университет ИТМО.

Новость максимально странная, хоть и не неожиданная. Движок NauEngine был выложен в открытый доступ в конце прошлого года. С тех пор он ни разу не обновлялся в публичном репозитории. Работа с комьюнити так-же не осуществлялась. За это время был принят всего ОДИН Pull Request. Связанный с исправлением ошибок в Readme файле.

Разработчики не отвечали на создаваемые сообществом issues. Рост сообщества так же, на мой взгляд, был медленным. Всего порядка 320 звезд на момент публикации в репозитории и 45 форков.

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

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

Одно радует, это подтверждение мысли о том, что не все можно залить деньгами.

#nauengine
👍2👌2
Сегодня наконец замержил довольно старый Pull Request добавляющий возможность собирать редактор с использованием библиотеки Qt6. В новой, мажорной версии Qt были убраны различные методы и классы с пометкой Deprecated, что привело к необходимости доработать код на своей стороне.

Зато теперь редактор собирается и запускается на MacOS с процессором ARM (M серии). Картинку правда пока не выдает, т.к. Apple остановили поддержку OpenGL на версии 4.3 если не ошибаюсь. Для картинки теперь нужна поддержка Metal, над которой я работаю время от времени.
🔥4
Когда я только начинал изучать Metal (графический API от Apple), я виден много общего с Vulkan. И мне это нравилось. Местами он был проще в использовании чем Vulkan.

Спустя некоторое время, я начал замечать некоторые странности в API. Вот пример из жизни (сильно упрощенный):
MTL::RenderPipelineDescriptor* renderPipelineDescriptor;
....
renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(pixelFormat);


Класс RenderPipelineDescriptor используется для создания RenderPipelineState. Главного объекта отвечающего за отрисовку конкретного меша. Именно к нему крепятся шейдеры и различные настройки графического конвейера.
Совершенно не понятно зачем мне крепить к нему pixel format для аттачментов отдельно для каждого. В Vulkan я просто отдавал сам VkRenderPass ему и он там сам разбирался с форматом пикселеля.
Но с этим еще можно жить. Самый треш начался с вершинными атрибутами...
🤔1
Продолжаем нытье про Metal. Итак, RenderPipelineState должен иметь представление о поступающих вершинных атрибутах, что в общем-то логично. Ведь пайплайн должен знать оффсеты и индексы буферов в которых содержатся данные о вершинах рисуемой модели. Разработчик может хранить атрибуты разными способами. Есть несколько типичных схем:
1. Буфер < Позиция, UV, Normals; Позиция, UV, Normals; Позиция, UV, Normals и так далее
2. Буфер < Позиция, Позиция, Позиция; UV, UV, UV; Normals, Normals, Normals
3. Вариант похож на второй только каждый атрибут храним в отдельном буфере.

Я всегда предпочитал второй вариант. По причине того, что желательно хранить позицию отдельно от остальных атрибутов, на случай если вам понадобится построить BVH. Такой способ был ОК в Vulkan т.к. офсеты атрибутов можно передавать отдельно, не связывая его с пайплайном. Таким образом, можно отделять саму геометрию от пайплайна который ее рисует. Можно поменять рисуемый меш прямо на рантайме. В Metal можно тоже поменять. Но офсеты нужно подать заранее,при создании пайплайна. А в случае второго варианта, вам, для вычисления офсетов, обязательно знать количество вершин в буфере. В этом заключается основное неудобство, над котором мне предстоит подумать.
👍1
Каждый раз когда я начинаю работать над поддержкой нового графического API, я начинаю с простейшей задачи. Что может быть проще прямоугольника с наложенным шейдером? Так и сегодня я наконец вывел требуемый прямоугольник с использованием Metal API и стал на один шаг ближе к возвращению поддержки MacOS. Еще предстоит многое сделать и, возможно, переделать, но начало положено!

#thunderengine
🔥53👍2
Следующими двумя шагами в портировании графического пайплайна на Metal, были добавление поддержки текстур и добавление поддержки параметров для Материалов. На скриншоте вы можете видеть работу шейдера, который окрасил текстуру в красный цвет (цвет задается из параметра) и со сдвигом UV координат, на основе таймера. Еще 2 маленьких шага на пути к мировому господству в тайне от санитаров!

#thunderengine
🔥2😁1
Немного о том, какие шаги еще предстоит сделать, что-бы выпустить поддержку metal в релиз?
1. Поддержка рендер таргетов - это буферы в которые производится отрисовка промежуточных результатов.
2. Поддержка рендеринг стейтов (настройки смешивания, теста глубины и пр.)
3. Чтение из GPU текстур в CPU память - нужно что бы можно было выделять объекты и рендерить иконки в редакторе
4. Проверка работы рендера в других окнах отличных от главного (редактор материалов как пример)

После этого поддержку Metal можно будет выпускать в Draft Release и править возможные баги
🔥3
В процессе работы с графическими API, очень важно иметь инструмент, позволяющий заглянуть в содержимое промежуточных буферов, проверить корректность байндингов ресурсов, проверить производительность. Любой уважающий себя разработчик графики должен уметь работать с GPU профилировщиками.

Но как обстоят дела на MacOS. Все очень не просто. У разработчика нет внешнего инструментария позволяющего подключиться к процессу и "тормознуть кадр" для отладки.

Однако, не все так плохо, купертиновцы позаботились об API профилировщка внутри самого Metal. Условно говоря, вы вызываете специальные функции в начале и в конце профилируемого кадра, а Metal записывает все в специальный буфер и позволяет сохранить дамп на диск. Далее с помощью XCode можно открыть дамп и проанализировать что происходило во время отрисовки. Пример вы можете видеть на скриншоте.

Удобно ли оно? В целом да! Глючно ли оно? Тоже да! Но это точно лучше чем ничего!

#thunderengine
🔥5
Докладываю недельный прогресс, по добавлению поддержки Metal.
1. Добавил поддержку рендер таргетов.
2. Рендеринг стейты тоже теперь доступны.
3. Рендер так-же работает в других окнах.

Итого 3 из 4 основных задач готовы.

Однако, в процессе работы вскрылись некоторые проблемы, которые предстоит починить:
- Смена размеров окна приводит к потере картинки (подозреваю, что это связано с инвалидацией текстур в рендер таргетах)
- Текст рисуется тоже странно - полагаю, что это так-же связано с изменением размера текстур.
- Не рисуются Frame объекты из UI пакета
- В отличии от BottomLeft координат, Metal использует TopLeft систему координат, что накладывает проблемы с ориентацией в рендер таргетах (некоторые слои рисуются перевернутыми)

Ну и все еще предстоит добавить чтение из текстур.

Очень надеюсь, что успею все починить к концу месяца.

#thunderengine
🔥4👍21
Похоже, что эра геометрических шейдеров подошла к концу (а ведь я их совсем недавно добавлял).

В API Metal их нет! Совсем нет. В принципе, когда я их добавлял в движок, я знал что они считаются устаревшими. Вместо них предлагается использовать Mesh шейдеры. Но их нет в старых версиях OpenGL которые используются в веб. Дилемма!

С другой стороны у меня пока нет юзкейсов на их использование. А у вас?
🤔3
Небольшая рекомендация при работе с функциями dFdx и dFdy. Если вы используете их, для различных вычислений в экранном пространстве. Крайне рекомендую оборачивать их в abs функцию, что бы потом не чесать затылок как я. Эти функции могут возвращать отрицательные значения!
👍1🔥1
После разговора, с моим хорошим знакомым из студии FIFTYTWO, последние 2 недели обдумываю позиционирование своего движка в этом конкурентном мире.
Так-же размышляю о причинах провала "первого отечественного игрового движка NauEngine". На данный момент, я склоняюсь к мысли, что он был неправильно позиционирован, не нашел своего пользователя и благополучно слит во время финансовой оптимизации VK.

Но сколько таких проектов на просторах интернета? Очень много! Если вы откроете Гитхаб (https://github.com/topics/game-engine), то просто офигеете от их количества, разной степени популярности.
Как же не потонуть среди такого потока проектов? Ответ один, правильное позиционирование и поиск своей ниши!

Сейчас я пытаюсь анализировать (между подходами к портированию на MacOS) что отличает успешные проекты, от провальных. Что привлекает людей?
Я заметил, что многие провальные проекты слишком увлекаются графикой. Они бесконечно тратят время на совершенствование выдаваемой картинки. Некоторые даже упарываются в рейтрейсинг, забывая про основной аспект игрового движка...

Инструментарий! Если кто не знает, я пишу движок уже очень давно. Когда давно потухшие звезды были еще молодыми. Ладно не настолько. С самого начала я мечтал сделать успешный коммерческий движок, но потом Unreal Engine 4 вышел в OpenSource и просто покрыл весь мир.
Пришлось подстраиваться и тоже выпустить движок в открытое плавание. Но этого оказалось недостаточно. Нельзя построить стадион и ожидать что люди подтянуться (не помню откуда это). Поэтому я продолжаю думать о вероятной нише.

Что совершенно точно я не собираюсь делать, так это зацикливаться на графике. Много прекрасных игр, сделаны с достаточно примитивными моделями освещения. Маленькие студии (а я целюсь в маленьких). Не могут позволить себе высококлассный контент. Т.к. он стоит очень дорого. Графика уровня Super Mario Odyssey вполне меня устроит. Поэтому я фокусируюсь на удобстве инструментария и пытаюсь привлечь, кого-то для сотрудничества. Людей привлекают реализованные на движке игры!

#thunderengine
5👍3🔥2
Продолжаю держать вас в курсе делиться с Вами впечатлениями от использования Metal.

Вот уже 3 недели я активно разрабатываю с использованием Metal. После определённых неудобств в использовании, связанных скорее с недостатком опыта работы, я могу с уверенностью сказать, что это прекрасный API для работы с графикой!

Metal по своей сути очень похож на Vulkan, только с меньшим количеством заморочек с управлением памятью. Я бы поместил Metal по сложности освоения между OpenGL и Vulkan.

Столь стремительное портирование функционала на Metal, мне обеспечила база написанная на Vulkan. Получился очень похожий код, только компактней и стабильней.

Могу ли я рекомендовать Metal для освоения? Если вы работаете с MacOS или iOS однозначно да! Так-же, это прекрасным стартом, для работы с современной графикой!

#thunderengine
3👍3
Я долго к этому шел и наконец это случалось. Дамы и господа, MacOS вернулся в поддерживаемые платформы.

Теперь рендер использует Metal API для отрисовки картинки!

К сожалению, с иконками возникла заминка, но она скорее связана с необходимостью переделки механизма создания иконок, чем с проблемами с Metal.

#thunderengine
🔥5🍾4
Решил немного расслабиться на этой неделе и практически не писал код движка.

Однако, это не означает что я его совсем не писал. Сейчас я перерабатываю макросы, для работы с интроспекцией. A_REGISTER и A_OVERRIDE макросы будут убраны на этой неделе.

Вместо них можно будет будет использовать A_OBJECT и A_OBJECT_OVERRIDE. Сделано это с одной простой целью, сделать различие между классами основанными на классе Object и другими классами.

Да да я хочу добавить возможность делать интроспекцию и для классов не основанных на классе Object. Макрос для таких классов будет называться A_GENERIC. Так-же хочу попробовать сделать возможность добавлять в интроспекцию, конструкторы с параметрами.

А для чего это нужно, возможно спросите вы? Все очень просто. Чем больше классов будет покрыто интроспекциями, тем больше будет возможностей их использования из скриптов!
🔥4