Серия «Relict Engine»

6

Relict Engine: VBS/HS. Часть 1. Бэкенд

Серия Relict Engine

Все еще нарабатываю теорию по проблематике функционала.

Как я когда-то, еще в прошлом году, говорил, Relict Engine использует структуру сценических объектов, похожую на компонентную систему в Unreal Engine. т.е. эта структура представлена в виде нисходящего дерева, где каждая ветвь является частью сцены, наследуя трансформацию от родительской ветви. Иными словами, только ствол, или рут компонент имеет сразу трансформацию в мировом представлении. Все дочерние объекты будут пересчитывать свою трансформацию основываясь на матрице этого рутового объекта.

Задача бэкенда в контексте VBS/HS это хранение объектов в мировом пространстве VBS/HS. Иными словами, если мы захотим поставить звезду в координатах [ 2 световых года, 0, 0 ] относительно глобального центра координат, она там и должна быть. Без всяких но. И, если к этой звезде мы привяжем планету на расстоянии 8и световых минут от нее, то это так-же должно быть отражено в пространстве VBS/HS как есть. Даже, если в матрице трансформации звезды мы задали масштабирование. Иными словами мы должны всегда знать точную позицию того или иного объекта в пространстве VBS/HS, независимо от того, какие преобразования мы ему задали в родительском объекте.

Так-же абсолютно ясно, что хранить координаты таких объектов в "чистом" виде не выйдет из-за ограничений float и double (а long double с размерностью 128бит, пока еще не все компиляторы умеют). Тут можно подумать о комплексном представлении. Система Continius Calculation, упомянутая в прошлом посте (далее просто CC) сработает, однако, т.к. она держит числа в единицах с наименьшем битовым заполнением, для работы она будет постоянно эти хранимые числа перегонять в разные, удобные для расчета единицы. Иными словами - система надежная, но относительно медленная. Вчера довольно долго и обстоятельно общался с Gemeni на эту тему - по итогу (правда, я его сломал в конце) вектор для размышлений он дал довольно интересный. Он предложил разделить мир на кубы размером в 1Мм (мегаметр), а их в свою очередь на более мелкие кубы по 20километров каждый + локальное смещение. И объединить их в такую виртуальную сетку, где каждая координата будет состоять из 3х компонент вида [ Macro, Index, Offset ]. Система более внушительная и сложная для реализации, но для CPU с ней проще работать, а значит она будет быстрее.

оценка Gemeni касательно затрат на расчет с помощью обоих систем (Ваша Система - это CC)

оценка Gemeni касательно затрат на расчет с помощью обоих систем (Ваша Система - это CC)

Иными словами, если систему CC можно использовать, например в каких-то небольших проектах, то для движка это будет уже как стоп кран. Поэтому за основу мы возьмем систему с разбиением. CC, правда тоже не выбросим. Она пригодится для расчета линейных расстояний в более простом виде, т.к. система кубов эту проблему решить не может. И, по прикидкам, комбинация из этих двух систем даст нам на выходе сцену с ребром примерно равным 2000000000 (2 миллиарда) световых лет и с точностью позиционирования объектов на любом участке этой сцены вплоть до 1 миллиметра (неплохо, да?). Конечно такие размеры нам нафиг не сдались, а если говорить конкретно о Cold Fusion, то там будет задействован ничтожный кусочек этого диапазона меньше чем в 1 000 световых лет, но тут важен сам факт.

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

Показать полностью 1
6

Relict Engine: Очень Большие Сцены (VBS/HS)

Серия Relict Engine

Как я указал в прошлом посте, осталось реализовать последний источник света - а именно источник звездного (Солнечного, если хотите) света. Почему я упоминаю это, ну на самом деле, потому что эти две сущности довольно плотно связаны. Этот источник не может работать без VBS/HS и наоборот VBS/HS может работать ТОЛЬКО с таким или подобным ему источниками.

Почему так? Этот источник оперирует реальными параметрами звезды. Температура, радиус, расстояние до освещаемого объекта, кол-во энергии которое этому объекту передается. Большая часть этих параметров далеко выходят за точность float. А с double видеокарты до сих пор(!) работать на этапе отрисовки кадра нормально не могут и производительность проседает +- в 8 раз (и вряд ли это изменится в обозримом будущем). Поэтому, мы не можем просто сказать видеодрайверу, что, "эй, вот тут звезда с радиусом 6 9600 000 000 сантиметров, а объект на расстоянии 149 597 870 700 000 сантиметров от него. Иди рисуй свет" (утрированно), потому что это не сработает и в лучшем случае мы получим очень неопределенный результат. Поэтому, при создании больших пространств хитрят, и этот пост как раз о таких хитростях.

Когда-то уже давно, еще когда я работал с Unreal Engine, я уже затрагивал эту тему, например вот в этом посте. В Relict Engine я хочу пойти чуть дальше и создать из нее сценопостроитель прямо в движке, который будет на отрисовку выдавать объекты сразу в нужном виде и с нужными параметрами, чтобы избежать тех проблем, которые возникали с введением такой системы в UE (собственно это одна из целей, зачем движок и затевался).


Для начала немного теории.
Чтобы все это работало, сцену условно нужно разделить на две сущности.
Первая сущность, сцена мира, или угловая сцена, работает так, как я описывал в посте по Unreal Engine. Т.е. объекты гвоздями прибиты к некой орбите вокруг камеры, а их размер и позиция на этой орбите отвечают за относительное направление к этим объектам и видимый угловой размер. При этом их истинные позиции и размеры сохранены на стороне движка и все операции производятся именно с ними.
Вторая сущность, это уже классическая сцена xyz где и происходят основные действия, физика столкновений, итд. Геймплей в общем.
При этом разделение именно что условное. Сцена не будет прорисовываться дважды - в этом нет никакого практического смысла, т.к. и первой и второй сущностью по сути управляют одни и те-же правила. Меняется только перспектива.

В итоге у нас получается следующая структура:

Джордано Бруно передаем пламенный привет xD

Джордано Бруно передаем пламенный привет xD

Камера является центром мироздания (если так можно выразится), затем вокруг нее располагаются классическим образом актеры, источники света, эффекты и тдп. Затем на конкретном удалении звезды, планеты луны и другие крупные тела. И еще за ними скайбокс. Рисуется, впрочем, все в противоположном порядке, дабы избежать ошибок в z буфере, да и видеоадаптеру так проще считать. Можно заметить, что объекты на орбите в определенных позициях могут занимать одну точку, и можно подумать, что при определенных условиях, более мелкий или дальний объект может "проглядывать" через более ближний, но это не является проблемой. Все "проглядывания" одного объекта через другой скроет их движение (и выключенный Deph test) по этой орбите вокруг камеры и в готовом кадре будет выглядеть так, как будто объекты находятся на своих местах.


Теперь обратно к нашему источнику "Звездного света". По понятным причинам при таком построении сцены такой источник не может полагаться на честный закон обратных квадратов, т.к. значение, полученное в шейдере будет объективно неверным, а значит не верным будет и затухание. Считать параметр затухания, как и видимый угловой размер, и кол-во световой энергии, придется на стороне ++ движка и в шейдер передавать уже готовые параметры. И делать это нужно будет для каждого небесного тела (в прочем это можно сделать только один раз, или раз в N кадров, где N довольно большое число, если эти объекты должны двигаться), когда как для локальной сцены можно ограничится параметрами, рассчитанными для камеры, т.к. такая сцена в общем случае не должна будет превышать 5 км по полуоси, что относительно всей остальной сцены не существенно и может быть принято за точку.

Размерность в 5км берется из-за ограничений float. Т.е. итоговая сцена будет 10x10x10 км (от -5 до +5 по осям) из-за того, что точность дробной части после 5км (начиная с числа 524288, т.е. с 5км 242 метров, если принять 1 юнит за 1 сантиметр) начнет заметно искажаться из-за не хватки памяти в 4байтовом блоке (размер float 4 байта), а ошибка в вычислениях будет в районе ~0.06

таблица точности float

таблица точности float

Другая проблема, т.к. разделение сцен условно, то свет из классического пространства теоретически может "осветить" в том числе и объекты, расположенные на угловой сцене. Чтобы этого избежать, в материалах объектов должно быть жестко прописано, какой сцене будет принадлежать объект, использующий этот материал. Следовательно, нам нужно будет дописать это условие в компилятор материалов, чтобы он это учитывал и не давал использовать некорректные материалы на некорректных сценах.

Итак план на ближайшие дни:

  • Сценопостроитель с разделением сущностей сцен с разными правилами трансформации объектов

  • Дополнительные расчеты для хранения больших чисел (Continuous calculation)

  • Доработка парсера материалов

  • Правка Surface шейдера для правильного наложения света в новых реалиях

Вроде бы ничего не забыл.

Показать полностью 2
9

Relict Engine: DevLog 20260913

Серия Relict Engine

Краткий список изменений

  • Исправлено состояние "вечно грязной" камеры

  • Исправлено обновление графического состояния объекта в случае, если его движение вызвал родительский юнит сцены

  • Исправлено редкое состояния "моргания" точечного источника света при определенных углах камеры

  • Переделана отрисовка света со статичных слотов, на очередь по весу и расстоянию

  • Добавлены прожекторы

Комментарий

С основными источниками света закончили. Все унифицировано и работает по единым правилам. Как работает можно посмотреть на видео.

Прожекторов так-же в кадре может быть 16, как и точечных. Итого, на данный момент в кадре может быть 33 источника света.

Статичные слоты ушли в небытье, теперь при движении камеры источники света формируют массив, отсортированный по дистанции к камере, а так-же по весу (чем больше вес, тем более приоритетным считается источник)

Теперь самое интересное - свет, излучаемый звездой.

Показать полностью
7

Relict Engine: DevLog 20260911

Серия Relict Engine

Краткий список изменений

  • Добавлены в первом приближении считывание осей мыши

  • Добавлены точечные источники света

  • Обновлены внешние библиотеки до последних стабильных релизов

  • Исправлена ошибка получения ширины/высоты вьюпорта при работе движка в режиме "Развернутого окна"

Комментарий

Что касается клавиш и устройств ввода - буду переделывать, и возможно кастом кодом не оглядываясь на glfw, но чуть позже. Сейчас довольно топорно работают (а в wsl еще и не стабильно), но для теста света достаточно.

Точечные источники света успешно добавлены. Все как полагается: бликуют, смешиваются, затухают с расстоянием

На сцене может быть до 16и точечных источников света + направленный свет. Пока реализовано в виде статичных слотов. В дальнейшем переделаю на очередь. Кривая затухания пока так-же захардкожена на 3км и менять ее нельзя, т.к. пока не придумал в каком виде реализовать ее настройку (используется тройная презентация: const linear quadratic).

UPD: пардоньте, я дурак. Переделал на обратный квадрат дистанции. Стало лучше

2 ушло, 2 осталось. На очереди прожекторы.

Показать полностью 3
10

Relict Engine: DevLog 20260826

Серия Relict Engine

Краткий список изменений

  • Окончательно разведены потоки движка.

  • Исправлены последние редкие ctd при очистке мусора (наконец-то)

  • Добавлена обработка клавиш в первом приближении.

Комментарий

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

Система обработки клавиш на данный момент использует калбаки glfw с дополнительной оберткой в виде темплейтов биндов - для создания класса с привязкой к конфигу и системой делегатов для получения вызовов по по событию (на данный момент OnPress и OnRelease).

Выглядит это следующим образом:

Оглашается раскрытие темплейта и вызов его статичного метода для регистрации в системе обработки ввода.

Оглашается раскрытие темплейта и вызов его статичного метода для регистрации в системе обработки ввода.

Бинд привязывается к текстовой метке UserSettings конфига

клавиши пока в цифровом формате и без модификаторов

клавиши пока в цифровом формате и без модификаторов

А дальше, где-нибудь в коде на один (или сразу на все) делегаты вешается нужный метод

в данном случае по нажатию Escape будет вызван метод OnEscape экземпляра актера testActor

в данном случае по нажатию Escape будет вызван метод OnEscape экземпляра актера testActor

При этом в лог будет записано страшное, ибо я не придумал ничего умнее, чем связать бинд с конфигом через систему Property (т.е. сейчас каждый бинд это полновесный метакласс фреймворка):

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

Показать полностью 4
7

Relict Engine: DevLog 20260809

Серия Relict Engine

Краткий список изменений

  • Добавлен Направленный источник света (Directional Light Source)

  • Добавлена TBN (TangentBinormalNormal) матрица в структуру передачи Vertex->Fragment

  • Добавлен пересчет Нормалей 3д модели в Мировое пространство

  • Исправлены ошибки шейдерного домена Surface

  • Исправлена ошибка очистки генерации Выражений в коде материла

Комментарий

Отрисовка кубов с направленным источником света

Отрисовка кубов с направленным источником света

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

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

Так-же, собирая тестовый релизный билд обратил внимание, что в Linux бинарях пропал ctd при завершении потоков. Конечно, это не означает, что ошибка исправлена, ибо в конфигурации Дебага она никуда не делась. Но, по крайней мере, можно не торопится с ее исправлением, ибо не критично (главное потом не забыть, про нее xD)

Бонус: Проверил, как направленный источник света будет работать с картой нормалей

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

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

В движок обработку карт нормалей добавлять пока не буду - займусь этим, когда дойду до текстур. Будет это где-то после теней и систем частиц. Тогда-же, наверное, и паралакс сделаю.

Показать полностью 2
6

Relict Engine: DevLog 20260802

Серия Relict Engine

Краткий список изменений

  • Доделана поддержка сцен и сцены внедрены в пайплайн отрисовки.

  • Переделан MulticastDelegate на версию, которая не требует использования std::bind

  • Продолжаю разведение GameThread и RenderThread (по сути осталось только деревья Сборщика мусора растащить окончательно)

  • Добавлена первая заготовка под юниты света в виде DirectionalLight юнита.

  • Добавлена двойная буферизация для буфера команд RenderThread

Комментарий

Рано обрадовался, работы (не по движку) пока еще довольно много + духота по мозгам долбит. Ползу медленней, чем обычно, поэтому решил пока бросить приоритет на отладку и производительность того, что уже сделано, чем на добавление нового функционала.
Как всегда больше всего проблем вылезает в Linux сборке - ведро как-то более либерально ко всему относится (причем настолько, что я ему уже не доверяю). Есть проблемы с крэшами сборки из-за Сборщика мусора при удалении объектов из разных потоков (происходит из-за состояния гонки [Родитель приходит к состоянию очистки памяти раньше, чем дочерние, что не есть правильно]), и кроме того, как полностью разделить деревья и вынести триггеры сборщика в отдельные не связанные сущности решения похоже нет (При этом такое поведение наблюдатся исключительно в Linux; Windows как-то пофиг на это, что добавляет отдельно батхерта). Хотя, возможно надо было так изначально делать, т.к. из-за кросс потоковых деревьев приходится паузить треды на тике Сборщика. Если деревья будут разделены, то этого делать будет уже не нужно, а следовательно и производительность несколько увеличится (в прочем там могут другие проблемы вылезти).

Так-же наконец-то добрался до света и pbr. Базовый (очень базовый) шейдер уже написал, теперь нужно прописать логику для юниформов (std140, естно) и работой со светом через ++. Думаю, сначала поэкспериментирую на DirectionalLight (как самом простом варианте), потом добавлю уже остальные по готовому шаблону. Финальным аккордом по теме глобального света должна стать реализация объемного источника света (нужен для реализации физически корректного света от звезд)

Показать полностью
7

Relict Engine: DevLog 20260625

Серия Relict Engine

Краткий список изменений

  • триада WVP (World, View, Projection) так-же перенесены на DSA

  • Добавлена поддержка нескольких активных сцен (миров)

  • Добавлен класс камеры

  • исправлено неопределенное поведение при обновлении трансформации юнита сцены (синхронизация состояний трансформов в начале кадра)

Комментарий

В очередной раз отваливался по рабочим вопросам =/ Но, вроде, вернулся. Чендж лог сегодня очень небольшой по этой-же причине.

Итак, миры и камеры.

Мир определяется рут объектом GameWorld, который хранит все объекты сцены, камеры итд.
Камер у сцен может быть сколь угодно много, но активной одномоментно (во всем движке) может быть только одна (дальше будет сделано исключение для RenderTarget камер, но это отдельно). При этом, сцена без активной камеры продолжит свою работу в фоне. Она продолжит тикать, обновляется, пересчитывается. Просто не будет выводится на экран.

Переключение камер происходит функцией Activate соответствующего Юнита.

как пример, каждые 10 секунд мы переключаем активную камеру между первым и вторым акторами

как пример, каждые 10 секунд мы переключаем активную камеру между первым и вторым акторами

При этом, если камера принадлежит другой сцене, то сцена так-же переключится.

Показать полностью 1
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества