Files

141 lines
12 KiB
Markdown
Raw Permalink 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.
# 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 -- <dossier> [--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-<version>.zip`, `a2m release [patch|minor|major]` (version du manifest, CHANGELOG,
commit, tag `v<version>`, 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.