UMA в игровом движке Godot и часть PoC7

Загрузка ресурсов UMA

Это журнал разработки, чтобы узнать, смогу ли я перенести надстройку Универсальный многоцелевой аватар (UMA) для Unity на движок Godot. Вы можете найти Часть 6 здесь.

У меня было много разочарований с момента моего последнего обновления, потому что я забыл Первый закон программирования Дастина: «Ничто никогда не будет легким». Я проследил весь этот сумасшедший спагетти-код в дюжине исходных файлов, многие из которых содержали тысячи строк кода в одном файле. И что я нашел на дне тарелки? Проприетарные функции Unity, для которых у меня нет исходного кода и они даже не написаны на .NET, что означает, что я не могу легко их декомпилировать.

Я должен поддержать и объяснить, почему это так отстойно.

Компоновка активов UMA

Определение UMA хранится в нескольких файлах. Вверху есть «RaceData», который содержит только несколько фрагментов данных.
-Recipe: Название «Рецепта», с которого начинается UMA. Это указатель на другой файл.

Две самые важные вещи в файле рецепта — это ДНК UMA (как и какие части можно модифицировать) и слоты (части тела, из которых состоит UMA).

Слот UMA — это место, где мы фактически получаем визуальное определение UMA. Файл Slot вместе с данными костей фактически перечисляет вершины в Mesh для создания ноги, ступни, головы и т. д.

Все Обфускация!

Теперь вот проблемы, с которыми я столкнулся. Я уже несколько раз упоминал об очень тесной интеграции кода UMA с Unity Engine. Теперь эта тесная интеграция просочилась в формат этих файлов ресурсов.

Первая проблема заключается в том, что все описанные выше файлы находятся в файлах Unity .asset. Эти файлы активов имеют формат yaml. Ничего страшного, я всегда могу получить программу для чтения yaml на github. Проблема в том, что многие ресурсы не хранятся в текстовом формате, как в Recipe. Некоторые из них хранятся в двоичных файлах, созданных функциями Unity без исходного кода, о которых я упоминал в начале. И, похоже, не существует официального способа их декодирования, который можно было бы использовать в проекте с открытым исходным кодом.

Похоже, что все файлы определения RaceData находятся в этом двоичном формате, а это означает, что мне нужно как-то расшифровать двоичные файлы. В Unity есть инструмент binary2text, который я мог бы использовать для преобразования их по одному. Проблема в том, что это будет работать только для моего PoC. Это не решение для полного продукта. Я бы не ожидал, что люди будут запускать проприетарный инструмент командной строки с несколькими десятками файлов, которые они только что купили, прежде чем они смогут использовать доспехи. Это будет проблема, которую я решу на следующем этапе. Я нашел этот инструмент (с исходным кодом!) многообещающим.

Для этой вехи я просто хочу отрендерить кое-что! Поэтому я пропускаю данные о гонках и перехожу сразу к рецепту и слотам. Здесь я столкнулся с еще одним препятствием. В активах слота, даже если актив хранится в виде текста, а не в проприетарном двоичном формате, текстовые данные закодированы. Вместо того, чтобы просто перечислить значения с плавающей запятой всех вершин, он сохраняет их в длинном шестнадцатеричном потоке. Немного погуглив и поэкспериментировав, я смог расшифровать формат.

Получите это:
Первые 8 шестнадцатеричных символов представляют 1 число с плавающей запятой в векторе. Шестнадцатеричные символы должны быть разбиты на байты, а затем помещены в число с плавающей запятой. Но прежде чем сделать это, мы должны переставить кучу символов. Потому что хотя вершины читаются слева направо. Байты в шестнадцатеричном слове читаются справа налево. Это похоже на то, что вместо предложения «Тор бьет Халка» вы получаете «rohT stih kluH». Но подождите… это еще не все! Каждые два символа транспонируются, поэтому вы на самом деле читаете это как «orTh tshi lkHu». Я уверен, что есть кто-то со степенью магистра компьютерных наук, который уделял больше внимания в школе, чем я, и точно понимает, почему это так, но для меня…

Задача под рукой

На практике это означает, что при наличии такой шестнадцатеричной строки:
09a8d03d7bf7073e
я должен преобразовать ее в следующую:
3dd0a809 3e07f77b
И затем я могу преобразовать каждую в float value (в данном случае значения x и y первой вершины).

Итак, чтобы визуализировать всю UMA, мне нужно:
-1. сначала запустите двоичный файл в текстовый файл данных гонки
-2. Читать в тексте как ямл.
-3. Используйте yaml, чтобы узнать, какой базовый рецепт
-4. (возможно, расшифровать рецепт) и прочитать в файле базового рецепта в Yaml
-5. Из базового рецепта прочитайте «Строку рецепта» в формате JSON
-6. Используйте строку рецепта для поиска каждого из слотов
-7. Прочитать в каждом из Slot файлов как yaml
-8.Расшифровать вершины в шестнадцатеричном формате
-9.А потом, ТО! Я могу использовать массив вершин и визуализировать сетку.

Это то, что меня ждет в Milestone 3. Сейчас я просто собираюсь начать с файла слота и убедиться, что смогу отрендерить его в ArrayMesh (шаги 7–9).

Заглядывая еще дальше в будущее, мне также придется придумать новый способ найти активы UMA. Код зависит от того, что Unity хранит какой-то словарь для поиска всех ресурсов в проекте и таким образом ищет файлы. Так что это означает, что в какой-то момент мне придется написать какую-то функцию обнаружения чтения файлов, чтобы найти все различные активы UMA.

Вывод

Я разочарован тем, как мало существующего кода UMA я могу использовать повторно. Я начинаю корить себя за то, что потратил неделю на перенос кода. Возможно, это окупится в будущем Milestone, но сейчас кажется, что 90% этих усилий были напрасными.

При расшифровке всех этих файлов у меня был момент, когда я задавался вопросом, будут ли UMA в Godot практичными. К счастью, я нашел несколько инструментов, которые сделали этот вопрос мимолетным, но в то время это деморализовало.

Заглядывая вперед, предполагая, что Первый закон Дастина больше не утверждает себя, я думаю, что закончил придумывать материал для Milestone 2. Мне просто нужно закодировать его, чтобы доказать, что он работает так, как я думаю. Я с оптимизмом смотрю на то, что мое следующее обновление будет содержать изображение части тела UMA, отрендеренной в Godot.