13 июля

Разжимаем древний формат сжатия анимаций

ПрограммированиеCРеверс-инжинирингКомпьютерная анимация
Из песочницы
image

В один день я просматривал различные видео на YouTube, связанные с персонажами программы Vocaloid (не совсем точное описание, но дальше буду называть просто вокалоидами). Одним из таких видео было так называемое PV из игры Hatsune Miku: Project DIVA 2nd. А именно песня relations из The Idolmaster, которую исполняли вокалоиды Megurine Luka и Kagamine Rin. Оба персонажа от Crypton Future Media. Порыскав по сети я понял, что никто так и не смог сконвертировать анимации из этой игры? Но почему? Об этом под катом.

Сама игра использует Alchemy Engine, который разработала Intrinsic Graphics, а позже купила Vicarious Visions. Это можно увидеть по файлам, имеющим расширение ".igb" (далее — IGB), а также соответствующим строкам в них. Сами файлы бинарные. Погуглив немного я нашёл скрипт от тов. minmode для известной в определённых кругах программы Noesis. Запускаем её, с перекинутым в папку скриптом, пытаемся открыть файл анимаций и… Получаем тыкву.

image

Как объяснил тов. minmode в своём посте на DeviantArt, этот скрипт не может прочитать анимацию, сжатую некоей Enbaya. В Google Patents я смог найти только подобное. Самим патентам уже лет 19-20, поэтому я и предполагаю, что сам алгоритм сжатия тоже древний. Да и сам сайт на это тоже намекает (доступен только через веб-архив). Поискав ещё немного я понял, что этот алгоритм был в составе некоего ProGATE от компании Enbaya. Но это ничего нам не даёт.

Вернёмся же к IGB. Переписав код для IGB, который я смог найти, а также воспользовавшись скриптом для Noesis, на C#, картина начала проясняться.

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

Уточнение — *List — массив из элементов *

igAnimationDatabase
--igSkeletonList
---igSkeleton - Скелет, который, возможно, будет использоваться нами
----igSkeletonBoneInfoList
-----igSkeletonBoneInfo - Нода скелета
--igAnimationList
---igAnimation - Наша анимация
----igAnimationBindingList
-----igAnimationBinding - Ссылается на igSkeleton. Служит для линковки скелета к анимации
----igAnimationTrackList
-----igAnimationTrack - Сам трек анимации
------igEnbayaTransformSource
-------igEnbayaAnimationSource
--------igData - Тут уже хранятся сырые данные Enbaya
igData - Нода с данными, которые уже не являются нодами.

Таким образом я смог достать сырые данные для дальнейшего изучения. С помощью PPSSPP, Ghidra и плагина для неё я начал изучать бинарник игры. Я уже не особо помню как именно нашёл нужные функции, но приведу конкретные функции из EBOOT.BIN из ULJM05681 [или NPJH50300] (в данном случае это первая Project Diva 2nd, а не вторая, так называемая Bargain Version или же Project Diva 2nd#):

0x08A08050 — инициализация функции декомпрессии на основе заголовка из igData
0x08A0876C — запрос данных по конкретному времени (да. Enbaya работает со временем, не кадрами).

Сам код декомпилирован и выложен на GitLab. Написан он на Си. Компилируется как в Visual Studio, так и в gcc. Работает как в x86, так и в x64.

Я не стану углубляться в сам алгоритм. За меня лучше расскажет мой код.

Но если кратко, то Enbaya использует дельту для данных о перемещении и кватернионах. Дельту оно применяет, просто прибавляя/отнимая её к/от предыдущим/текущих данных. Перемещение остаётся как есть, а кватернион нормализуется для дальнейшего использования. Алгоритм позволяет вернуться назад во времени, не перезагружая файл. При этом он оперирует не частотой кадров, а семплами в секунду. Для этого он в памяти хранит два состояния — предыдущий семпл и следующий, а движок сам интерполирует значение между ними. Однако в следствии того, что у нас данные в файле везде в целочисленном виде, мы должны их на что-то делить (точнее умножить. например на 0.0002), чтобы получить дробное число. Это число указывается в заголовке. Из-за этого деления (на самом деле умножения, но не суть) с каждым сложением и вычитанием точность немного уплывает.

А на этом всё. Честно говоря, мне было весело реверсить всё это. Надеюсь, что мои труды не прошли даром.

P.S. Используя данные igSkeleton мы уже можем получить готовую анимацию и экспортировать её, например в Maya. Через тот же Noesis.

Теги:анимацияигровые анимациискелетная анимацияalchemyanimationenbayaintrinsic alchemyvucarious visions
Хабы: Программирование C Реверс-инжиниринг Компьютерная анимация
+19
4,3k 24
Комментарии 6
Лучшие публикации за сутки