Charge le plugin via AdditionalPluginDirectories, conserve ShowCouple et les commandlets anim côté jeu, et documente les lots S0–S8 (CHG-212 à CHG-220). Co-authored-by: Cursor <cursoragent@cursor.com>
17 KiB
20. Chaîne des animations : de l'achat du pack au mod livré (étude, 2026-10-06)
Objectif : qu'un pack d'animations, quel que soit son squelette d'origine, soit converti pour les corps du jeu (Genesis 8 : Bridget, Michael), évalué et livré en mod sans intervention manuelle, avec un contrôle bloquant à chaque étape. Base technique : la méthode validée dans la sandbox Mesure (CHG-188 à 204, mémoire « transfert de pose ») et le mécanisme des mods d'assets (16_H3_Mods_Paquets.md).
1. État actuel de la chaîne
| Question | Situation aujourd'hui | Source |
|---|---|---|
| Comment les animations entrent | Un seul pack, importé à la main : Tools/ImportQuaternius.py lit un .glb à un chemin fixe (D:/Game/Universal Animation Library[Standard]/…) et écrit dans /Game/Quaternius/UAL. Un second pack (Content/FreeAnimationsPack, mannequin UE5) est présent mais n'est pas traité. |
ImportQuaternius.py |
| Comment le modèle est identifié | Il ne l'est pas : la correspondance des os est écrite en dur deux fois, pour le seul couple « mannequin UE4 (Quaternius) → Genesis 8 » : en C++ (Links, TSegs, TransferMaps, DazToT dans LPPoseMeasure.cpp) et en Python (SOURCE_CHAINS, DAZ_CHAINS dans RetargetQuaternius.py). |
|
| Le pack contient-il un modèle de référence | Quaternius : oui, UAL1_Standard (maillage, squelette, repos en pose T). FreeAnimationsPack : oui, SKM_Manny / SKM_Quinn, plus un clip MM_T_Pose et son propre RTG_Mannequin. |
Content/Quaternius/UAL, Content/FreeAnimationsPack/Demo |
| Calques | Le calque de pose (CHG-203) est le squelette cible posé par la formule, à partir du squelette source du pack : il utilise déjà le modèle de référence du pack (son squelette au repos), pas un modèle à nous. | mode Mesure du plugin LPSandbox (LPSandboxMeasure*.cpp, ex-LPPairSandbox.cpp) |
| Conversion | Retargeter Unreal généré par RetargetQuaternius.py, pose de retarget lue dans Saved/Measurement/retarget_pose_<Corps>.txt (CHG-204). Écriture : entrée du mode Mesure (Tools/debug/LifePlay_measure_sandbox.bat, Saved/sandbox_mode.txt = Mesure) ou commandlet -run=LPAnimEval (-PoseDir = Saved/Measurement par défaut). Module de mesure : LPAnimMeasure dans l'addon LifePlay-Sandbox (plugin LPSandbox, lot S3). Les os Twist sont répartis après cuisson (-run=LPAnimTwist, AP3). |
RetargetQuaternius.py, 21_Sandbox_Addon.md |
| Évaluation | Interactive : tournée sandbox Mesure (Saved/Measurement/tour.csv, captures tour/, vignettes, planches ; CHG-202, AP6). Headless : -run=LPAnimEval (LifePlayEditorTools, dépend de LPAnimMeasure) — rapports sous Saved/AnimPipeline/<run>/ ; contrôles indépendants AP4 (controles_*.csv, rapport.json). |
CHG-206 à CHG-208, S6-VAL.md |
| Livraison | Les clips convertis sont dans le contenu du jeu (/Game/Quaternius/UAL/B_*, M_*), adressés par un chemin en dur (LPAnimRedirect::ClipPath). Ils ne passent pas par un mod. BuildMod.ps1 -Retarget ne vérifie que la présence d'une ligne de journal. |
LPAnimRedirect.cpp, BuildMod.ps1 |
| Appel depuis un scénario | Un scénario désigne une animation par une clé courte : ANIMATION: write (.lpaction), Actor.animate(martialart) (.lpscene). Le jeu lui associe les assets <clé>_F (corps féminin) et <clé>_M (corps masculin), par exemple Content/Heavy/New3/Anims/Daily/martialart_F / _M ; la même convention sert aux paires de couple (LPShowCoupleSubsystem). Les clips convertis, nommés B_<clip> / M_<clip>, ne sont donc pas appelables par un scénario. Le jeu résout la clé par Person::PlayDaily, qui cherche dans Room.Dailies (tableau fixe de clips, sans registre d'assets) ; les clips des mods y sont ajoutés par ULPModDailiesSubsystem (CHG-209). |
vin_Base/Actions, vin_Base/Scenes |
| Information pour le moddeur | Aucune : pour connaître la durée, la posture ou l'usage d'un clip, il faut l'ouvrir dans l'éditeur. |
Écarts à combler
- Pas d'identification du squelette : un pack Mixamo, UE5, CC4 ou Genesis 9 serait converti avec une table fausse.
- Correspondance dupliquée (C++ et Python) : une modification oubliée d'un côté fausse le résultat sans erreur.
La pose de retarget dépend d'une ouverture manuelle de la sandbox.Levé (AP2 / S6) :-run=LPAnimEvalécrit les mêmes fichiers sans fenêtre ; la sandbox reste utile pour le contrôle visuel.- Torsion des membres non répartie entre Bend et Twist (peau de l'avant-bras).
- Michael converti mais jamais mesuré.
- Livraison hors mod : impossible de distribuer un pack sans recuire le jeu.
- Aucun contrôle bloquant entre les étapes.
- Clips nommés hors de la convention
<clé>_F/<clé>_M: inutilisables depuis un scénario. - Aucun catalogue : un moddeur doit ouvrir chaque clip pour savoir ce qu'il fait.
2. Réponses de fond
Le modèle de référence du pack doit-il servir aux calques ? Oui, et c'est même nécessaire. Le calque est le
squelette cible posé par la transformation ; la transformation part de la pose T du squelette source. Chaque pack
apporte donc sa référence : son squelette au repos suffit (un USkeleton a toujours une pose de référence, même sans
maillage) ; son maillage ne sert qu'à l'affichage (touche M). Notre mannequin UAL1_Standard ne convient que pour les
packs au squelette mannequin UE4.
Condition : le repos du squelette source doit être une pose T connue. Un pack livré en pose A (comme Genesis) doit déclarer sa conversion A → T dans son profil (comme les réglages Daz). Un contrôle le vérifie (étape 3).
Conversion d'un modèle vers un autre : la méthode validée est générale :
- pose T commune, ajustée segment par segment (phase A) ;
- rotation de chaque os depuis la pose T, passée dans le repère du corps cible (phase B) ;
- chaînes de longueurs différentes réparties par interpolation (colonne, cou) ;
- torsion séparée entre os Bend et Twist ;
- report dans le retargeter Unreal (phase C), qui applique la même formule quand sa pose de retarget est la pose T ajustée (0,00 % d'écart sur 129 instants, CHG-204).
Seule la table de correspondance change d'un squelette à l'autre : elle devient une donnée (profil), plus du code.
3. Chaîne cible
Un pilote unique, Tools/AnimPipeline.ps1, sur le modèle de HairPipeline.ps1, appelé par
BuildMod.ps1 -Anim <pack>. Chaque étape écrit un rapport JSON dans Saved/AnimPipeline/<pack>/ et s'arrête au
premier contrôle en échec, avec la liste des causes. Une étape réussie n'est pas refaite (reprise par -From <étape>).
Rien n'est supprimé : un résultat précédent est déplacé dans precedent_<date>.
| # | Étape | Contenu | Contrôle bloquant |
|---|---|---|---|
| 0 | Inventaire | Pack déclaré dans AnimSources/<pack>/pack.json : origine, licence, fichiers (.fbx, .glb, ou dossier .uasset). |
Licence présente et compatible (règle existante de BuildMod pour les mods payants) ; fichiers trouvés ; empreintes SHA-256 consignées. |
| 1 | Import | Import automatisé (généralisation d'ImportQuaternius.py) dans /AnimSources/<pack>/. |
Nombre de clips importés = nombre attendu ; durée et cadence lues ; aucun clip vide ; un squelette unique. |
| 2 | Identification | Empreinte du squelette (noms d'os, hiérarchie) comparée aux profils Tools/anim/profiles/*.json : mannequin UE4, mannequin UE5, Mixamo, Genesis 8, Genesis 9, CC4… |
Un seul profil reconnu, avec au moins 95 % de ses os obligatoires présents ; sinon arrêt « squelette inconnu » et liste des os manquants. |
| 3 | Référence et pose T | Pose T source = repos du squelette (ou conversion déclarée par le profil) ; ajustement de la pose T de chaque corps cible (phase A, sans la sandbox : commandlet). | Repos source vérifié en T (bras à l'horizontale, jambes droites, tolérance fixée) ; après ajustement : tous les segments ≤ 1 %, réglages symétriques gauche / droite (écart ≤ 0,5°), aucun réglage hors bornes ; fichier retarget_pose_<Corps>.txt écrit. |
| 4 | Conversion | Rigs et retargeters générés depuis le profil (chaînes, Interpolated pour colonne et cou, doigts, orteils, bassin) ; cuisson des copies dans /<Mod>/Anims/<Corps>/. Puis répartition de la torsion Bend / Twist sur les clips produits (post-traitement). |
Autant de clips produits que de clips source, par corps ; durées et nombres d'images identiques ; aucune valeur non numérique. |
| 5 | Évaluation | Tournée sans intervention (fenêtre de jeu automatisée) sur chaque corps cible : écart à la formule, plus des contrôles indépendants (voir § 4). Planches de captures face / profil / dos et rapport HTML. | Chaque clip est classé « accepté », « à revoir » ou « rejeté » selon des seuils fixés ; un clip rejeté bloque la livraison sauf exclusion explicite dans pack.json. |
| 6 | Catalogue | Une fiche par animation (§ 5), calculée sur les clips produits et complétée par pack.json. |
Une fiche par clé et par clip ; clés uniques dans le mod et sans collision avec les clés du jeu ni des mods connus ; champs obligatoires remplis ; vignettes présentes. |
| 7 | Livraison | Mod d'assets (H3) : clips renommés à la convention du jeu, <clé>_F / <clé>_M, sous /<Mod>/Anims/… ; module texte .lpmod ; catalogue joint ; cuisson DLC, contrôle du conteneur et archive .zip (étapes existantes de BuildMod). La clé peut contenir _ (coupure au dernier _, CHG-209) ; outil : Tools\anim\DeliverAnims.ps1. |
Conteneur sans asset du jeu ; archive testée ; essai de chargement : jeu de test lancé avec le mod, chaque clé du catalogue appelée par animate() sur un personnage féminin et un masculin (journal). |
Le jeu résout les clés par Room.Dailies ; les clips des mods y sont ajoutés par ULPModDailiesSubsystem (CHG-209).
LPAnimRedirect ne sert plus qu'à la sandbox et au personnage piloté.
4. Évaluation : ce qui est mesuré
L'écart à la formule (0,00 % aujourd'hui) prouve que la conversion reproduit la transformation ; il ne prouve pas que le résultat est beau. Des contrôles indépendants s'ajoutent, tous calculés sur la pose et sans rendu :
| Contrôle | Défaut visé | Seuil « à revoir » (rejet : 3 × le seuil) |
|---|---|---|
| Écart à la formule (direction des segments, rotation du tronc) | conversion fausse | ≤ 1 % |
| Torsion locale des os Bend / Twist | peau de l'avant-bras ou de la cuisse vrillée | relevée ; bloquante sur option -SeuilTorsion |
| Main ou coude dans le volume du tronc (capsules) | « le bras passe à travers le corps » | pénétration ≤ 1 cm |
| Pied sous le sol, glissement au contact | jambes plus longues ou plus courtes que la source | sol ≤ 3 cm, glissement ≤ 3 cm/image |
| Limites articulaires (coude, genou) | hyperextension | genou ≤ 1 cm, flexion ≤ 5° |
| Continuité d'une image à l'autre | saut, tremblement | ≤ 10°, au-delà de 1,5 × la source + 2° |
| Symétrie des réglages de pose T | ajustement aberrant d'un côté | ≤ 0,5° |
Faute d'actif physique sur les corps, les capsules du tronc sont construites depuis la peau du maillage.
Les planches de captures restent la validation finale à l'œil, mais seulement pour les clips classés « à revoir ».
5. Catalogue des animations (livré avec le mod)
But : qu'un moddeur choisisse une animation et l'écrive dans un scénario sans ouvrir l'éditeur ni le jeu.
Formats :
Content/Modules/<Mod>/Animations/catalogue.json: pour les outils (lecture par script, éditeur de scénarios) ;Content/Modules/<Mod>/Animations/catalogue.html: pour le moddeur, une ligne par animation avec sa vignette, filtrable par posture, usage et durée ; lisible hors ligne ;Content/Modules/<Mod>/Animations/vignettes/<clé>.png: profil droit à 1/3 de la durée, mode vignettes de la tournée.
Fiche d'une animation : calculé = mesuré sur le clip produit, sans saisie ; déclaré = repris de pack.json
(ou déduit du nom, puis corrigeable).
| Champ | Exemple | Origine |
|---|---|---|
cle (identifiant) |
qua_walk_loop |
calculé : préfixe du pack + nom source normalisé ; unique et stable d'une version à l'autre |
appel |
Actor.animate(qua_walk_loop) / ANIMATION: qua_walk_loop |
calculé |
nom |
« Marche » / « Walk » | déclaré (nom source par défaut) |
assets |
/<Mod>/Anims/Female/qua_walk_loop_F, …/Male/qua_walk_loop_M |
calculé |
duree_s, images, cadence |
1,07 s, 32 images, 30 i/s | calculé |
taille_ko |
186 Ko (_F) + 190 Ko (_M), cuits |
calculé (après cuisson) |
boucle |
oui (première et dernière pose identiques à 1 % près) | calculé |
deplacement |
avance 1,2 m par cycle (1,1 m/s), sans root motion : le personnage marche sur place | calculé (trajet du bassin) |
posture |
debout / assis / accroupi / à genoux / allongé | calculé (hauteur du bassin et inclinaison du tronc) |
hauteur_assise_cm |
46 cm (pour placer un siège) | calculé, postures assises |
contacts |
pieds au sol ; mains libres / main droite occupée | calculé (hauteur des pieds, vitesse et position des mains) |
accessoire |
pistolet, épée, torche, volant | déclaré, proposé d'après le nom (Pistol, Sword, Torch, Driving) |
categorie |
locomotion, attente, conversation, combat, assis, interaction, sport, danse | déclaré, proposé d'après le nom |
style |
neutre, formel, détendu, agressif | déclaré |
usage |
« attente en conversation, debout » | déclaré |
corps |
féminin, masculin | calculé (clips produits) |
qualite |
accepté ; pire écart 0,00 % ; contrôles verts | calculé (étape 5) |
source, licence, credit |
Quaternius UAL, CC0 | déclaré (pack.json) |
version, empreinte |
version du mod, SHA-256 des clips | calculé |
Réalisation (AP6, CHG-210) : les champs calculés viennent de LPAnimCatalogCommandlet (-run=LPAnimCatalog, mesure image par image du clip féminin source, contrôle que F et M ont même durée et même nombre d'images) ; les champs déclarés viennent de AnimSources/quaternius/pack.json ; la qualité vient du rapport AP4 ; la taille, l'empreinte et les chemins viennent des fichiers livrés. Tools/anim/Catalogue.py assemble le tout. Définitions : boucle si la dernière image diffère de la première de 1 % de la taille ou moins (extrémités relatives à la hanche) ; déplacement : trajet horizontal de la hanche, « sur place » sous 5 cm ; posture par image (allongé : tronc > 60° ; à genoux : genou < 12 cm et hanche < 72 % ; assis : hanche < 72 % et plus de 20 cm en arrière des chevilles ; accroupi : hanche < 72 % ; debout sinon), posture du clip si elle couvre au moins 60 % des images, sinon « variable ». Les vignettes font 512 px, de profil. taille_ko est la taille des .uasset non cuits (taille_cuite: false) en attendant AP7. La posture peut être déclarée dans pack.json (champ posture), ce qui remplace la posture calculée. Planches (CHG-211) : chaque fiche porte aussi une planche JPEG de 256 px (12 images par seconde de clip, de 4 à 24, côte à côte) que la page fait défiler au survol de la vignette (au toucher : lance / arrête ; la planche n'est chargée qu'au premier survol) ; un GIF a été écarté (256 couleurs, lourd, aucun encodeur disponible).
Le catalogue est régénéré à chaque passage de la chaîne : il ne peut pas décrire un état antérieur des clips. Le pilote refuse de livrer un mod dont le catalogue n'a pas été produit dans le même passage.
6. Découpage en lots proposé
| Lot | Objet | Contrôle de sortie |
|---|---|---|
| AP1 ✔ | Profils de squelettes en JSON, lus par le C++ et le Python ; suppression des tables en dur | sandbox et retarget identiques à CHG-204 (tournée : 0,00 %) — fait, CHG-205 |
| AP2 ✔ | Commandlet de pose T et d'évaluation sans fenêtre (étapes 3 et 5, mesures) | mêmes fichiers de pose et même tour.csv que la sandbox — fait, CHG-206 (-run=LPAnimEval) |
| AP3 ✔ | Répartition de la torsion Bend / Twist sur les clips produits | contrôle de torsion vert, comparaison visuelle — fait, CHG-207 (-run=LPAnimTwist) ; comparaison visuelle à faire |
| AP4 ✔ | Contrôles indépendants (§ 4) et rapport HTML | seuils étalonnés sur les 43 clips — fait, CHG-208 (-run=LPAnimEval, Tools/anim/RapportControles.py) ; 0 rejeté, 8 clips à revoir (4 par corps : Death01, Fixing_Kneeling, Roll au sol, Jump_Start au saut) |
| AP5 ✔ | Livraison en mod : clips renommés <clé>_F / <clé>_M sous /<Mod>/Anims, ajout à Room.Dailies et correctif de Person::PlayDaily, essai de chargement par animate() |
jeu de test avec le mod Quaternius, clés appelées depuis un scénario d'essai — fait, CHG-209 ; essai empaqueté reporté (nouvelle version de référence nécessaire) |
| AP6 ✔ | Catalogue (§ 5) : fiches calculées, pack.json, vignettes, catalogue.json et catalogue.html |
une fiche par clip, champs calculés relus sur 5 clips témoins (marche, assis, pistolet, danse, chute) — fait, CHG-210 ; taille cuite en AP7 |
| AP7 | Pilote AnimPipeline.ps1 + BuildMod -Anim, identification, deuxième pack (FreeAnimationsPack, mannequin UE5) |
pack UE5 converti, évalué, catalogué et livré de bout en bout sans intervention |
Chaque lot suit 10_Protocole_Operations.md : instantané, journal CHG, retour arrière par Restore.ps1.