Décompression de l'ancien format de compression d'animation

image



Un jour, j'ai regardé diverses vidéos sur YouTube liées aux personnages du programme Vocaloid (pas tout à fait une description précise, mais à partir de maintenant, je l'appellerai simplement Vocaloid). Une de ces vidéos était le soi-disant PV du jeu Hatsune Miku: Project DIVA 2nd. À savoir, les relations de chanson de The Idolmaster, qui a été interprétée par les vocaloids Megurine Luka et Kagamine Rin. Les deux personnages sont de Crypton Future Media. Après avoir surfé sur le net, j'ai réalisé que personne n'était capable de convertir les animations de ce jeu? Mais pourquoi? À propos de cela sous la coupe.



Le jeu lui-même utilise le moteur Alchemy, qui a été développé par Intrinsic Graphics puis acheté par Vicarious Visions. Cela peut être vu dans les fichiers avec l'extension ".igb" (ci-après - IGB), ainsi que dans les lignes correspondantes. Les fichiers eux-mêmes sont binaires. En cherchant un peu sur Google, j'ai trouvé un script du camarade. minmode pour le programme Noesis bien connu dans certains cercles . Nous le lançons, avec le script jeté dans le dossier, essayons d'ouvrir le fichier d'animation et ... Nous obtenons la citrouille.



image



En tant que camarade. minmode dans son article sur DeviantArt, ce script ne peut pas lire les animations compressées par certains Enbaya. Sur Google Patents, je n'ai pu trouver que des produits similaires . Les brevets eux-mêmes ont déjà entre 19 et 20 ans, je suppose donc que l'algorithme de compression lui-même est également ancien. Et le site lui-mêmefait allusion à cela aussi (disponible uniquement via l'archive Web). Après avoir cherché un peu plus, j'ai réalisé que cet algorithme faisait partie d'un certain ProGATE de la société Enbaya. Mais cela ne nous donne rien.



Revenons à l'IGB. En réécrivant le code IGB que j'ai pu trouver, ainsi qu'en utilisant le script Noesis en C #, l'image a commencé à s'éclaircir.



Ci-dessous, je vais donner un tableau des éléments, car il était aligné dans les fichiers IGB de ce jeu (désolé d'être maladroit. Je ne peux pas faire autrement). Je ne donnerai que les éléments dont nous avons besoin



Clarification - * Liste - un tableau d'éléments *



igAnimationDatabase
--igSkeletonList
---igSkeleton - , , ,   
----igSkeletonBoneInfoList
-----igSkeletonBoneInfo -  
--igAnimationList
---igAnimation -  
----igAnimationBindingList
-----igAnimationBinding -   igSkeleton.      
----igAnimationTrackList
-----igAnimationTrack -   
------igEnbayaTransformSource
-------igEnbayaAnimationSource
--------igData -      Enbaya
igData -   ,     .


De cette façon, j'ai pu mettre la main sur les données brutes pour une étude plus approfondie. Avec l'aide de PPSSPP, Ghidra et un plugin pour cela, j'ai commencé à étudier le binaire du jeu. Je ne me souviens pas vraiment comment j'ai trouvé les fonctions nécessaires, mais je vais donner des fonctions spécifiques de EBOOT.BIN de ULJM05681 [ou NPJH50300] (dans ce cas, il s'agit du premier Project Diva 2nd, et non du second, la soi-disant Bargain Version ou Project Diva 2nd #) :



0x08A08050 - initialisation de la fonction de décompression basée sur l'en-tête de igData

0x08A0876C - demande de données à un moment précis (oui. Enbaya fonctionne avec le temps, pas les trames).



Le code lui-même est décompilé et publié sur GitLab . Il est écrit en C. Compile à la fois dans Visual Studio et gcc. Fonctionne à la fois en x86 et x64.



Je n'entrerai pas dans l'algorithme lui-même. Mon code vous dira mieux pour moi.



Mais en bref, Enbaya utilise un delta pour les données de déplacement et de quaternion. Il applique le delta en l'ajoutant / en le soustrayant simplement aux données précédentes / actuelles. La traduction reste telle quelle et le quaternion est normalisé pour une utilisation ultérieure. L'algorithme vous permet de remonter le temps sans recharger le fichier. De plus, il ne fonctionne pas avec une fréquence d'images, mais avec des échantillons par seconde. Pour ce faire, il stocke deux états en mémoire - l'échantillon précédent et le suivant, et le moteur lui-même interpole la valeur entre eux. Cependant, en raison du fait que nous avons des données dans le fichier partout sous forme entière, nous devons les diviser par quelque chose (plus précisément, multipliez-les, par exemple, par 0,0002) pour obtenir un nombre fractionnaire. Ce numéro est indiqué dans le titre. En raison de cette division (en fait la multiplication, mais pas l'essence), à ​​chaque addition et soustraction, la précision dérive un peu.



Et c'est tout. Pour être honnête, je me suis amusé à tout inverser. J'espère que mon travail n'a pas été vain.



PS En utilisant les données igSkeleton, nous pouvons déjà obtenir l'animation terminée et l'exporter, par exemple, vers Maya. Par la même Noesis.






All Articles