Relict Engine
55 постов
55 постов
12 постов
Добавлен Направленный источник света (Directional Light Source)
Добавлена TBN (TangentBinormalNormal) матрица в структуру передачи Vertex->Fragment
Добавлен пересчет Нормалей 3д модели в Мировое пространство
Исправлены ошибки шейдерного домена Surface
Исправлена ошибка очистки генерации Выражений в коде материла
Ну чтож, шейдер успешно внедрен, логика написана. Теперь нужно дописать оставшиеся юниты света и вплотную заняться объемным источником света для получения корректного света от звезд. После чего переключится на каст теней. Почему не сейчас? Потому что для теней нужно будет делать отдельный прогон шейдера в отдельный же буфер вывода (текстуру). Причем нужно будет реализовать несколько техник. Отдельно для планетарных и других крупных небесных объектов, и отдельно для мелочи, типо станций, кораблей, мелких обломков, итд.
Но перед этим всем, думаю, стоит наконец добавить код для чтения клавиш, чтобы камерой можно было гулять, ибо тестировать стало несколько не удобно.
Так-же, собирая тестовый релизный билд обратил внимание, что в Linux бинарях пропал ctd при завершении потоков. Конечно, это не означает, что ошибка исправлена, ибо в конфигурации Дебага она никуда не делась. Но, по крайней мере, можно не торопится с ее исправлением, ибо не критично (главное потом не забыть, про нее xD)
Бонус: Проверил, как направленный источник света будет работать с картой нормалей
это не движок, а внешний редактор шейдеров SHADERed, который я использую для предварительных тестов. Нормаль сгенерирована через Шум Перлина
В движок обработку карт нормалей добавлять пока не буду - займусь этим, когда дойду до текстур. Будет это где-то после теней и систем частиц. Тогда-же, наверное, и паралакс сделаю.
Доделана поддержка сцен и сцены внедрены в пайплайн отрисовки.
Переделан MulticastDelegate на версию, которая не требует использования std::bind
Продолжаю разведение GameThread и RenderThread (по сути осталось только деревья Сборщика мусора растащить окончательно)
Добавлена первая заготовка под юниты света в виде DirectionalLight юнита.
Добавлена двойная буферизация для буфера команд RenderThread
Рано обрадовался, работы (не по движку) пока еще довольно много + духота по мозгам долбит. Ползу медленней, чем обычно, поэтому решил пока бросить приоритет на отладку и производительность того, что уже сделано, чем на добавление нового функционала.
Как всегда больше всего проблем вылезает в Linux сборке - ведро как-то более либерально ко всему относится (причем настолько, что я ему уже не доверяю). Есть проблемы с крэшами сборки из-за Сборщика мусора при удалении объектов из разных потоков (происходит из-за состояния гонки [Родитель приходит к состоянию очистки памяти раньше, чем дочерние, что не есть правильно]), и кроме того, как полностью разделить деревья и вынести триггеры сборщика в отдельные не связанные сущности решения похоже нет (При этом такое поведение наблюдатся исключительно в Linux; Windows как-то пофиг на это, что добавляет отдельно батхерта). Хотя, возможно надо было так изначально делать, т.к. из-за кросс потоковых деревьев приходится паузить треды на тике Сборщика. Если деревья будут разделены, то этого делать будет уже не нужно, а следовательно и производительность несколько увеличится (в прочем там могут другие проблемы вылезти).
Так-же наконец-то добрался до света и pbr. Базовый (очень базовый) шейдер уже написал, теперь нужно прописать логику для юниформов (std140, естно) и работой со светом через ++. Думаю, сначала поэкспериментирую на DirectionalLight (как самом простом варианте), потом добавлю уже остальные по готовому шаблону. Финальным аккордом по теме глобального света должна стать реализация объемного источника света (нужен для реализации физически корректного света от звезд)
триада WVP (World, View, Projection) так-же перенесены на DSA
Добавлена поддержка нескольких активных сцен (миров)
Добавлен класс камеры
исправлено неопределенное поведение при обновлении трансформации юнита сцены (синхронизация состояний трансформов в начале кадра)
В очередной раз отваливался по рабочим вопросам =/ Но, вроде, вернулся. Чендж лог сегодня очень небольшой по этой-же причине.
Итак, миры и камеры.
Мир определяется рут объектом GameWorld, который хранит все объекты сцены, камеры итд.
Камер у сцен может быть сколь угодно много, но активной одномоментно (во всем движке) может быть только одна (дальше будет сделано исключение для RenderTarget камер, но это отдельно). При этом, сцена без активной камеры продолжит свою работу в фоне. Она продолжит тикать, обновляется, пересчитывается. Просто не будет выводится на экран.
Переключение камер происходит функцией Activate соответствующего Юнита.
При этом, если камера принадлежит другой сцене, то сцена так-же переключится.
Удален юнион UniformValue, как ненужный и не используемый
Заменена функция Set на шаблон с предопределёнными типами для удобства
UniformType удален из движка и используется только для разбора входных динамических параметров материала в RatTools
Замены легаси OpenGL буферы на DSA в коде создания динамических экземпляров (Instancing) материалов
Создание инстанций, кроме инстанции по умолчанию, теперь используют прямое копирование данных на стороне GPU, заместо заполнения буфера через шину
Добавлена заготовка под шейдерный домен Surface на основе физически корректного рендеринга (PBR)
Думается мне, тему инстансов на этом можно закрыть. Оно работает как нужно, параметры определяются, обновляются, читаются и рисуются ровно так, как требуется.
Для закрытии самой темы материалов осталось реализовать только вставки пользовательского кода в скрипт материала. Думаю, завтра/послезавтра уже сделаю. SPIR-V контейнеры отложим в долгий ящик. Сейчас это явно не приоритет.
Следующий этап - класс камеры и юниты источников света (чтобы можно было начать полноценную работу над PBR)
Ассет материала теперь содержит отдельный блок с возможными вводными параметрами шейдера по умолчанию отдельно от юниформов шейдера меатерила
В шейдер введен макет std140 для юниформов
Добавлен отдельный класс в модуле рендера для работы с инстанциями материалов через Uniform Buffer Object (UBO)
Для материалов, имеющих хотя бы один input параметр создается инстанция по умолчанию со значениями юниформов по умолчанию, с запретом на изменение
Добавлено "ленивое" создание инстанций на стороне модуля отрисовки по мере необходимости
Исправлена синхронизация потоков при передаче параметров инстанции материала. Теперь утилизируется uniq_cmd потока отрисовки вместо прямой установки
Переделал инстанции материалов на UBO. Все еще считаю их несколько сырыми и буду их еще какое-то время тестировать и дописывать их код. Кратенько опишу как это работает.
Во первых: UBO требует в шейдере макетной структуры, и поля в ней не могут иметь инициализаторов, поэтому пришлось написать довольно массивный парсер параметров с утилизацией variant и type_identity
Во вторых: эта структура требует выравнивая данных, поэтому, уже на стороне движка пришлось делать особую уличную магию перегоняя сырой буфер в выровненный cогласно стандарту
В третьих: чтобы не пересоздавать UBO буфер каждый раз, пришлось высчитывать офсеты юниформов и хранить их отдельно в виде пары офсет-размер. Таким образом при изменении одного параметра, в GPU отправится только он.
а вот от текстовой метки до конца так и не удалось избавится, благо у unordered_map итерация идет как 0(1)
ну и в четвертых, т.к. действие происходит сразу в двух потоках (игровом и отрисовки), то на выходе получается довольно много операций копирования (ссылки не доживают до исполнения очереди)
В общем снова на очереди вычитка, удаление старого кода, правка нового. Что-то упростить можно, структуры собрать в одном месте, чтобы не были раскиданы по юнитам. Возможно, выбросить нафиг union, ибо от него сейчас пользы никакой уже, но зато сильно меньше удобства при обновлении переменной юниформа, или обертку над ним хотя бы сделать удобства для.
Добавлена смена рабочий директории на необходимую (давно надо было сделать, но все забивал)
Добавлена первая итерация материал инстансов (в очень сыром виде, но работает)
Касательно инстанций, значит. Передал несколько класс шейдера. Пока по тупому, в лоб. На выходных надо будет все это просмотреть, вычитать еще раз, и переписать по человечески. А работает это так:
При инициализации контекста дергаются ассеты материалов на загрузку. и передаются в GLShaderProgram
GLShaderProgram это дело компилирует, проверяет и линкует (когда-нибудь потом будет добавлен кэш, но пока рассчитываем на кэш драйвера)
После этого проходится по инпутам, собирая их в 100500 мапов
При отрисовке, если на юнит выставлен инстанс, а не сам материал, проверяет в таблице инстанса по текстовой (!) метке наличие установленного параметра.
Выставляем инстансы, но не задаем параметры. При инициализации рассчитываем на дефолт юниформа в шейдере (но можно и выставить при желании)
Если текстовая метка присутствует в мапах класса инстанса (там столько-же мапов, по одному на тип), то передает в шейдер значение из него, если нет, то из таблицы дефолта.
И, разумеется, текстовые метки опрашиваются в каждом кадре (что очень не есть хорошо). Нужно будет сделать какой-нить кэш для быстродоступа к нужным параметрам. Да подумать, как избавится от этих мапов, которые мне прям очень сильно не нравятся.
Но зато даже в таком виде оно работает.
Простенький примерчик:
Добавлена заготовка под MaterialInstance
Добавлена обработка ключевого слова input в парсере скрипта материала
Добавлена дополнительная проверка и автоматический выбор параметра max_concurent_taks в случае, если в конфиге параметр равен нулю
Добавлено исключение, в случае, если процессор поддерживает менее 4х потоков
Добавлен программный ограничитель кадров в графическом потоке
Изменена сортировка рендера с сортировки по геометрии на сортировку по шейдерам для уменьшения кол-ва переключения контекста шейдеров OpenGL
Исправлена ошибка при запуске RatTools приводящая к полному запуску движка
Исправлено редкое исключение при обработке очереди AsyncTask разными потоками из-за неучтенного состояния гонки при проверке на пустую очередь
Готовлю движок для внедрения инстансов материалов, чтобы максимально сократить кол-во переключений контекста шейдера (материал == шейдер). Возможно еще проведу оптимизацию по vao - собирая определенные меши в один длинный буфер (сейчас один буфер - один меш + лоды). Однако там есть нюанс с динамической выгрузкой сеток и пересчетом индексов и вообще там не все так очевидно, да и прирост по кадрам не то чтобы прямо большой. Я бы даже сказал не заметный. Т.ч. возможно это того и не стоит, т.к. функция glBindVertexArray всего-лишь перещёлкивает указатель на уже загруженный в GPU буфер. Подумаю, в общем, ибо сейчас это не горит.
Особый класс, который можно создать как вручную, так и загрузив через заранее подготовленный ассет. Содержит перечень переменных со значениями для передачи через uniform шейдера. Привязывается к Материалу(шейдеру) и используется как надстройка над материалом для ускорения процедуры отрисовки.
Добавлен дополнительный интерфейс IThread
Добавлен класс GameThread
RenderThread перенесен из реликта RenderCore в Core
Все семейство классов Thread вынесена из фреймворка RelictClass в обычные классы
Исправлена работа сборщика мусора при удалении объектов с владельцем в другом потоке
Исправлена работа сборщика мусора при закрытие движка
Исправлено завершение потоков семейства Thread в Linux
Мультипоточность отлажена на столько, на сколько это на данном этапе возможно. Движок работает стабильно в обоих целевых ОС. Правда кое-что пришлось таки переделать. В частности Потоки теперь не являются частью фреймворка RelictClass, теперь это самые обычные Сишные классы. Появился дополнительный класс потока GameThread, который по факту не является потоком, но абстракцией над основным потоком приложения. Соответственно изменены и метапараметры RelictClass. Теперь заместо класса потока передается указатель на объект потока. Это добавит в будущем немного сложности, если нам понадобятся пул воркеры, но на данном этапе это сильно упростило жизнь при синхронизации объектов.