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 | une coiffure mal placée flotte ou traverse le crâne |
| Poids de peau répartis sur tête, cou, clavicules et poitrine | une coiffure longue liée à la seule tête tourne d'un bloc avec elle et ses mèches traversent épaules et poitrine |
| 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 |
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 |
| Liaison rigide à la tête (première version) | cheveux longs : les mèches tournent avec la tête et traversent épaules et poitrine (vidéo utilisateur) | transfert de poids depuis le corps et sortie de la peau (`-Skin=transfer`, défaut) |
.\Tools\HairPipeline.ps1 -Config Tools\hairs\<lot>.json -Step Inspect # puis relire <backup>\rapport_Inspect.txt
.\Tools\HairPipeline.ps1 -Config Tools\hairs\<lot>.json -Step Apply # [-Only <nom>] pour une seule coiffure
```
**Inspect** : extraction (zip, rar, 7z, archives imbriquées, avec 7-Zip), copie du FBX et des textures sous des noms
sans espaces, import (`HairImportFbx.py`), lecture des associations matériau → textures du FBX
(`Tools/FbxMaterialMap.py`, lecteur de FBX binaire sans SDK), puis détection des champs `auto` :
| Champ | Règle |
|---|---|
| `mesh` | plus gros maillage qui n'est pas la tête (nom quelconque : `Box001` pour Pocolov 03) |
| `head` | maillage dont le nom contient `head` ; sinon la coiffure elle-même (et `margin` 1,0) |
| `cap_slots` | emplacements nommés `base`, `cap` ou `scalp`, **seulement s'il reste un autre emplacement** pour les mèches |
| `diffuse` | parmi les textures nommées `hair` (si l'archive contient une tête complète : peau, yeux…) : non masque, grise de préférence, la plus grande |
| `strands_opacity` | masque (gris, noir/blanc) **vertical** (un masque carré est la lisière de la calotte) ; préférence au nom d'un emplacement des mèches, puis aux bords latéraux sombres (carte à bords transparents) ; emplacement unique : masque déclaré par le FBX |
Les champs détectés sont mémorisés dans `auto_fields` et recalculés à chaque inspection ; une valeur saisie à la main
n'est jamais écrasée. Le rapport liste chaque texture (taille, saturation, part noir/blanc, bas et bords sombres) et
les associations du FBX.
**Apply** : essai à blanc et contrôle des échelles (entre 0,6 et 1,8, sinon la coiffure est sautée), conversion,
matériaux (`HairMaterials.py` ; matériau de calotte créé seulement s'il sert), dossier de travail déplacé vers la
sauvegarde, `.lphair` avec attribution, ligne de crédits (sans doublon), collections, bilan. Une coiffure dont le
`SkeletalMesh` existe déjà est sautée : la chaîne peut être relancée après une interruption.
**Premier lot (HAIRS1, 2026-10-02)** : Pocolov Hair 03, 06, 11, 15, 16 (CC BY 4.0). Cas rencontrés et intégrés aux
règles : modèle dans un RAR (03) ; archive avec tête complète, textures de peau et d'yeux (03) ; maillage nommé
`Box001` (03) ; masque carré pris pour celui des mèches (16) ; emplacement unique (11) ; masques `A`/`A1` voisins (03,
15). Résultat : 5 coiffures conformes (dépendances limitées au squelette et aux matériaux), toutes ajoutées par le jeu.
**Licences** : seules les licences permettant la redistribution (CC BY, CC0) conviennent, l'archive des sources
publiée contenant `Content/Heavy`. La licence standard Fab (« personal/professional ») ne le permet pas.