34 KiB
Fiche U7b-T2 — Niveau N3 — Modèle prévu lp-cart | utilisé claude-opus-5-5 — Agent lp-cart — Skills sk-protocol, lp-commandlets (préchargés aussi : ue-cpp-build, lp-paths)
U7b-T2 : portage de RetargetPack.py (étape 4 de la chaîne AP) à l'API Python de l'IK Retargeter UE 5.8
Date : 2026-10-09. Lecture seule : rien n'a été modifié, lancé ni commité. Ce livrable est le seul fichier écrit.
- Addon : worktree
D:\Game\LifePlay-Sandbox-5.8, brancheue5.8, HEADd1efdd1.git status --porcelainest vide. - Script :
Tools\anim\RetargetPack.py(463 lignes). Il est identique surlot/DC3-atelier, le checkout 5.5 :git -C D:/Game/LifePlay-Sandbox diff --stat HEAD ue5.8 -- Tools/anim/RetargetPack.pyne sort rien. - Moteurs :
UE_5.8(5.8.3, CL 58210709,Engine/Build/Build.version) etUE_5.5. Les sources IKRig et PythonScriptPlugin sont présentes dans les deux. - Abréviations :
K8/=D:\Game\Launcher\Engine\UE_5.8\Engine\Plugins\Animation\IKRig\Source\;K5/= idem sousUE_5.5;P8/=D:\Game\Launcher\Engine\UE_5.8\Engine\Plugins\Experimental\PythonScriptPlugin\Source\PythonScriptPlugin\Private\;RP=RetargetPack.py. - Niveaux de preuve : établi = lu à la source ou rejoué ; estimé = déduit ; incertain = non vérifié, avec l'essai qui tranche.
Résumé
- Il y a trois ruptures, pas deux. Les deux du report U5 sont confirmées. La troisième, absente du report, est la plus grave.
- R1 (établi, code) :
duplicate_and_retarget(..., True)(RP:396-397) lève uneTypeErroren 5.8.- Le 9e paramètre est désormais
TargetPath: FString(K8/IKRigEditor/Public/RetargetEditor/IKRetargetBatchOperation.h:206-218). - Un
boolPython n'est converti ni enstrni enName(P8/PyConversion.cpp:307-326) : l'appel échoue sur « Failed to convert parameter » (P8/PyWrapperObject.cpp:300-311). - La fonction est en plus dépréciée en 5.8 (h:196-205). La remplaçante est
run_batch_retarget(IKRetargetBatchOperationInputs)(h:116-177, 193-194 ; cpp:964-1010).
- Le 9e paramètre est désormais
- R2 (établi, code + essai U5) :
get/set_retarget_chain_settings(RP:279, 286) sont dépréciés depuis 5.6 (IKRetargeterController.h:758-766).- Ils n'agissent que sur
ChainSettings_DEPRECATED, vide sur un retargeter 5.8 (cpp:2593-2621). setrenvoie False (Saved\U5T3b\resultats_v3.txt:12). La voie qui marche passe par l'op « FK Chains » :get_op_controller(i).get_settings()/set_settings()(FKChainsOp.h:369-384, cpp:1222-1230).
- Ils n'agissent que sur
- R3 (établi, code ; nouveau) : en 5.8, un retargeter créé par
IKRetargetFactoryn'a aucune op (IKRetargetFactory.cpp:22-31; constructeurIKRetargeter.cpp:30-46).set_ik_rign'en crée pas non plus (IKRetargeterController.cpp:76-121).- Conséquence :
auto_map_chains(RP:274) ne fait rien, car il n'agit que sur le mappage de chaque op (cpp:908-939). Le réglage des chaînes n'a rien à modifier. - Effet estimé : clips figés en pose de retarget. Incertain : aucun avertissement n'existe dans le code pour une pile vide (recherche vide).
- Conséquence :
- Les RTG existants n'ont pas ce défaut. Leur pile de 6 ops a été construite au chargement par la conversion 5.5 → 5.8 (
IKRetargeter.cpp:261-473). Le dump après resave montre : Pelvis Motion, FK Chains, Stride Warp (désactivée), Speed Plant (sans chaîne), Run IK Rig, Pole Vector Alignment. - Correctif proposé (§ 5, diff non appliqué), en trois points :
- ajouter 3 ops (Pelvis Motion, FK Chains, Run IK Rig) juste après
set_ik_rig; - régler les chaînes par l'op FK Chains (
FKChainRotationMode) ; - remplacer l'appel par lot par
run_batch_retarget, avec les mêmes valeurs qu'en 5.5.
- ajouter 3 ops (Pelvis Motion, FK Chains, Run IK Rig) juste après
- Garde de version : pas nécessaire. Le checkout 5.5 garde sa propre copie du script (branche
lot/DC3-atelier). Le correctif ne va que surue5.8. Une variante par détection de fonctionnalité est donnée au § 6. - Le point le plus risqué : lancer le script non corrigé en 5.8 supprime les références avant d'échouer (§ 8, risque 1). Il remplace les IK/RTG par des RTG sans op, puis efface les clips cuits B_/M_ (RP:438), puis lève la
TypeError(RP:396). Ces dossiers sont ignorés par git. - Essai décisif (§ 7) : tout se joue en 5.8, sur une destination temporaire.
- Recréer les RTG avec le script corrigé, puis recibler les mêmes clips avec le RTG de référence et avec le nouveau.
- Critère : 0 valeur différente, bit pour bit, plus un témoin qui doit réagir.
1. Recherche web (avant la vérification locale)
Les pages ont été lues par curl et sont traitées comme des données. Toutes les valeurs ont ensuite été relues dans les sources installées.
- API
IKRetargetBatchOperation, à trois versions :- 5.6 :
duplicate_and_retarget(..., suffix='', include_referenced_assets=True), 9 paramètres. https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/IKRetargetBatchOperation?application_version=5.6 - 5.7 : ajoute
overwrite_existing_filesen 10e position ; le 9e reste le booléen, donc l'appel du script y marchait encore. https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/IKRetargetBatchOperation?application_version=5.7 - 5.8 :
(…, suffix='', target_path='', use_source_path=False, include_referenced_assets=True, overwrite_existing_files=False), marquée « deprecated: Use RunBatchRetarget instead », plusrun_batch_retarget(inputs). https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/IKRetargetBatchOperation?application_version=5.8
- 5.6 :
- Structure d'entrée : https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/IKRetargetBatchOperationInputs?application_version=5.8. Champs Python :
assets_to_retarget,source_mesh,target_mesh,ik_retarget_asset,override_set_names,search,replace,prefix,suffix,target_path,use_source_path,include_referenced_assets,overwrite_existing_files,retain_additive_flags.- La signature de la page affiche
include_referenced_assets=Falseetretain_additive_flags=False. Les défauts C++ valenttrue(h:167, 176). - Il faut donc tout régler explicitement (estimé : la page montre des défauts de type, pas ceux du constructeur).
- La signature de la page affiche
- Contrôleur et op FK, en 5.6 et en 5.8 :
- https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/IKRetargeterController?application_version=5.6 et
…=5.8:get_op_controller,get_index_of_op_by_name,add_retarget_op,add_default_ops,auto_map_chains(auto_map_type, force_remap, op_name='None').set_retarget_chain_settingsreste listé, sans mention de dépréciation côté Python. - https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/IKRetargetFKChainsController?application_version=5.8 :
get_settings()etset_settings(). - https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/RetargetFKChainSettings?application_version=5.8 :
target_chain_name,enable_fk,rotation_mode,rotation_alpha,translation_mode,translation_alpha. - https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/FKChainRotationMode?application_version=5.8 :
INTERPOLATED=0,ONE_TO_ONE=1, etc. - https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/RetargetRotationMode?application_version=5.8 : « NOTE: Replaced by FK Chain Op », fichier
IKRetargetDeprecated.h.
- https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/class/IKRetargeterController?application_version=5.6 et
- Notes de version 5.8 : https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-5-8-release-notes
- « Expose bRetainAdditiveFlags to RunBatchRetarget Blueprint/Python API ».
- « Blend to Source, Scale Goals, and Offset Goals are split out in the IK Op Stack ».
- Rien sur le 9e argument de
DuplicateAndRetarget. - Les pages de notes 5.6 et 5.7 et la page « retargeting scripting » sont générées en JavaScript :
curlne rapporte que la table des matières, contenu non lu.
2. Chaîne d'appel (pilote)
AnimPipeline.ps1étape 4Step-Conversion(l. 262-291) écritanim_retarget.json(mode bake,pose_dir = <Work>/pose), puis lanceBuildMod.ps1 -Retarget bake -RetargetOnly -RetargetConfigparcmd /c start /wait.- Il exige ensuite la ligne
RETARGET bridget n michael n, avec n = nombre de clips source (l. 286-290).
- Il exige ensuite la ligne
BuildMod.ps1Invoke-AnimToGenesis(l. 84-148) :- il copie la configuration vers
Saved\anim_retarget.jsonen ajoutant un jeton ; - il lance
UnrealEditor.exe "<projet>" -ExecutePythonScript="<addon>\Tools\anim\RetargetPack.py" -nosplash -unattended(l. 113) ; - il attend
RETARGET … jeton <j>ouRETARGET echec … jeton <j>(l. 73-77, 131-140).
- il copie la configuration vers
- Le seul consommateur de ces API dans l'addon est
RP. Commande :grep -rn "IKRetargeterController|IKRetargetBatchOperation|RetargetRotationMode|get_retarget_chain_settings"sur les.py/.cpp/.hdu worktree, horsContent→ 4 lignes, toutes dans RP (269, 279, 281, 396). Aucun autre script n'importe RP :LP_RETARGET_NOMAINn'apparaît qu'en RP:462.
3. Appel par appel (RP:ligne → état 5.8 → équivalent 5.8)
Recomptage : grep -o "unreal\.[A-Za-z_]*\(\.[A-Za-z_]*\)\?" Tools/anim/RetargetPack.py | sort | uniq -c → 37 symboles distincts, dont log_warning et log_error. grep -o "ctrl\.[a-z_]*" → 9 méthodes de contrôleur.
| RP:ligne | Appel | État 5.8 | Équivalent / preuve 5.8 (5.5 si utile) |
|---|---|---|---|
| 185 | factory.set_editor_property("edit_after_new", False) |
inchangé | UFactory::bEditAfterNew ; factories IKRigDefinitionFactory.cpp:23-33, IKRetargetFactory.cpp:15-31 |
| 190, 194, 202 | MathLibrary.subtract_vector_vector, normal, cross_vector_vector |
inchangé | Engine/Source/Runtime/Engine/Classes/Kismet/KismetMathLibrary.h:1381, 1703, 1441 (5.5 : 1384, 1702, 1444) |
| 206 | mesh.skeleton.get_reference_pose() |
inchangé | Engine/Source/Editor/AnimationBlueprintLibrary/Public/AnimPose.h:329 |
| 207, 345 | AnimPoseExtensions.get_bone_names, get_bone_pose |
inchangé | AnimPose.h:181, 193 |
| 328-337 | AnimPoseEvaluationOptions (should_retarget), get_anim_pose_at_time |
inchangé | AnimPose.h:62, 288 |
| 229, 270-273 | RetargetSourceOrTarget.SOURCE/TARGET |
inchangé | ERetargetSourceOrTarget, signatures du contrôleur h:76, 93 |
| 243, 265, 311, 370 / 244, 266, 312 | EditorAssetLibrary.does_asset_exist / delete_asset |
inchangé | …/EditorScriptingUtilities/Public/EditorAssetLibrary.h:70 / 144 |
| 259, 287 / 294 / 301 / 403 | save_loaded_asset / list_assets / find_asset_data / rename_asset |
inchangé | EditorAssetLibrary.h:262 / 328 / 62 / 206 |
| 249, 267 | AssetTools.create_asset(name, path, class, factory) |
inchangé (compatible) | Engine/Source/Developer/AssetTools/Public/IAssetTools.h:349 : paramètre optionnel bOverwriteExisting ajouté en fin |
| 251-255 | IKRigController.get_controller, set_skeletal_mesh, set_retarget_root, add_retarget_chain(chain, start, end, Name()) |
inchangé | K8/IKRigEditor/Public/RigEditor/IKRigController.h:56-57, 61-62, 349-350, 309-310. SetRetargetRoot porte DisplayName="SetPelvisBone", mais le nom Python vient de ScriptName (P8/PyGenUtil.cpp:3213-3216) et la doc 5.8 liste set_retarget_root : établi |
| 268 | create_asset(…, IKRetargeter, IKRetargetFactory) |
comportement changé (R3) | IKRetargetFactory.cpp:22-31 : NewObject seul, pile RetargetOps vide. Remplacer par add_retarget_op(type) ×3 (h:106-109, cpp:197-207, 780-835). OnAddedToStack lit alors les IK Rigs du retargeter (FKChainsOp.cpp:990-1000, PelvisMotionOp.cpp:137-149, RunIKRigOp.cpp:358-370) |
| 269 | IKRetargeterController.get_controller |
inchangé | h:70 |
| 270-271 | set_ik_rig |
signature inchangée | h:76, cpp:76-121 : ne met à jour que les mappages des ops déjà présentes, côté source seulement (l. 99-116). Les ops doivent être ajoutées après |
| 272-273 | set_preview_mesh |
inchangé | h:93 |
| 274 | auto_map_chains(EXACT, True) |
changé (sémantique, R3) | h:285-286 (op_name=None ajouté) ; cpp:908-939 : boucle sur les ops. Sans op, aucun effet. À appeler après l'ajout des ops |
| 236 | set_rotation_offset_for_retarget_pose_bone(bone, quat, TARGET) |
signature inchangée | h:413-414, cpp:1359-1379. Le tri hiérarchique se fait par le squelette du maillage de prévisualisation (5.5 : par le squelette de l'IK Rig, K5/…/IKRetargeterController.cpp:889-899). Effet sur la sortie : estimé nul ; ordre de sérialisation : incertain (essai § 7, md5 de TargetRetargetPoses) |
| 279 | get_retarget_chain_settings(chain) |
déprécié 5.6, inerte (R2) | h:758-761 ; cpp:2593-2604 renvoie FTargetChainSettings() par défaut. Remplacer par get_index_of_op_by_name("FK Chains") (h:153-154), get_op_controller(i) (h:209-210) et IKRetargetFKChainsController.get_settings() (K8/IKRig/Public/Retargeter/RetargetOps/FKChainsOp.h:377-378) |
| 280, 285 | propriété fk de TargetChainSettings |
déprécié | IKRetargetDeprecated.h (doc 5.8 : « Property 'FK' is deprecated ») → RetargetFKChainSettings (FKChainsOp.h:176-230) |
| 281 | RetargetRotationMode.INTERPOLATED / ONE_TO_ONE |
déprécié | K8/IKRig/Public/Retargeter/IKRetargetDeprecated.h:49 → FKChainRotationMode (FKChainsOp.h:164-174 : Interpolated=0, OneToOne=1), même valeur numérique (conversion IKRetargeter.cpp:342) |
| 283 | RetargetTranslationMode.NONE |
déprécié | IKRetargetDeprecated.h:38 → FKChainTranslationMode.NONE (FKChainsOp.h:153-162), défaut l. 219 |
| 284 | pole_vector_matching = 0.0 |
déprécié | Remplacé par l'op Pole Vector (AlignPoleVectorOp.h, bEnabled=false par défaut l. 73). 0,0 est le défaut 5.5 (K5/IKRig/Public/Retargeter/IKRetargetSettings.h:98), et la conversion ne crée aucune chaîne active à 0 (IKRetargeter.cpp:456) : pas d'op nécessaire |
| 286 | set_retarget_chain_settings(chain, settings) |
déprécié 5.6, sans effet (R2) | h:763-766 ; cpp:2606-2621 renvoie False. Remplacer par IKRetargetFKChainsController.set_settings(settings) (FKChainsOp.h:382-383, cpp:1227-1230 → CopySettingsAtRuntime cpp:787-800, recopie par nom de chaîne IKRetargetOpUtils.h:164-178) |
| 396-397 | IKRetargetBatchOperation.duplicate_and_retarget(clips, src, mesh, rtg, "", "", prefixe, "", True) |
déprécié 5.8 et cassé (R1) | 5.5 : 9e = bIncludeReferencedAssets (K5/IKRigEditor/Public/RetargetEditor/IKRetargetBatchOperation.h:129-139). 5.8 : 9e = TargetPath (h:206-218), meta DeprecatedFunction (h:197-205) ; échec de conversion bool → FString, voir § 4. Remplacer par run_batch_retarget(IKRetargetBatchOperationInputs) (h:193-194 ; struct h:116-177 ; cpp:964-1010) |
| 321, 407 | EditorLoadingAndSavingUtils.save_dirty_packages(True, True) |
inchangé | Engine/Source/Editor/UnrealEd/Public/FileHelpers.h:108 |
| 323, 455, 458 | SystemLibrary.quit_editor() |
inchangé | KismetSystemLibrary.h:656 (5.5 : 606) |
| 43, 224, 245…, 296, 342, 413 | Name, Quat, load_asset, AnimSequence, AnimPoseSpaces.WORLD, Paths.project_saved_dir |
estimé inchangé | non relus un par un (types et fonctions de base) |
Bilan (comptage manuel du tableau) :
- 4 appels rompus ou sans effet : RP:396, 286, 279, 274 ;
- 4 types ou propriétés dépréciés, tous dans le bloc RP:279-286 ;
- 2 comportements changés sans échec : RP:268 (retargeter sans op) et RP:236 (tri de la pose) ;
- 25 inchangés établis et 2 lignes de tableau « estimé inchangé ».
4. Détail des trois ruptures
R1, appel par lot (RP:396-397).
- Comportement en 5.8, établi par le code :
- avertissement
DeprecationWarning« Function 'duplicate_and_retarget' on 'IKRetargetBatchOperation' is deprecated » (P8/PyWrapperObject.cpp:288-296) ; - conversion de
TrueversFString: échec, seulsstretunreal.Namesont acceptés (P8/PyConversion.cpp:307-326,NATIVIZE_INLINE_PROPERTY(FStrProperty)l. 761) ; TypeError« Failed to convert parameter 'target_path' when calling function 'IKRetargetBatchOperation.DuplicateAndRetarget' on 'Default__IKRetargetBatchOperation' » (l. 309). Texte exact : estimé, car le nom de l'objet n'a pas été vérifié.
- avertissement
- Le script attrape l'exception et écrit
RETARGET echec : … jeton <j>(RP:456-459). BuildMod lève alors « Conversion en echec » (BuildMod.ps1:139). - Équivalence 5.5 → 5.8 des valeurs :
- 5.5 ne réglait pas le dossier :
FNameDuplicationRule::FolderPathvaut/Gamepar défaut (Engine/Source/Editor/UnrealEd/Public/EditorAnimUtils.h:27, identique en 5.5 et 5.8). Les copies naissaient donc sous/Game/<préfixe><clip>, puis RP:399-406 les déplaçait versout_dir. C'est pour cela quedelete_copiesvise aussi/Game/(RP:309). - 5.8 garde ce défaut si
target_pathest vide (cpp:985-988). - Les défauts de contexte sont identiques :
bRetainAdditiveFlags=true,bExportOnlyAnimatedBones=true(5.5 h:79-83 ; 5.8 h:82-86, struct h:176).
- 5.5 ne réglait pas le dossier :
R2, réglage des chaînes (RP:278-286).
- Avec un retargeter neuf,
getrenvoie le défaut (Interpolated) etsetrenvoie False, sans effet (essai U5,D:\Game\LifePlay-master 5.8\Saved\U5T3b\resultats_v3.txt:12-13). - La voie op FK est prouvée par les témoins U5 (l. 16-22) : Spine relu
ONE_TO_ONE, 930 valeurs sur 59 210 différentes, 8,91°. - Les 24 chaînes
OneToOnedu script seraient perdues : seules Spine et Neck sont vouluesInterpolated, le défaut (FKChainsOp.h:203).
R3, retargeter neuf sans op (RP:268-274).
- Établi : ni la factory, ni le constructeur, ni
set_ik_rign'ajoutent d'op.AddDefaultOpsn'est appelé que par l'UI :SRetargetAnimAssetsWindow.cpp:687etSRetargetOpStack.cpp:1106(grep sur les plugins 5.8). - Le flux d'Epic pour l'auto-retarget enchaîne
SetIKRig×2,RemoveAllOps,AddDefaultOps, puis le mappage exact (SRetargetAnimAssetsWindow.cpp:680-692). - Pourquoi ne pas reprendre
add_default_ops()tel quel :- il ajoute aussi Root Motion et Curve Remap (
IKRetargeterController.cpp:383-396), absents des RTG de référence (dump, § 7) ; - sans op de courbe, 5.8 garde toutes les courbes copiées à la duplication (
IKRetargetBatchOperation.cpp:593-614), comme 5.5 sans op Curve Remap (K5/…/IKRetargetBatchOperation.cpp:497-523) ; - Root Motion modifierait l'os racine (estimé).
- D'où la pile minimale : Pelvis Motion, FK Chains, Run IK Rig.
- il ajoute aussi Root Motion et Curve Remap (
- Les réglages de Pelvis Motion par défaut (
PelvisMotionOp.h:31-125) sont ceux de l'op convertie : tous les champs du dump sont égaux aux défauts. Ses os de bassin sont lus sur les IK Rigs (PelvisMotionOp.cpp:137-149) :pelvis→hipdans la référence. - Les 3 ops omises de la référence sont inertes (estimé) :
- Stride Warp
bEnabled=False; - Speed Plant sans chaîne ;
- Pole Vector avec
bEnabledpar chaîne à false par défaut (AlignPoleVectorOp.h:73).
- Stride Warp
- Chemins de type des ops (
AddRetargetOp(FString)=FindObject<UScriptStruct>(nullptr, path), cpp:197-206 ; exemple d'en-tête h:107 ; noms vus au dump) :/Script/IKRig.IKRetargetPelvisMotionOp,/Script/IKRig.IKRetargetFKChainsOp,/Script/IKRig.IKRetargetRunIKRigOp.
Référence lue : la pile des RTG convertis, par python -I D:\Game\LifePlay-master 5.8\Saved\U5T3b\scripts\ops.py <section> sur D:\Game\LifePlay-master 5.8\Saved\Logs\portage\U5_assets_apres.txt:1117300-1117315 (RTG_Bridget Quaternius) → ops: 6. Contenu :
- FK
ChainsToRetarget: 24OneToOne; Spine et Neck à défaut ; ChainMappingexact par nom (26 paires selon U5-T3b § 3.1) ;- Run IK Rig
Chains=vide ; - Pole Vector : entrées sans
bEnabled.
5. Correctif proposé (diff non appliqué, branche ue5.8, base d1efdd1)
Ordre imposé :
set_ik_rig×2 (les ops lisent les rigs à l'ajout) ;set_preview_mesh×2 (tri de la pose) ;- ops ;
auto_map_chains;- pose ;
- réglages FK.
Les lignes RETARGET … attendues par BuildMod et AnimPipeline ne changent pas.
--- a/Tools/anim/RetargetPack.py
+++ b/Tools/anim/RetargetPack.py
@@ -178,6 +178,12 @@
INTERPOLATED = ("Spine", "Neck")
+# UE 5.8 : un retargeter neuf n'a aucune op (IKRetargetFactory.cpp:30). Pile minimale equivalente a celle que la
+# conversion 5.5 -> 5.8 a donnee aux RTG existants (IKRetargeter.cpp:309-446) : Pelvis Motion, FK Chains, Run IK Rig.
+# Stride Warp (desactivee), Speed Plant (sans chaine) et Pole Vector (aucune chaine active) sont inertes : omises.
+RETARGET_OPS = ("/Script/IKRig.IKRetargetPelvisMotionOp",
+ "/Script/IKRig.IKRetargetFKChainsOp",
+ "/Script/IKRig.IKRetargetRunIKRigOp")
def make_factory(factory_class):
@@ -260,30 +266,57 @@
return rig, mesh, rig_chains
+def set_fk_chains(ctrl, name, source_chains):
+ # UE 5.6+ : les reglages de chaine vivent dans l'op FK Chains ; set_retarget_chain_settings est inerte en 5.8
+ # (IKRetargeterController.cpp:2606-2621). Spine et Neck : Interpolated (defaut) ; les autres : OneToOne ;
+ # translation None (defaut). pole_vector_matching 0 (defaut 5.5) = pas d'op Pole Vector.
+ index = ctrl.get_index_of_op_by_name("FK Chains")
+ fk_op = ctrl.get_op_controller(index) if index >= 0 else None
+ if fk_op is None:
+ raise RuntimeError("op FK Chains absente %s" % name)
+ wanted = {}
+ for chain_name, _, _ in source_chains:
+ wanted[chain_name] = (unreal.FKChainRotationMode.INTERPOLATED if chain_name in INTERPOLATED
+ else unreal.FKChainRotationMode.ONE_TO_ONE)
+ settings = fk_op.get_settings()
+ chains = list(settings.get_editor_property("chains_to_retarget"))
+ for chain in chains:
+ mode = wanted.get(str(chain.get_editor_property("target_chain_name")))
+ if mode is None:
+ continue
+ chain.set_editor_property("enable_fk", True)
+ chain.set_editor_property("rotation_mode", mode)
+ chain.set_editor_property("translation_mode", unreal.FKChainTranslationMode.NONE)
+ settings.set_editor_property("chains_to_retarget", chains)
+ fk_op.set_settings(settings)
+ read = {str(c.get_editor_property("target_chain_name")): c.get_editor_property("rotation_mode")
+ for c in fk_op.get_settings().get_editor_property("chains_to_retarget")}
+ wrong = sorted(n for n, m in wanted.items() if read.get(n) != m)
+ if wrong:
+ raise RuntimeError("reglage FK non applique %s : %s" % (name, ", ".join(wrong)))
+
+
def make_retargeter(name, source_rig, target_rig, source_mesh, target_mesh, body, source_chains):
asset_path = CFG["dest"] + "/" + name
if unreal.EditorAssetLibrary.does_asset_exist(asset_path):
unreal.EditorAssetLibrary.delete_asset(asset_path)
retargeter = unreal.AssetToolsHelpers.get_asset_tools().create_asset(
name, CFG["dest"], unreal.IKRetargeter, make_factory(unreal.IKRetargetFactory))
ctrl = unreal.IKRetargeterController.get_controller(retargeter)
ctrl.set_ik_rig(unreal.RetargetSourceOrTarget.SOURCE, source_rig)
ctrl.set_ik_rig(unreal.RetargetSourceOrTarget.TARGET, target_rig)
ctrl.set_preview_mesh(unreal.RetargetSourceOrTarget.SOURCE, source_mesh)
ctrl.set_preview_mesh(unreal.RetargetSourceOrTarget.TARGET, target_mesh)
+ # Un retargeter neuf n'a aucune op en 5.8 ; les ops lisent les IK Rigs a l'ajout (OnAddedToStack) :
+ # apres set_ik_rig, avant auto_map_chains (qui n'agit que sur le mappage des ops).
+ for op_type in RETARGET_OPS:
+ if ctrl.add_retarget_op(op_type) < 0:
+ raise RuntimeError("op impossible %s %s" % (name, op_type))
ctrl.auto_map_chains(unreal.AutoMapChainType.EXACT, True)
# Pose de retarget : la pose ajustee de la sandbox, et non plus l'alignement par le maillage,
# les reglages Daz et les demi-tours d'epaule (pole / roll180), qu'elle remplace.
apply_pose(ctrl, target_mesh, body)
- for chain_name, _, _ in source_chains:
- settings = ctrl.get_retarget_chain_settings(chain_name)
- fk = settings.get_editor_property("fk")
- mode = unreal.RetargetRotationMode.INTERPOLATED if chain_name in INTERPOLATED else unreal.RetargetRotationMode.ONE_TO_ONE
- fk.set_editor_property("rotation_mode", mode)
- fk.set_editor_property("translation_mode", unreal.RetargetTranslationMode.NONE)
- fk.set_editor_property("pole_vector_matching", 0.0)
- settings.set_editor_property("fk", fk)
- ctrl.set_retarget_chain_settings(chain_name, settings)
+ set_fk_chains(ctrl, name, source_chains)
unreal.EditorAssetLibrary.save_loaded_asset(retargeter)
return retargeter
@@ -392,7 +425,15 @@
def bake_named(clips, source_mesh, bodies):
# bodies : [(corps, maillage, retargeter)] ; renvoie (nombre de copies par corps, nombre deplaces).
+ # UE 5.8 : duplicate_and_retarget est deprecie et son 9e argument est devenu target_path (FString) :
+ # run_batch_retarget et sa structure. Memes valeurs qu'en 5.5 : copies dans /Game (target_path vide), puis deplacees.
made = []
for body, mesh, retargeter in bodies:
- made.append(unreal.IKRetargetBatchOperation.duplicate_and_retarget(
- clips, source_mesh, mesh, retargeter, "", "", body["prefixe"], "", True))
+ inputs = unreal.IKRetargetBatchOperationInputs()
+ for prop, value in (("assets_to_retarget", clips), ("source_mesh", source_mesh), ("target_mesh", mesh),
+ ("ik_retarget_asset", retargeter), ("search", ""), ("replace", ""),
+ ("prefix", body["prefixe"]), ("suffix", ""), ("target_path", ""),
+ ("use_source_path", False), ("include_referenced_assets", True),
+ ("overwrite_existing_files", False), ("retain_additive_flags", True)):
+ inputs.set_editor_property(prop, value)
+ made.append(unreal.IKRetargetBatchOperation.run_batch_retarget(inputs))
moved = 0
Notes sur le diff :
- Diff vérifié sur une copie du script hors projet (scratchpad de session) :
git apply --check -v p.diffpasse,git applyest appliqué, etast.parsedu résultat donne « syntaxe OK ». Après application, aucune occurrence deduplicate_and_retarget(ni deset_retarget_chain_settings(en code ; il ne reste que des commentaires. L'addon reste intact : md53c6491c6…,git status --porcelainà 0 ligne. - Comparer les valeurs d'enum Python (
read.get(n) != m) : estimé correct, l'essai U5 l. 17 relit<FKChainRotationMode.ONE_TO_ONE: 1>. get_op_controllerrenvoie l'objet de classe réelleIKRetargetFKChainsController: établi par l'essai U5, qui utilisaitget_settingsetset_settings.- Variante possible pour
target_path: passerCFG["out_dir"]pour écrire directement dansout_dir.bake_namedgère déjàpackage == dest(RP:403).- Cela s'écarte de 5.5 : la correction du chemin de réimport s'active quand le dossier n'est pas vide (5.8 cpp:180-…).
- À n'adopter qu'après l'essai.
6. Garde de version
- Pas nécessaire dans l'organisation actuelle.
- L'addon 5.5 =
D:\Game\LifePlay-Sandbox, branchelot/DC3-atelier; l'addon 5.8 = worktreeue5.8(git worktree list). - Chaque moteur exécute le script de son checkout. Le correctif ne se pose que sur
ue5.8.
- L'addon 5.5 =
- Elle le deviendrait si une seule copie devait servir les deux moteurs, par exemple en fusionnant
ue5.8dans la branche 5.5 avant le retrait de 5.5.- Le code 5.8 ne tourne pas en 5.5 : aucune op ni
FKChainsOpdansK5/(recherche vide), pas derun_batch_retargeten 5.5 (h:129-139), etAddRetargetOpy prend une classeURetargetOpBase(K5/…/IKRetargeterController.h:114). - Variante proposée, par détection de fonctionnalité plutôt que par numéro de version :
- Le code 5.8 ne tourne pas en 5.5 : aucune op ni
OP_STACK = hasattr(unreal, "IKRetargetFKChainsController") # pile d'ops : UE 5.6+
BATCH_INPUTS = hasattr(unreal.IKRetargetBatchOperation, "run_batch_retarget") # structure d'entree : UE 5.8
# make_retargeter : if OP_STACK -> ops + set_fk_chains ; else -> ancien bloc RP:278-286.
# bake_named : if BATCH_INPUTS -> run_batch_retarget ; else -> duplicate_and_retarget(..., True).
7. Essai décisif (à blanc, sous 5.8, références intactes)
Références, copie 5.8 D:\Game\LifePlay-master 5.8\Content\ ; toutes ignorées par git (U5-T1-CART l. 80) :
- méthode ue4 :
Quaternius\Retarget\{IK_Quaternius, IK_Bridget, IK_Michael, RTG_Bridget, RTG_Michael}.uasset; - méthode ue5 :
Retarget_ue5\{IK_Source_ue5, IK_Bridget_ue5, IK_Michael_ue5, RTG_Bridget_ue5, RTG_Michael_ue5}.uasset; - clips cuits en 5.5 :
Quaternius\UAL\B_*,M_*(43 + 43,ls | grep -c) etAnimPacks\FreeAnimationsPack\B_*,M_*(10 + 10) ; - originaux 5.5 d'avant le resave :
D:\Game\LifePlay_Backup_5.5\U5\Content\{Quaternius\Retarget, Retarget_ue5}; - poses :
Saved\Measurement\retarget_pose_{Bridget,Michael}.txt(ue4) etSaved\AnimPipeline\freeanims\pose\…(ue5). Les md5 sont identiques à la copie 5.5. - Banc de comparaison réutilisable :
D:\Game\LifePlay-master 5.8\Saved\U5T3b\scripts\U5T3b_func.py. Il contientretarget(en mémoire,run_batch_retarget),sample(toutes images, tous os, RAW, local) etcompare(égalité exacte des 10 composantes). Résultats de la base :resultats_v3.txt.
Étapes (éditeur fermé ; l'exécution relève d'une fiche IMPL ou VAL, pas de celle-ci) :
0. Instantané Snapshot.ps1 des dossiers de référence ci-dessus. Ils sont ignorés par git : sans instantané, aucun retour arrière.
- Appliquer le diff sur
ue5.8. - Rigs sous une destination temporaire, sans cuisson :
- commande :
BuildMod.ps1 -GameRoot "D:\Game\LifePlay-master 5.8" -Retarget rigs -RetargetOnly -RetargetConfig <json>; - JSON ue4 :
{"mode":"rigs","methode":"ue4","dest":"/Game/_TempU7b/Retarget"}; - JSON ue5 :
source_meshSKM_Manny,clips_dir/Game/FreeAnimationsPack/Animations,dest/Game/_TempU7b/Retarget_ue5,pose_dir= copie 5.8…/Saved/AnimPipeline/freeanims/pose. Le JSON existant defreeanimspointe vers la copie 5.5. - Attendu : la ligne
RETARGET rigs prets jeton <j>.
- commande :
- Structure :
LPDumpAssetssur les nouveaux RTG et les références, puisops.py.- Attendus :
TargetRetargetPosesau même md5 ; FKChainsToRetargetavec 24OneToOneaux mêmes noms ;ChainMappingidentique. - Seul écart admis : 3 ops au lieu de 6.
- Attendus :
- Sortie, par un commandlet
pythonscriptdérivé d'U5T3b_func.py: recibler en mémoire les mêmes clips avec le RTG de référence et avec le nouveau.- ue4 : UAL1_Standard → bridget_gp et michael, au moins Dance_Loop et 2 autres clips ; les 43 si le temps le permet.
- ue5 : SKM_Manny → bridget_gp et michael, au moins AS_AirKiss.
- Critère : 0 valeur différente sur chaque comparaison.
- Témoin obligatoire : Spine passée en
ONE_TO_ONEsur le nouveau RTG doit diverger. Référence U5 : 930 sur 59 210, 8,91°.
- Facultatif, informatif seulement : cuisson complète vers un
out_dirtemporaire (/Game/_TempU7b/UAL), puis comparaison avec les B_/M_ cuits en 5.5.- Ce n'est pas un critère du portage : cela mesure l'équivalence d'algorithme 5.5 → 5.8, restée incertaine (U5-T3b § 7, essai N4).
- Rangement :
/Game/_TempU7best déplacé versD:\Game\LifePlay_Backup_5.5\U7b\, jamais supprimé.
8. Risques
- Script non corrigé lancé en 5.8 : perte des références (établi par l'ordre du code RP:428-441).
make_rigetmake_retargetersuppriment puis recréent IK et RTG dansdest(RP:243-244, 265-266). On obtient des RTG sans op.delete_copiesefface ensuite les B_/M_ deout_diret de/Game(RP:438, 305-312), avant quebake_namedne lève laTypeError(RP:396).- Avec la configuration par défaut, cela touche
Quaternius/Retargetet 86 clips deQuaternius/UAL, dossiers ignorés par git. - Ne lancer ni AnimPipeline étape 4 ni
BuildMod -Retargetsurue5.8avant le correctif.
- Même corrigé, la configuration par défaut écrase les références : l'essai se fait sur une destination temporaire et après un instantané.
add_default_ops()est tentant mais ajoute Root Motion et Curve Remap, que la référence n'a pas. Effet sur la racine estimé non nul.- L'ordre d'appel compte : des ops ajoutées avant
set_ik_rig(TARGET)ne verraient pas la cible (cpp:99-116,OnAddedToStack), etauto_map_chainsappelé avant les ops ne fait rien. - Tri de la pose : 5.8 trie par le squelette du maillage de prévisualisation (
set_preview_meshreste avantapply_pose). Différence de sérialisation possible, à vérifier par le md5 de l'étape 3. - Valeurs par défaut de la structure d'entrée : la doc Python et le C++ divergent (§ 1). Le diff règle les 13 champs explicitement.
- Une recuisson complète en 5.8 peut ne pas égaler les clips cuits en 5.5, à cause de l'algorithme (incertain).
- Recuire les packs relève d'une décision de l'utilisateur : DeliverAnims, mods figés en V2.0.
- Après toute recuisson, la chaîne lance
LPAnimTwist(étape 4).
- Pas d'avertissement moteur pour un retargeter sans op.
set_fk_chainslève une erreur si l'op FK manque ou si un réglage n'est pas relu : l'échec devient visible (RETARGET echec). include_referenced_assets=Trueest repris de 5.5. Si un clip référence d'autres assets, le comptebridget ndépasse n et AnimPipeline échoue (l. 289). Comportement identique en 5.5.
9. Points d'appel à casser (pour la fiche IMPL)
RP:268-274: insérer l'ajout des 3 ops entreset_preview_meshetauto_map_chains.RP:278-286: remplacer le bloc déprécié parset_fk_chains.RP:396-397: remplacer parrun_batch_retarget.- Rien à changer dans
BuildMod.ps1niAnimPipeline.ps1: les formats de ligne sont conservés. - Documentation à mettre à jour après validation :
D:\Game\LifePlay-master 5.8\Docs\Migration\21_Sandbox_Addon.md:206(report U5), à compléter par R3.
10. Écarts, fichiers, état
- Écarts à la fiche :
- Recherche web faite par
curl, faute d'outil WebSearch ou WebFetch. Les pages de notes 5.6 et 5.7 n'ont pas été lues, faute de rendu JavaScript. - Rupture R3 ajoutée : hors du report U5, mais dans l'objectif de la fiche.
- Recherche web faite par
- Fichier écrit : ce livrable seul,
D:\Game\LifePlay-master 5.5\Docs\Migration\etat\U58\U7b\U7b-T2-CART.md. - Pages web téléchargées dans le dossier temporaire de session (scratchpad), hors projet.
- Aucun lancement d'éditeur ni de commandlet, aucun commit.