Добавлена функция пересчета координат для дальних объектов
Переписан бэк кубокоординат
Комментарий
Джемени меня все-таки обманул (весь день сегодня (вернее уже вчера)) искал косяк в теории - нашел два (плюс один свой уже в реализации). Один в расчете этих самых кубокоординат; второй в подсчете дистанций между объектами по этим кубокоординатам (там же еще и я сам косякнул). Что вылилось в переписывание почти всей VBS/HS. Но за то теперь точно работает.
Доделана т.н. Far считалка для больших далеких объектов, который с локальной сцены перемещает объекты на 10км орбиту вокруг камеры с правильным скейлом. Ради этого вытащил весь этот комбайн поближе к GameWorld классу, т.к. оттуда удобнее получать доступ к камере. Получается, что теперь SceneUnit больше интерфейс к системе VBS/HS чем самостоятельная сущность, ну и для сохранения привычной древовидной структуры объектов, а сама магия плейсмента ушла почти целиком в GameWorld.
В общем, с CPU частью системы, думается мне, с горем пополам, можно сказать закончили. Ну может полернуть еще пару моментов. Теперь нужно править рендер, чтобы правильно эти объекты рисовал и приниматься наконец за объемный источник света. А вам на сравнение два сэмпла. Один с большим кубом, поставленным классическим образом (в 20км), а другой, с этим же кубом, но через метод пересчета для удаленных объектов (в 10км). В остальном (ну кроме ракурса) все полностью идентично.
А с нейронками надо завязывать. Пойду завтра (сегодня) советский учебник по тригонометрии заберу со второй квартиры. Он полезнее будет. Вот такие дела.
Исправлена инвертированная проверка света по дальности к камере
Исправлен Spin Lock основного цикла, связанный с программным ограничителем логических кадров (Fixed Timestep).
Удален расчет матрицы трансформации через расчет промежуточных относительных трансформов как устаревший и не нужный.
Добавлена сборка матрицы трансформации сразу в мировом пространстве. Математика расчета переделана на скалярные и векторные операции.
Добавлены кубические координаты в первом приближении.
Комментарий
Наработка теории по проблематике заняла чуть больше времени, чем ожидал. Итоговый конспект занял около 500 страниц в формате А4 (нарабатывался с помощью Gemeni), но это того стоило. Удалось все грамотно упаковать в памяти и по максимуму использовать кэши CPU. Таким образом пересчет координат в кубические фактически не заметен.
Теперь нужно переделать рендер, чтобы можно было рисовать объекты на орбите камеры. И дальше уже базой данных объектов заняться.
А пока, вот вам огромный кубик находящийся в 20км от камеры.
Это конечно еще не итоговый вариант. По сути оно даже не использует кубокоординаты еще. Но зато на этом примере можно посмотреть, как эти координаты рассчитываются. Ну и потом можно будет сравнить с этим видео как это будет работать.
PS: то что один из источников моргает на видео - это прожектор дотягивается до грани большого куба.
Из плохих новостей - у меня закончился отпуск. Как пойдет дальше - будет зависеть от загрузки на работе.
Все еще нарабатываю теорию по проблематике функционала.
Как я когда-то, еще в прошлом году, говорил, 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)
Иными словами, если систему CC можно использовать, например в каких-то небольших проектах, то для движка это будет уже как стоп кран. Поэтому за основу мы возьмем систему с разбиением. CC, правда тоже не выбросим. Она пригодится для расчета линейных расстояний в более простом виде, т.к. система кубов эту проблему решить не может. И, по прикидкам, комбинация из этих двух систем даст нам на выходе сцену с ребром примерно равным 2000000000 (2 миллиарда) световых лет и с точностью позиционирования объектов на любом участке этой сцены вплоть до 1 миллиметра (неплохо, да?). Конечно такие размеры нам нафиг не сдались, а если говорить конкретно о Cold Fusion, то там будет задействован ничтожный кусочек этого диапазона меньше чем в 1 000 световых лет, но тут важен сам факт.
Дополнительно потребуется еще некая база данных этих объектов для быстрого поиска и обращения к объектам. Но необходимый для нее функционал пока окончательно не определен, поэтому будет либо отдельный пост, либо в обычном DevLog опишу ее работу, когда она уже будет сделана. А пока, думаю и экспериментирую с впихиванием этих кубов в SceneUnit движка.
Как я указал в прошлом посте, осталось реализовать последний источник света - а именно источник звездного (Солнечного, если хотите) света. Почему я упоминаю это, ну на самом деле, потому что эти две сущности довольно плотно связаны. Этот источник не может работать без 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
Камера является центром мироздания (если так можно выразится), затем вокруг нее располагаются классическим образом актеры, источники света, эффекты и тдп. Затем на конкретном удалении звезды, планеты луны и другие крупные тела. И еще за ними скайбокс. Рисуется, впрочем, все в противоположном порядке, дабы избежать ошибок в z буфере, да и видеоадаптеру так проще считать. Можно заметить, что объекты на орбите в определенных позициях могут занимать одну точку, и можно подумать, что при определенных условиях, более мелкий или дальний объект может "проглядывать" через более ближний, но это не является проблемой. Все "проглядывания" одного объекта через другой скроет их движение (и выключенный Deph test) по этой орбите вокруг камеры и в готовом кадре будет выглядеть так, как будто объекты находятся на своих местах.
Теперь обратно к нашему источнику "Звездного света". По понятным причинам при таком построении сцены такой источник не может полагаться на честный закон обратных квадратов, т.к. значение, полученное в шейдере будет объективно неверным, а значит не верным будет и затухание. Считать параметр затухания, как и видимый угловой размер, и кол-во световой энергии, придется на стороне ++ движка и в шейдер передавать уже готовые параметры. И делать это нужно будет для каждого небесного тела (в прочем это можно сделать только один раз, или раз в N кадров, где N довольно большое число, если эти объекты должны двигаться), когда как для локальной сцены можно ограничится параметрами, рассчитанными для камеры, т.к. такая сцена в общем случае не должна будет превышать 5 км по полуоси, что относительно всей остальной сцены не существенно и может быть принято за точку.
Размерность в 5км берется из-за ограничений float. Т.е. итоговая сцена будет 10x10x10 км (от -5 до +5 по осям) из-за того, что точность дробной части после 5км (начиная с числа 524288, т.е. с 5км 242 метров, если принять 1 юнит за 1 сантиметр) начнет заметно искажаться из-за не хватки памяти в 4байтовом блоке (размер float 4 байта), а ошибка в вычислениях будет в районе ~0.06
таблица точности float
Другая проблема, т.к. разделение сцен условно, то свет из классического пространства теоретически может "осветить" в том числе и объекты, расположенные на угловой сцене. Чтобы этого избежать, в материалах объектов должно быть жестко прописано, какой сцене будет принадлежать объект, использующий этот материал. Следовательно, нам нужно будет дописать это условие в компилятор материалов, чтобы он это учитывал и не давал использовать некорректные материалы на некорректных сценах.
Итак план на ближайшие дни:
Сценопостроитель с разделением сущностей сцен с разными правилами трансформации объектов
Дополнительные расчеты для хранения больших чисел (Continuous calculation)
Доработка парсера материалов
Правка Surface шейдера для правильного наложения света в новых реалиях
Прожекторов так-же в кадре может быть 16, как и точечных. Итого, на данный момент в кадре может быть 33 источника света.
Статичные слоты ушли в небытье, теперь при движении камеры источники света формируют массив, отсортированный по дистанции к камере, а так-же по весу (чем больше вес, тем более приоритетным считается источник)
Теперь самое интересное - свет, излучаемый звездой.
Добавлены в первом приближении считывание осей мыши
Добавлены точечные источники света
Обновлены внешние библиотеки до последних стабильных релизов
Исправлена ошибка получения ширины/высоты вьюпорта при работе движка в режиме "Развернутого окна"
Комментарий
Что касается клавиш и устройств ввода - буду переделывать, и возможно кастом кодом не оглядываясь на glfw, но чуть позже. Сейчас довольно топорно работают (а в wsl еще и не стабильно), но для теста света достаточно.
Точечные источники света успешно добавлены. Все как полагается: бликуют, смешиваются, затухают с расстоянием
На сцене может быть до 16и точечных источников света + направленный свет. Пока реализовано в виде статичных слотов. В дальнейшем переделаю на очередь. Кривая затухания пока так-же захардкожена на 3км и менять ее нельзя, т.к. пока не придумал в каком виде реализовать ее настройку (используется тройная презентация: const linear quadratic).
UPD: пардоньте, я дурак. Переделал на обратный квадрат дистанции. Стало лучше
Исправлены последние редкие ctd при очистке мусора (наконец-то)
Добавлена обработка клавиш в первом приближении.
Комментарий
Все еще до конца не перешел из состояния "втупляю" в состояние "поперло", но через полторы недели отпуск, там разгонюсь.
Система обработки клавиш на данный момент использует калбаки glfw с дополнительной оберткой в виде темплейтов биндов - для создания класса с привязкой к конфигу и системой делегатов для получения вызовов по по событию (на данный момент OnPress и OnRelease).
Выглядит это следующим образом:
Оглашается раскрытие темплейта и вызов его статичного метода для регистрации в системе обработки ввода.
Бинд привязывается к текстовой метке UserSettings конфига
клавиши пока в цифровом формате и без модификаторов
А дальше, где-нибудь в коде на один (или сразу на все) делегаты вешается нужный метод
в данном случае по нажатию Escape будет вызван метод OnEscape экземпляра актера testActor
При этом в лог будет записано страшное, ибо я не придумал ничего умнее, чем связать бинд с конфигом через систему Property (т.е. сейчас каждый бинд это полновесный метакласс фреймворка):
Глубоко прорабатывать систему пока не буду - нет необходимости. Добавлю обработку для мыши, чтобы все таки можно было камерой гулять, и продолжу со светом.
Добавлен Направленный источник света (Directional Light Source)
Добавлена TBN (TangentBinormalNormal) матрица в структуру передачи Vertex->Fragment
Добавлен пересчет Нормалей 3д модели в Мировое пространство
Исправлены ошибки шейдерного домена Surface
Исправлена ошибка очистки генерации Выражений в коде материла
Комментарий
Отрисовка кубов с направленным источником света
Ну чтож, шейдер успешно внедрен, логика написана. Теперь нужно дописать оставшиеся юниты света и вплотную заняться объемным источником света для получения корректного света от звезд. После чего переключится на каст теней. Почему не сейчас? Потому что для теней нужно будет делать отдельный прогон шейдера в отдельный же буфер вывода (текстуру). Причем нужно будет реализовать несколько техник. Отдельно для планетарных и других крупных небесных объектов, и отдельно для мелочи, типо станций, кораблей, мелких обломков, итд.
Но перед этим всем, думаю, стоит наконец добавить код для чтения клавиш, чтобы камерой можно было гулять, ибо тестировать стало несколько не удобно.
Так-же, собирая тестовый релизный билд обратил внимание, что в Linux бинарях пропал ctd при завершении потоков. Конечно, это не означает, что ошибка исправлена, ибо в конфигурации Дебага она никуда не делась. Но, по крайней мере, можно не торопится с ее исправлением, ибо не критично (главное потом не забыть, про нее xD)
Бонус: Проверил, как направленный источник света будет работать с картой нормалей
это не движок, а внешний редактор шейдеров SHADERed, который я использую для предварительных тестов. Нормаль сгенерирована через Шум Перлина
В движок обработку карт нормалей добавлять пока не буду - займусь этим, когда дойду до текстур. Будет это где-то после теней и систем частиц. Тогда-же, наверное, и паралакс сделаю.