LifePlay-Revival/Docs/Migration/13_Protocole_Coiffure.md
edujiro5972 2744242609 Protocole de conversion d'une coiffure (13_Protocole_Coiffure.md) et outils HairImportFbx, HairMaterials
Protocole rejoue de bout en bout sur Pocolov 17 : resultat identique.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:16:09 +02:00

179 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 13. Protocole de conversion d'une coiffure
Ce protocole décrit comment ajouter au jeu une coiffure livrée en **maillage statique** (FBX de Fab ou d'ailleurs),
sans modifier aucun Blueprint. Il a été établi sur *Pocolov Hair 17* (lot O7e, `11_Audit_Optimisation.md` §16.8) puis
rejoué de bout en bout avec les outils ci-dessous : résultat identique au millimètre.
Durée : environ 30 minutes pour une coiffure, contrôles en jeu compris.
## 1. Ce que le jeu attend d'une coiffure
| Exigence | Raison |
|---|---|
| `SkeletalMesh` dont les os portent les noms Genesis 8 (`hip`, `pelvis`… `neckUpper`, `head`) | `Person` fait suivre la coiffure au corps par `SetLeaderPoseComponent`, qui associe les os **par leur nom** |
| Placée autour de la tête de Bridget, dans la pose de référence | les sommets sont liés à l'os `head` ; une coiffure mal placée flotte ou traverse le crâne |
| Matériaux enfants de `/Game/Heavy/Daz/Bridget/Hairs/DazHair` | le jeu règle la couleur et l'épaisseur par les paramètres `HairColor` et `HairThickness` |
| Déclarée dans un fichier `Modules/<module>/**/*.lphair` | la liste des coiffures du jeu est construite depuis ces fichiers (lots H1, H2) ; un maillage non déclaré n'est jamais utilisé |
| Nom d'objet unique | les personnages désignent leur coiffure par ce nom (`HAIR Hairstyle: <nom>` dans les `.lpcharacter`) |
Coiffures **exclues** : les « grooms » MetaHuman (liés à la tête MetaHuman ; plugin `HairStrands` limité à l'éditeur
depuis O1). Une coiffure déjà riggée Genesis 8 (export Daz) n'a pas besoin des étapes 2 et 3 : l'importer en
`SkeletalMesh` et passer à l'étape 4.
## 2. Outils
| Outil | Rôle |
|---|---|
| `Tools/HairImportFbx.py` | import du FBX en maillages statiques séparés, dans un dossier de travail ; affiche tailles et emplacements de matériaux |
| commandlet `LPHairFromStaticMesh` (`Source/LifePlayEditorTools`) | ajuste la coiffure sur la tête de Bridget et la convertit en `SkeletalMesh` Genesis 8 |
| `Tools/HairMaterials.py` | importe les textures, crée les matériaux `<Nom>_Cap` et `<Nom>_Strands`, les affecte, contrôle les dépendances |
| `Tools/BuildCollections.py` | range la coiffure dans la collection `LifePlay_Cheveux` de l'éditeur |
| option de jeu `-LPVerifyHairstyles` | journalise la construction de la liste des coiffures |
Variables utilisées ci-dessous (PowerShell) :
```powershell
$UE = 'D:\Game\Launcher\Engine\UE_5.5\Engine\Binaries\Win64\UnrealEditor-Cmd.exe'
$P = 'D:\Game\LifePlay-master 5.5\LifePlay.uproject'
$T = 'D:/Game/LifePlay-master 5.5/Tools'
$W = 'D:/Game/LifePlay_Backup_5.5/<lot>/src' # sources de travail, chemins SANS espaces
```
## 3. Étapes
### Étape 0 : préparation
1. Vérifier la **licence** du produit (page Fab : « License terms »). CC BY impose une attribution ; noter auteur, titre,
lien.
2. Télécharger l'archive (accord de l'utilisateur), la copier dans `D:\Game\LifePlay_Backup_5.5\<lot>\`.
3. Extraire ; repérer le FBX et les textures. Copier dans `$W` sous des noms **sans espaces** (les arguments des
scripts Python sont séparés par des espaces) : `hair.fbx`, `diffuse.png`, `strands_opacity.jpg`…
4. Identifier les textures en les ouvrant :
- **couleur des mèches** : de préférence grise (elle est teintée par `HairColor`) ;
- **masque des mèches** : blanc = visible, noir = transparent, en bandes verticales ;
- **masque de la calotte** (lisière) : facultatif, voir étape 4.
5. Tag git `<lot>-avant`. Choisir le **nom** de la coiffure (unique, sans espace, ex. `Pocolov17`) et son dossier :
`/Game/Heavy/New5/Hairs/` (hors des dossiers à chemin fixe, `08_Guide_Developpeur.md` §2.1).
### Étape 1 : import
```powershell
& $UE $P -run=pythonscript "-script=$T/HairImportFbx.py fbx=$W/hair.fbx dest=/Game/Heavy/New5/Hairs/_Work" -unattended -nopause -nosplash
```
Lire les lignes `HAIRIMPORT` : repérer le **maillage de la coiffure** et la **tête de référence** souvent livrée avec
(ex. Pocolov : `Hair_17`, 8 250 triangles, emplacements `Hair_Base`, `Hair_01` ; `Head`, 21 262 triangles). Noter
quel emplacement est la **calotte** (ici `Hair_Base`). Sans tête de référence, voir §5.
### Étape 2 : ajustement et conversion
Essai à blanc d'abord :
```powershell
& $UE $P -run=LPHairFromStaticMesh '-Static=/Game/Heavy/New5/Hairs/_Work/Hair_17' '-FitHead=/Game/Heavy/New5/Hairs/_Work/Head' '-Out=/Game/Heavy/New5/Hairs/<Nom>' -DryRun -unattended -nopause -nosplash
```
Contrôler les lignes `LogLPHairFromStatic` :
| Ligne | Attendu |
|---|---|
| `Tete du corps` | Bridget : haut du crâne ≈ 15 × 20 cm |
| `Tete de reference` | haut du crâne du même ordre |
| `Ajustement : echelle` | entre 0,8 et 1,5 sur chaque axe ; un écart fort entre X et Y signale une tête de référence atypique |
| `Os 'head'` | `correction aucune` (squelette cible identique au corps) |
| `Coiffure placee` | largeur ≈ 25 à 32 cm (Flora : 31 cm), sommet ≈ 181-183 cm |
Puis sans `-DryRun`. La commandlet refuse d'écraser un asset existant : pour refaire, déplacer d'abord `<Nom>` et
`<Nom>_Skeleton` vers la sauvegarde.
Paramètres de retouche (après un premier contrôle en jeu) : `-OffsetZ=` (cm, monter/descendre), `-OffsetY=` (cm,
avancer/reculer), `-Scale=` (facteur global), `-Margin=` (défaut 1,05 : écart calotte/cuir chevelu), `-Cranium=` (défaut
0,3 : hauteur mesurée sous le sommet, en fraction de la profondeur de la tête), `-Uniform` (même échelle sur X et Y).
### Étape 3 : textures et matériaux
```powershell
& $UE $P -run=pythonscript "-script=$T/HairMaterials.py mesh=/Game/Heavy/New5/Hairs/<Nom> diffuse=$W/diffuse.png strands_opacity=$W/strands_opacity.jpg cap_opacity=white cap=Hair_Base thicken=1" -unattended -nopause -nosplash
```
- `cap=` : emplacements de la calotte (séparés par des virgules) ; tous les autres reçoivent le matériau des mèches.
- `cap_opacity=white` : calotte **opaque** (recommandé : une lisière découpée laisse voir le crâne entre les mèches) ;
sinon le fichier du masque de la calotte.
- `thicken=` : épaississement du masque des mèches. **1** pour un masque large (cartes de mèches, Pocolov) ; 10 pour un
masque de mèches fines (coiffures Daz). Une valeur trop forte donne des cartes opaques.
Contrôle : la dernière ligne `HAIRMAT dependances … -> OK` (la coiffure ne dépend que de son squelette et de ses deux
matériaux).
### Étape 4 : nettoyage
Déplacer `Content/Heavy/New5/Hairs/_Work` vers `D:\Game\LifePlay_Backup_5.5\<lot>\` (il ne doit pas être cuit dans le
jeu). Ne rien supprimer sans copie.
### Étape 5 : déclaration
Fichier `Content/Modules/<module>/Hairstyles/<nom>.lphair` (module existant, ex. `lp_Revival`, ou module du mod) :
```
// <Titre> - <auteur> - licence <licence>
// Source : <lien>
// Modifications : rattachee au squelette Genesis 8 (os head), ajustee a la tete de Bridget, materiaux DazHair.
HAIRSTYLE: /Game/Heavy/New5/Hairs/<Nom>.<Nom>
SEX: F
DAZ: true
```
Licence à attribution : ajouter la même mention dans `Licenses/Free_3D_Models_Credits.txt`.
### Étape 6 : collections, build, contrôle du journal
```powershell
& $UE $P -run=pythonscript "-script=$T/BuildCollections.py" -unattended -nopause -nosplash
```
Build Development (`09_Commandes_Utiles.md` §2) dans un **nouveau** dossier d'archive (la mise en place avec `-iterate`
ne retire pas les fichiers supprimés). Lancer le jeu ; le journal doit contenir :
```
LogLifePlay: Coiffures : <Nom> ajoutee (index N, F, module <module>)
```
### Étape 7 : contrôle en jeu (utilisateur)
| # | Contrôle | Défaut typique → correction |
|---|---|---|
| 1 | Création de personnage du bon sexe : la coiffure est en fin de liste | absente : chemin du `.lphair`, module désactivé, journal |
| 2 | **De face** : le crâne est couvert | zones chauves, coiffure étroite : vérifier l'ajustement (§4), `-Scale`, `-Margin` |
| 3 | **De profil** : rien ne traverse le crâne, l'oreille, les épaules ; pas de trou au-dessus de l'oreille | trous : `cap_opacity=white` ; trop haute/basse : `-OffsetZ` ; trop en avant/arrière : `-OffsetY` |
| 4 | Couleur et épaisseur réglables dans le menu | sans effet : matériau non `DazHair` |
| 5 | Mouvement (marche, animation) : la coiffure suit la tête | décalée : os `head` absent ou correction de pose non nulle |
| 6 | Nouvelle partie (liste des villes) et Continue | — |
Puis : entrée CHG dans `Journal_Modifications.md`, commit, tags `<lot>-apres` / `<lot>-valide`.
## 4. Pièges rencontrés (O7e)
| Piège | Effet | Règle |
|---|---|---|
| Ajuster sur la tête **entière** | la tête Pocolov a des oreilles très larges (24,4 cm) : coiffure rétrécie à 74 %, enfoncée dans le crâne | ajuster sur le **haut du crâne** (option `-Cranium`, par défaut) |
| `Thicken` des coiffures Daz (10) sur un masque large | mèches en cartes noires opaques | `thicken=1` pour les cartes de mèches |
| Lisière découpée de la calotte | crâne visible au-dessus de l'oreille | `cap_opacity=white` |
| Affectation des matériaux en Python | `save_loaded_asset` ne sauve que les assets « modifiés » ; une affectation par propriété ne les marque pas | sauvegarder avec `only_if_is_dirty=False` (fait par `HairMaterials.py`) |
| Matériaux importés du FBX | souvent sans texture reliée | ne pas importer les matériaux (`HairImportFbx.py`) ; recréer avec `HairMaterials.py` |
| Comparer des noms d'assets | `soldier` et `Soldier` désignent le même asset | comparaisons insensibles à la casse |
## 5. Cas particuliers
- **Pas de tête de référence** dans le FBX : utiliser la coiffure elle-même comme `-FitHead` (son haut est la calotte),
avec `-Margin=1.0`, puis corriger en jeu avec `-Scale` et `-OffsetZ`.
- **Coiffure masculine** : `SEX: M` dans le `.lphair` (le menu du personnage masculin la propose).
- **Morphs de forme** : non générés (la coiffure ne suit pas les morphs du visage). Un morph existant de la coiffure peut
être déclaré avec `FIT_MORPH: <morph> <valeur>`.
- **Mèches animées** : non gérées (coiffure rigide sur la tête).
- **Coiffure apportée par un mod sans recompiler le jeu** : impossible aujourd'hui (le maillage doit être cuit avec le
jeu) ; étape H3 prévue.
## 6. Retour arrière
Retirer le fichier `.lphair` suffit à retirer la coiffure du jeu. Pour retirer aussi les assets : déplacer
`Content/Heavy/New5/Hairs/<Nom>*` vers la sauvegarde, régénérer les collections, reconstruire.