# Slice Wrap — add-on Blender : surface propre à partir d'un maillage troué, wrap, nettoyage et analyse L'utilisateur parle **français** : répondre et documenter en français. Libellés d'interface Blender en anglais (convention Blender), descriptions / docstrings en français. Documentation en deux langues, à tenir à jour ensemble : `README.fr.md` en français, `README.md` en anglais (sa traduction) ; de même `CHANGELOG.fr.md` / `CHANGELOG.md` (les fiches du site et les notes de version les lisent dans les deux langues). ## But Transformer un maillage **troué, à doubles parois ou bruité** (scan, génération IA type Pixal3D / Trellis — ex. tête brute de 11,8 M faces) en une **surface fermée, propre et détaillée**, prête à sculpter ou à retopologiser, puis fournir une **analyse de forme** (densité de détail, tags, direction des plis). Né pendant le projet personnage « Chiara » (`C:\Users\a-mma\Desktop\CharacterDesign\Work3D`) : le Voxel Remesh de Blender donnait du moiré et des fuites sur la tête générée ; un script de remplissage voxel tranche par tranche a résolu le problème, d'où l'add-on. **Concept à préserver** : Slice Wrap = « maillage troué → surface propre + analyse ». Aucune logique de topologie / flow ici : la retopologie guidée est un projet séparé, **Slice Retopo** (`E:\0000WorkTechnique\0002dev\slice_retopo_addon`), qui lit les attributs produits par Slice Wrap. ## Pipeline (bouton « Slice Wrap » = étapes 1 → 3, + 4 si « Despike After ») 1. **Envelope** (`core.build_envelope`) — sur la source (jamais modifiée) : échantillonnage de surface (sommets + points sur les triangles > ½ voxel) → voxels occupés → fermeture morphologique (`close_iter`) → **remplissage 3D global ∪ remplissage 2D tranche par tranche selon X, Y, Z** (un trou ne fait fuir que les tranches qu'il traverse) → ouverture (`open_iter`, filaments) → surface en cubes → **Voxel Remesh de Blender** sur ce volume déjà plein (aucune fuite possible) → plus grande pièce → lissage de Taubin (`smooth_iter`). Numpy pur (pas de scipy / skimage dans le Python de Blender). 2. **Wrap Setup** — gonflement le long des normales (défaut 2 voxels) pour que l'enveloppe soit entièrement **au-dessus** de la peau, **Multires** (niveaux, Catmull-Clark) puis **Shrinkwrap** : *Project*, aucun axe (= le long des normales), **Negative seul**, Limit (défaut 4 × gonflement), Cull Off, Offset 0. 3. **Freeze** — copie évaluée → `multires_reshape` (la projection est figée DANS les niveaux du Multires : base légère + détails) ; **Repair Missed Rays** : chaque sommet est comparé avant / après projection ; resté sur place (< 0,3 × gonflement → aiguille) ou parti trop loin (> 2 × la moyenne de ses voisins → creux sur une paroi interne) = raté, reconstruit par diffusion depuis ses voisins réussis. 4. **Despike** (manuel ou en fin de chaîne) — ne corrige qu'un sommet **isolé** : écart à la moyenne des voisins > Distance (0 = longueur moyenne d'arête) ET > Isolation × l'écart moyen des voisins ; Strength, Iterations ; filtres par **groupes de sommets** (poids = intensité ; liste vide = toute la surface ; liste non vide mais aucun groupe trouvé = refus) ; **Protect Detail** (× (1 − détail)). 5. **Analyze** (optionnel, ne modifie pas la géométrie) — tenseur de covariance des normales sur `Neighborhood` anneaux (valeurs propres λ1 ≥ λ2 ≥ λ3) + courbure moyenne signée : `sw_detail` (λ2+λ3 normalisé), `sw_anisotropy` ((λ2−λ3)/(λ2+λ3)), `sw_curvature`, `sw_shape` (0 Flat, 1 Bulge, 2 Hollow, 3 Ridge, 4 Fold, 5 Saddle), `sw_flow` (vecteur propre de λ3 = direction du pli), couleurs `SW_Detail_Color` / `SW_Shape_Color`, groupes `SW_Detail`, `SW_Bulge`, `SW_Hollow`, `SW_Ridge`, `SW_Fold`, `SW_Saddle`. Écrit sur les N premiers sommets du maillage évalué = sommets de base. ## Décisions et pourquoi - **Pas de vrai modificateur** (impossible en Python) → opérateurs + paramètres mémorisés sur le résultat (`slice_wrap_source`, `slice_wrap_pitch`, `slice_wrap_inflate`) + **Regenerate** (recalcul sur place). - **Nom du résultat** = source + **Suffix** (défaut `_slicewrapped`), **numéroté .001, .002…** : aucun objet existant n'est jamais écrasé (avant la v1.3, relancer remplaçait le maillage existant — corrigé). Seul Regenerate recalcule l'objet actif. Refusé si l'enveloppe est déjà wrappée (Multires / Shrinkwrap). - **Collection** optionnelle (défaut cochée, `SliceWrapCollection`) : réutilisée si elle existe (contenu intact), sinon créée et liée à la scène ; décochée → collections de la source. - **Voxel Relative / Absolute — conservé (décision utilisateur, 2026-10-17)** : Relative (défaut 0,6 % de la plus grande dimension, ≈ 170 voxels) rend le réglage indépendant de l'échelle (têtes IA normalisées à ~1 m, tête réelle 23 cm, main C4D importée à 3,7 m) ; Absolute donne la **même densité physique à plusieurs parties d'un même personnage** (tête, mains, pieds à raccorder). L'équivalent absolu du mode Relative est affiché. Possible plus tard : ranger Absolute dans une option avancée repliée. - Défaut 0,6 % (et non 0,4 %) : une base trop dense fait « voir » le grain de la source à la projection. - Despike par **isolation** et non par seuil seul : le seuil seul attrapait 8 % des sommets (oreilles, paupières). - Réparation des ratés **au Freeze** (on connaît exactement les sommets ratés) plutôt que deviner après coup. - Couleurs suffixées `_Color` : groupes de sommets et attributs partagent le même espace de noms. - **Plus de réglage Target (décision utilisateur, 2026-10-17)** : il compliquait l'interface pour rien. Tout s'applique à l'objet actif **et sélectionné** (`_obj_mode_mesh`) ; Wrap Setup projette sur `slice_wrap_source`. - **Calculs longs = générateurs + opérateur modal** (`_LongOperator`) : l'API bpy n'est pas thread-safe, donc pas de thread. Les étapes (`step_*`, `core.build_envelope`, `despike`, `fix_missed_rays`, `analyze_shape`…) cèdent la main en produisant (fraction, texte) ; `core.sub` imbrique les progressions, `core.run` exécute d'une traite (scripts / tests, `bpy.ops` sans INVOKE). Depuis l'UI : confirmation (`invoke_props_dialog`, préférence `confirm_long`), puis timer 0,02 s, tranches de 0,15 s, saisie absorbée, Échap → `gen.close()` : chaque étape nettoie dans `except BaseException` / `finally` (aucun demi-résultat ; la scène n'est modifiée qu'à la fin). Progression : `workspace.status_text_set(fonction)` + boîte en haut du panneau. Les étapes lisent `bpy.context` à chaque usage (le contexte d'un opérateur n'est plus valide aux ticks suivants). Pas de `REGISTER` sur ces opérateurs (un redo relancerait un modal). Surcoût mesuré ~10 %. Appels Blender d'un seul tenant (Multires subdivide / Reshape, Voxel Remesh) : l'écran reste figé sur leur libellé. ## Fichiers - `__init__.py` : réglages (`SliceWrapSettings`), étapes (`step_envelope`, `step_wrap`, `step_freeze`, `step_despike`, `step_analyze`, `_reshape_from_evaluated`, `_result_collection`), opérateurs (`run`, `envelope`, `regenerate`, `wrap_setup`, `freeze`, `despike`, `analyze`, `show`, `group_add/remove/clear`), panneaux (principal, Steps replié, Despike, Analyze replié), liste `SLICEWRAP_UL_groups`. - `core.py` : voxels (`dilate`, `erode`, `_outside`, `fill`), maillage (`mesh_world_arrays`, `sample_surface`, `voxelize`, `blocky_mesh`), nettoyage (`taubin`, `keep_largest_island`, `despike`, `group_weights`, `fix_missed_rays`), analyse (`analyze_shape`, `write_analysis`), `unique_object_name`, `build_envelope`. - `tests/run_tests.py` : suite (sphère trouée bruitée ; `--head` = tête réelle + rendus). Exclu du paquet. - `blender_manifest.toml` : extension **5.1+** (décidé le 2026-10-20) ; `[build]` exclut `__pycache__/`, zips, `.a2m/`, `.claude/`, `.git/`, `.gitignore`, `CLAUDE.md`, `tests/`, `dist/`. - `.a2m/project.toml` : données du projet pour la chaîne d'outils a2m et le site (écrit par `a2m adopt`). - `CHANGELOG.md` (en) / `CHANGELOG.fr.md` (fr) : historique ; la section « Unreleased » / « Non publié » donne les notes de la prochaine release. ## Commandes - Tests : `"C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" -b -P tests/run_tests.py -- [--head]` → `RESULTAT : TOUT OK` (~1 min, 29 contrôles dont annulations) ; avec `--head`, regarder `slice_wrap_head_face.png` / `_cote.png`. **À lancer avant chaque release** (la chaîne a2m ne lance pas encore les tests de l'addon). - Construction et publication : chaîne d'outils **a2m** (repo `ange/apc-toolchain`, remplace les anciens `tools/Build-Package.ps1` et `tools/New-GiteaRelease.ps1`, retirés le 2026-10-20) : `a2m validate --load` (manifest validé et addon chargé dans Blender 5.1 et 5.2, profil temporaire), `a2m build` → `dist\slice_wrap-.zip`, `a2m release [patch|minor|major]` (version du manifest, CHANGELOG, commit, tag `v`, release Gitea avec le zip et `publication.json`), `a2m release --dev` (pré-release de test, réservée aux membres). Publication = action externe : ne la lancer qu'à la demande de l'utilisateur. - `.gitignore` : `__pycache__/`, `dist/`, `*.zip`, rendus de test. ## Historique Voir [CHANGELOG.fr.md](CHANGELOG.fr.md) (une entrée par version ; les changements à venir dans « Non publié »). ## Mesures de référence (Blender 5.2.1, tête Pixal3D brute 11,8 M faces) Enveloppe 70 k faces en 11 s ; chaîne complète ~1,5–2 min ; ~93 k ratés réparés au Freeze ; Despike filtré « Oreilles » 683 corrections vs 4 749 global ; Analyze 9 s (Flat 86 %, Ridge 5 %, Bulge 3 %, Fold 3 %, Hollow 2 %, Saddle 1 % — hélice des oreilles et lèvres en Ridge, paupières et commissures en Fold). ## Dépôt d'extensions Blender sur a2msystemes.org (idée du 2026-10-17, prise en charge par APC) But : les addons de l'utilisateur (Slice Wrap, Slice Retopo, suivants) installables et mis à jour via *Preferences > Get Extensions > Repositories > Add Remote Repository*, au lieu d'*Install from Disk*. Cette note est à l'origine du projet **APC** (*A2M Publication Contract*) : le dépôt n'est plus à écrire ici. - **Publication** : `a2m release` (chaîne d'outils `ange/apc-toolchain`) joint à chaque release Gitea le zip et un `publication.json` (contrat `ange/apc-spec`) ; le script de déploiement du site (`ange/site-a2msystemes-org`) en fabrique `blender-addons/index.json` et les pages du projet. Adresse du dépôt et pages : voir le site. - **À rappeler à l'utilisateur** : les addons déjà installés par *Install from Disk* (dépôt `user_default`) ne reçoivent pas les mises à jour → les désinstaller puis réinstaller une fois depuis le nouveau dépôt. ## Pistes - Option avancée repliée pour Absolute ; préréglages par type d'objet (tête, main, accessoire). - Accélérer le remplissage (propagation par lignes / scanline au lieu d'une dilatation voxel par voxel). - Surplombs (pavillon de l'oreille) : seconde projection *Nearest Surface Point* limitée à un groupe de sommets. - Remaillage adaptatif (octree + Dual Contouring) pour props / LOD / cible de bake (pas pour l'animation). - Retopologie guidée → projet **Slice Retopo** (marqueurs + retopo_tags + motifs ; voir son CLAUDE.md). ## Préférences de travail de l'utilisateur - « Ne fais rien, explique » = aucune modification ; valider le plan avant les gros lancements ; expliquer les paramètres (à quoi ils servent) avant de décider. - Ne pas casser le concept de base d'un add-on en ajoutant des fonctions : sous-panneaux optionnels. - Dans son Blender ouvert (MCP) : lecture seule d'abord, copie « au cas où », sauvegarder / restaurer la vue. - Calculs longs dans des fenêtres PowerShell externes ; vider la VRAM ComfyUI avant chaque génération (`~/.claude/CLAUDE.md`). ## Skills du projet (`.claude/skills/`) - `slice-wrap-dev` — faire évoluer, tester et livrer cet add-on. - `mesh-wrap-cleanup` — la méthode wrap et le nettoyage manifold (à la main ou avec l'add-on). - `blender-addon-testing` — tests en arrière-plan, rendus de contrôle, paquet d'extension, pièges de l'API. - `blender-live-mcp` — travailler dans le Blender ouvert de l'utilisateur sans rien casser. - `ai-3d-asset-pipeline` — génération 3D par IA (ComfyUI) qui produit les maillages sources.