692 lines
26 KiB
Markdown
692 lines
26 KiB
Markdown
# Rapport technique — Avatar 3D pour Kazeia
|
||
## Face cloning, voice cloning, lip sync temps réel
|
||
### 2026-04-02
|
||
|
||
---
|
||
|
||
## 1. Vision
|
||
|
||
Kazeia est un compagnon de support émotionnel. L'avatar 3D donne un visage à ce compagnon :
|
||
|
||
- **Mode enfant** : personnage stylisé (ours en peluche, mascotte) avec expressions et lip sync
|
||
- **Mode ado/adulte** : visage humain photoréaliste reconstruit depuis une photo/vidéo de la personne ayant donné son consentement (thérapeute, proche, éducateur...)
|
||
|
||
L'avatar parle avec la voix clonée de cette même personne (voice cloning Qwen3-TTS), créant une expérience cohérente visage + voix.
|
||
|
||
---
|
||
|
||
## 2. Hardware cible
|
||
|
||
| Composant | Spec |
|
||
|-----------|------|
|
||
| Tablette | OnePlus Pad 3 (OPD2415) |
|
||
| SoC | Snapdragon 8 Elite (SM8750P) |
|
||
| Écran | 12.1", 2400×3392, 144Hz, HDR10/DolbyVision, 420 dpi |
|
||
| GPU | Adreno 830 — **100% libre** (ML sur NPU/Hexagon) |
|
||
| RAM | 12 GB (~8 GB disponibles après ML + OS) |
|
||
| NPU | Hexagon (HMX FP16 via ggml-hexagon + HTP via QNN SDK) |
|
||
|
||
Un visage affiché en gros plan sur cet écran fait **~2000×2000 pixels effectifs**. La barre de qualité est haute.
|
||
|
||
---
|
||
|
||
## 3. Répartition des ressources
|
||
|
||
```
|
||
Hexagon NPU (HMX FP16):
|
||
├── TTS Talker (27ms/step)
|
||
└── TTS Code Predictor (86ms/step)
|
||
|
||
Hexagon NPU (HTP via QNN):
|
||
├── TTS Decoder (3.5s, séquentiel après runners)
|
||
├── Whisper STT (~600ms)
|
||
└── LLM Qwen3-0.6B (93 tok/s)
|
||
|
||
CPU:
|
||
├── Sampling, IPC, embeddings (trivial)
|
||
├── Silero VAD
|
||
├── MediaPipe Face Mesh (capture, ~5ms)
|
||
└── OVRLipSync (~2ms)
|
||
|
||
GPU Adreno 830 (100% dédié avatar):
|
||
├── Rendu 3D avatar (50-80K vertices, <15% GPU)
|
||
├── Blendshape animation (52 shapes, 60fps)
|
||
├── PBR shading + subsurface scattering approximé
|
||
└── Marge : >80% GPU libre
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Protocole de capture — Séquence unique (~60 secondes)
|
||
|
||
### Principe
|
||
|
||
Une seule séquence de capture sert 3 objectifs :
|
||
1. **Preuve légale** de consentement (vidéo horodatée)
|
||
2. **Clonage vocal** (extraction x-vector depuis l'audio)
|
||
3. **Création avatar** (géométrie 3D, texture, calibration expressions)
|
||
|
||
### Phase 1 — Rotation guidée (20s)
|
||
|
||
L'utilisateur tourne lentement la tête, guidé par un overlay face tracking (MediaPipe Face Mesh, 468 landmarks).
|
||
|
||
```
|
||
Captures automatiques aux angles détectés :
|
||
|
||
④ ② ① ③ ⑤
|
||
60° gauche 30° G FACE 30° D 60° droite
|
||
```
|
||
|
||
- 5-7 photos **pleine résolution** (8-16 MP caméra frontale)
|
||
- Expression **neutre** demandée
|
||
- Pas de vidéo — photos nettes sans motion blur
|
||
- Face tracking valide l'angle et la netteté avant déclenchement
|
||
|
||
**Données extraites** : géométrie 3D (multi-view FLAME fitting), texture UV côtés
|
||
|
||
### Phase 2 — Vidéo de consentement (15s)
|
||
|
||
Texte affiché en mode prompteur. L'utilisateur lit face caméra :
|
||
|
||
> *"J'autorise l'application Kazeia à utiliser mon visage et ma voix, dans le cadre exclusif de cette application, pour créer mon avatar personnel."*
|
||
|
||
Formulation choisie pour :
|
||
- Durée ~6s (minimum pour x-vector fiable : 5s)
|
||
- Phonèmes variés (voyelles : a/o/i/u/e, consonnes : k/z/p/l/v/d/m)
|
||
- Clarté juridique (cadre exclusif, avatar personnel)
|
||
|
||
**Données extraites** :
|
||
- **Audio WAV 16kHz** → extraction x-vector (1024 floats) pour voice cloning Qwen3-TTS
|
||
- **Preuve légale** → vidéo horodatée, chiffrée, stockée sur l'appareil
|
||
- **Frames vidéo** (~450 frames à 30fps) → sélection automatique des meilleurs frames :
|
||
- Frame neutre → texture frontale haute résolution supplémentaire
|
||
- Frames bouche ouverte → calibration visèmes personnalisés
|
||
- Frames sourire naturel → calibration blendshape sourire
|
||
|
||
### Phase 3 — Expressions guidées (10s)
|
||
|
||
5 expressions demandées rapidement, toujours frontal :
|
||
|
||
| # | Expression | Ce qu'elle calibre |
|
||
|---|-----------|-------------------|
|
||
| 1 | Neutre | Référence de repos |
|
||
| 2 | Sourire (bouche fermée) | Commissures, joues, pommettes |
|
||
| 3 | Bouche ouverte ("ah") | Mâchoire, lèvres intérieures |
|
||
| 4 | Sourcils levés | Front, paupières supérieures |
|
||
| 5 | Yeux fermés | Paupières, cils |
|
||
|
||
**Données extraites** : blendshapes personnalisés (pas les génériques FLAME)
|
||
|
||
### Phase optionnelle — Gros plan iris (5s)
|
||
|
||
- Capture rapprochée d'un oeil
|
||
- Couleur et motif de l'iris pour des yeux réalistes
|
||
- Les yeux sont le premier point de focalisation du regard
|
||
|
||
### Conditions de capture
|
||
|
||
- **Éclairage** : diffus, face à une fenêtre, pas de soleil direct ni flash
|
||
- **Fond** : neutre (mur uni) pour faciliter la segmentation
|
||
- **Position** : stable, tablette posée ou tenue à bout de bras
|
||
- **Même lumière** pour toutes les phases (cohérence texture)
|
||
|
||
### UX guidée
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ │
|
||
│ ┌───────────────────────────┐ │
|
||
│ │ Caméra frontale │ │
|
||
│ │ │ │
|
||
│ │ Face tracking overlay │ │
|
||
│ │ + cible de pose │ │
|
||
│ │ ◎ ───► │ │
|
||
│ │ │ │
|
||
│ │ "Tournez la tête │ │
|
||
│ │ vers la droite" │ │
|
||
│ └───────────────────────────┘ │
|
||
│ │
|
||
│ ● ● ● ○ ○ ○ ○ ○ ○ ○ 3/10 │
|
||
│ │
|
||
│ [Recommencer cette étape] │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
MediaPipe Face Mesh détecte en temps réel :
|
||
- Angle de la tête (yaw/pitch/roll) → validation de pose
|
||
- Expression faciale → validation avant capture
|
||
- Netteté (variance du Laplacien) → rejet des frames floues
|
||
|
||
---
|
||
|
||
## 5. Pipeline de reconstruction 3D
|
||
|
||
### 5.1 Géométrie — FLAME multi-view fitting
|
||
|
||
```
|
||
5-7 photos angles + frames vidéo
|
||
│
|
||
▼
|
||
DECA / EMOCA (ResNet-50 backbone, ~25M params)
|
||
│
|
||
▼
|
||
Paramètres FLAME :
|
||
├── 300 shape params (identité : nez, mâchoire, pommettes...)
|
||
├── 50 expression params (blendshapes)
|
||
└── Pose (rotation tête)
|
||
│
|
||
▼
|
||
Mesh FLAME brut : ~5K vertices
|
||
│
|
||
▼
|
||
Subdivision Catmull-Clark (2 passes)
|
||
│
|
||
▼
|
||
Mesh final : ~80K vertices, topology régulière
|
||
```
|
||
|
||
- DECA inference : ~200ms sur GPU Adreno ou NPU (one-shot, une seule fois)
|
||
- Multi-view fitting améliore significativement vs single-image : profondeur du nez, mâchoire, pommettes
|
||
- La subdivision est offline (une fois) — ne rajoute pas de coût au rendu
|
||
|
||
### 5.2 Texture — Projection multi-vue + super-résolution
|
||
|
||
```
|
||
5-7 photos angles
|
||
│
|
||
▼
|
||
Projection UV par vue
|
||
(chaque pixel photo → coordonnée UV sur le mesh)
|
||
│
|
||
▼
|
||
Blending multi-vue (pondéré par angle de vue)
|
||
│
|
||
▼
|
||
Texture UV 2048×2048 (données directes ~90%)
|
||
│
|
||
▼
|
||
Inpainting zones manquantes (<10% : dessous menton, intérieur oreilles)
|
||
│
|
||
▼
|
||
Super-résolution (Real-ESRGAN ou équivalent)
|
||
│
|
||
▼
|
||
Texture finale 4096×4096
|
||
```
|
||
|
||
Cartes additionnelles pour le photoréalisme :
|
||
- **Normal map** : détail des pores (halluciné par ML depuis la texture diffuse, e.g. DECA detail map)
|
||
- **Roughness/specular map** : zones brillantes (nez, front) vs mates (joues)
|
||
- **Subsurface scattering** : paramètres peau génériques (difficile à capturer depuis tablette)
|
||
|
||
### 5.3 Blendshapes personnalisés
|
||
|
||
```
|
||
5 photos expressions + frames vidéo parole
|
||
│
|
||
▼
|
||
DECA/EMOCA par frame → 50 expression params
|
||
│
|
||
▼
|
||
Optimisation : ajuster les bases FLAME pour coller
|
||
au visage spécifique (sourire de cette personne,
|
||
pas le sourire "moyen" FLAME)
|
||
│
|
||
▼
|
||
52 blendshapes ARKit-compatibles personnalisés
|
||
```
|
||
|
||
Mapping FLAME → ARKit quasi 1:1 :
|
||
- `jawOpen`, `mouthClose`, `mouthFunnel`, `mouthPucker`, `mouthLeft/Right`
|
||
- `eyeBlinkLeft/Right`, `browDownLeft/Right`, `browInnerUp`
|
||
- `cheekPuff`, `cheekSquintLeft/Right`
|
||
- etc.
|
||
|
||
### 5.4 Yeux
|
||
|
||
- Iris : texture extraite du gros plan (ou frame vidéo haute-res)
|
||
- Sclera : blanc procédural avec veinules subtiles
|
||
- Cornée : reflet spéculaire procédural (point lumineux)
|
||
- Humidité : couche transparente réflective
|
||
- **Animation** : saccades oculaires aléatoires, suivi regard (optionnel)
|
||
|
||
### 5.5 Cheveux
|
||
|
||
Approche pragmatique pour la v1 :
|
||
- **Carte alpha** (billboard cards) suivant la forme détectée
|
||
- Pas de rendu strand-level (trop coûteux, pas nécessaire pour un cadrage visage)
|
||
- Couleur extraite de la photo
|
||
- Alternative : cadrage serré (front → menton) qui évite le problème
|
||
|
||
---
|
||
|
||
## 6. Rendu temps réel
|
||
|
||
### 6.1 Unity as a Library (UaaL)
|
||
|
||
Unity embarqué dans l'app Android native via UaaL :
|
||
- Export Android AAR depuis Unity
|
||
- `UnityPlayerActivity` lancée depuis l'app Kotlin
|
||
- Communication bidirectionnelle : `UnitySendMessage` (Java→C#) et `AndroidJavaObject` (C#→Java)
|
||
|
||
Contraintes :
|
||
- Unity exige sa propre Activity (pas un Fragment)
|
||
- Un seul player Unity actif à la fois
|
||
- Lifecycle : pause/resume coordonné avec les autres composants
|
||
|
||
### 6.2 Specs rendu
|
||
|
||
| Paramètre | Valeur |
|
||
|-----------|--------|
|
||
| Mesh | 50-80K vertices, topology quad subdivisée |
|
||
| Texture diffuse | 4096×4096 |
|
||
| Normal map | 2048×2048 (détail pores) |
|
||
| Roughness map | 1024×1024 |
|
||
| Blendshapes | 52 (ARKit-compatible) |
|
||
| Shading | PBR + subsurface scattering approx. (skin shader) |
|
||
| Target framerate | 60fps (stabilité thermique pour sessions longues de 15-30 min) |
|
||
| Résolution rendu | Natif 2400×3392 ou 80% avec upscale |
|
||
| Antialiasing | MSAA 4x ou TAA |
|
||
| Éclairage | 1 directionnelle + 1 ambient + IBL (image-based lighting) |
|
||
|
||
Budget GPU estimé : <15% de l'Adreno 830 pour un seul personnage.
|
||
|
||
### 6.3 Style visuel
|
||
|
||
**Approche photoréaliste en premier**, fallback semi-stylisé si qualité insuffisante :
|
||
|
||
Pour le photoréalisme :
|
||
- Skin shader avec subsurface scattering (pre-integrated SSS ou screen-space SSS)
|
||
- Normal map pore-level
|
||
- Specular lobe dual (peau grasse vs sèche)
|
||
- Eye shader avec refraction cornée
|
||
- Anti-aliasing agressif (les bords du visage à 3392px montrent tout)
|
||
|
||
Si le résultat tombe dans l'uncanny valley :
|
||
- Passer en semi-stylisé (peau lissée, yeux légèrement agrandis, shader toon subtil)
|
||
- Réduit les exigences de texture et de normal map
|
||
- Plus chaleureux pour du support émotionnel
|
||
|
||
---
|
||
|
||
## 7. Lip sync
|
||
|
||
### 7.1 Pipeline
|
||
|
||
```
|
||
TTS Qwen3-TTS → Audio PCM 24kHz
|
||
│
|
||
▼
|
||
OVRLipSync (Meta, Android NDK)
|
||
ou uLipSync (Unity, plus léger)
|
||
│
|
||
▼
|
||
15 visèmes Oculus → mapping vers 52 blendshapes ARKit
|
||
│
|
||
▼
|
||
Interpolation cubique Hermite (pas linéaire)
|
||
│
|
||
▼
|
||
Coarticulation (lookahead 2-3 frames)
|
||
│
|
||
▼
|
||
Blendshape weights à 60fps → SkinnedMeshRenderer Unity
|
||
```
|
||
|
||
### 7.2 Qualité lip sync sur grand écran
|
||
|
||
Les lèvres font ~300px de large à plein écran. Exigences :
|
||
|
||
- **52 blendshapes ARKit** (pas seulement 15 visèmes) — lèvres supérieure/inférieure/gauche/droite indépendantes
|
||
- **60fps** de mise à jour des poids (pas 30 — les transitions sont visibles sur 144Hz)
|
||
- **Interpolation cubique Hermite** entre keyframes — le linéaire donne un effet robotique
|
||
- **Coarticulation** : le shape de la bouche pour "ba" dépend de la voyelle suivante. 2-3 frames de lookahead dans le buffer audio
|
||
|
||
### 7.3 Mapping visèmes → blendshapes
|
||
|
||
Les 15 visèmes OVR se décomposent en mouvements de blendshapes multiples :
|
||
|
||
| Visème OVR | Blendshapes ARKit activés |
|
||
|-----------|--------------------------|
|
||
| PP (p/b/m) | mouthClose + mouthPucker |
|
||
| FF (f/v) | mouthFunnel + jawOpen(0.1) |
|
||
| TH (th) | tongueOut + jawOpen(0.2) |
|
||
| AA (a) | jawOpen(0.6) + mouthWideLeft/Right |
|
||
| OO (ou) | mouthPucker + mouthFunnel + jawOpen(0.3) |
|
||
| EE (i/e) | mouthSmileLeft/Right + jawOpen(0.2) |
|
||
| ... | ... |
|
||
|
||
Chaque visème active 2-5 blendshapes avec des poids différents → résultat plus riche que 15 shapes binaires.
|
||
|
||
---
|
||
|
||
## 8. Expressions émotionnelles
|
||
|
||
### 8.1 Émotions depuis le LLM
|
||
|
||
Le LLM Qwen3-0.6B tagger ses réponses avec des émotions **inline**, y compris au milieu des phrases :
|
||
|
||
```
|
||
Prompt système :
|
||
"Insère des tags d'émotion [joie], [tristesse], [empathie], [encouragement],
|
||
[neutre], [surprise] dans ta réponse quand l'émotion change."
|
||
|
||
Réponse LLM :
|
||
"[empathie] Je comprends que cette situation soit difficile.
|
||
[encouragement] Mais tu as déjà fait un grand pas en en parlant.
|
||
[joie] C'est vraiment courageux de ta part."
|
||
```
|
||
|
||
L'app parse les tags au fil du texte. Chaque tag déclenche une transition d'expression sur l'avatar **synchronisée avec le TTS** — l'émotion change au moment où la phrase correspondante est prononcée, pas avant.
|
||
|
||
### 8.2 Mapping émotion → expressions faciales
|
||
|
||
| Émotion LLM | Blendshapes dominants | Intensité |
|
||
|-------------|----------------------|-----------|
|
||
| joie | mouthSmile + cheekSquint + eyeSquint | 0.6-0.8 |
|
||
| tristesse | browInnerUp + mouthFrown + eyeWide(0.1) | 0.4-0.6 |
|
||
| empathie | browInnerUp(0.3) + mouthSmile(0.2) + headTilt | 0.3-0.5 |
|
||
| encouragement | browUp + mouthSmile(0.5) + nod | 0.5-0.7 |
|
||
| surprise | eyeWide + browUp + jawOpen(0.3) | 0.5-0.7 |
|
||
| neutre | repos + micro-expressions | 0.0-0.1 |
|
||
|
||
Les expressions se **blendent avec le lip sync** — l'avatar peut sourire tout en parlant.
|
||
|
||
### 8.3 Transitions
|
||
|
||
- Transition entre émotions : **ease-in-out sur 500ms** (pas de snap brutal)
|
||
- L'émotion s'applique sur la durée de la phrase TTS
|
||
- Les micro-expressions (léger sourire, haussement de sourcils) ajoutent du naturel
|
||
|
||
---
|
||
|
||
## 9. Idle animations — L'avatar vivant
|
||
|
||
Un avatar figé quand il ne parle pas = immédiatement "mort". Animations subtiles obligatoires :
|
||
|
||
| Animation | Fréquence | Amplitude |
|
||
|-----------|-----------|-----------|
|
||
| Clignement des yeux | Aléatoire, ~15-20/min | Naturel (rapide : 150ms) |
|
||
| Micro-saccades oculaires | Continu, 2-3/s | ±2° aléatoire |
|
||
| Respiration | Continue, ~16/min | Léger mouvement épaules/poitrine |
|
||
| Micro-expressions | Aléatoire, toutes les 3-8s | Très subtil (0.02-0.05) |
|
||
| Mouvement tête | Lent, continu | ±2° drift aléatoire |
|
||
|
||
Ces animations sont procédurales (pas des clips) — elles se blendent naturellement avec le lip sync et les émotions.
|
||
|
||
---
|
||
|
||
## 10. Mode enfant
|
||
|
||
### Pipeline simplifié
|
||
|
||
```
|
||
Asset pré-fait (ours en peluche .glb)
|
||
├── Mesh : 10-20K vertices
|
||
├── 15-20 blendshapes (visèmes + sourire + triste + surprise)
|
||
├── Texture : stylisée, pré-faite
|
||
└── Rig : squelette simple (tête + corps)
|
||
│
|
||
Même pipeline lip sync + émotions
|
||
│
|
||
Pas de capture nécessaire
|
||
```
|
||
|
||
- Pas de reconstruction faciale
|
||
- Pas de voice cloning (voix synthétique par défaut ou voix pré-enregistrée)
|
||
- L'ours en peluche fait les mêmes expressions et lip sync que l'avatar humain
|
||
- **Premier livrable** pour valider le pipeline complet avant le mode adulte
|
||
|
||
---
|
||
|
||
## 11. Multi-utilisateurs et profils
|
||
|
||
### Modèle de profils
|
||
|
||
Un **profil** = un avatar (visage + voix). Un **utilisateur** = une personne qui utilise Kazeia.
|
||
|
||
```
|
||
Profil "Dr. Martin"
|
||
├── Avatar 3D (mesh, texture, blendshapes)
|
||
├── X-vector voix
|
||
├── Vidéo consentement
|
||
└── Permissions :
|
||
├── Utilisateur: Léa (autorisé)
|
||
├── Utilisateur: Hugo (autorisé)
|
||
└── Mode: multi-utilisateur (autorisé par Dr. Martin)
|
||
|
||
Profil "Maman de Léa"
|
||
├── Avatar 3D + voix
|
||
└── Permissions :
|
||
└── Utilisateur: Léa uniquement (mono-utilisateur)
|
||
```
|
||
|
||
### Règles
|
||
|
||
- **Création** : la personne filmée crée le profil et donne son consentement
|
||
- **Mono-utilisateur** (par défaut) : le profil n'est utilisable que par un seul utilisateur désigné
|
||
- **Multi-utilisateur** : la personne doit explicitement autoriser le partage lors du consentement
|
||
- Phrase modifiée : *"...pour un usage partagé avec les utilisateurs que j'autorise"*
|
||
- **Révocation** : la personne peut révoquer son profil à tout moment (suppression avatar + voix, vidéo consentement conservée)
|
||
- **Pas de transfert** : un profil ne peut pas être copié vers un autre appareil (lié au device)
|
||
|
||
### Stockage profils
|
||
|
||
```
|
||
/data/data/com.kazeia/profiles/
|
||
├── profile_001/
|
||
│ ├── consent_video.enc (chiffré, non supprimable)
|
||
│ ├── avatar_mesh.enc (chiffré)
|
||
│ ├── avatar_texture.enc (chiffré)
|
||
│ ├── avatar_blendshapes.enc (chiffré)
|
||
│ ├── speaker_xvector.enc (chiffré)
|
||
│ └── metadata.json (permissions, utilisateurs autorisés)
|
||
└── profile_002/
|
||
└── ...
|
||
```
|
||
|
||
---
|
||
|
||
## 12. Mode dégradé
|
||
|
||
Si la personne ne souhaite pas un avatar photoréaliste de son visage :
|
||
|
||
| Option | Description | Voix |
|
||
|--------|------------|------|
|
||
| **Semi-stylisé** | Son visage mais en style 3D animation (Pixar-like) | Sa voix clonée |
|
||
| **Avatar générique** | Visage prédéfini parmi un catalogue | Sa voix clonée |
|
||
| **Personnage** | Ours en peluche ou autre mascotte | Sa voix clonée |
|
||
| **Voix seule** | Pas d'avatar, écran avec animation abstraite | Sa voix clonée |
|
||
|
||
Le choix est fait lors de la création du profil. Le voice cloning reste disponible dans tous les modes (seul le visuel change).
|
||
|
||
Le style semi-stylisé utilise le même pipeline de capture mais applique un **style transfer** au rendu :
|
||
- Peau lissée (pas de pores)
|
||
- Yeux légèrement agrandis
|
||
- Proportions adoucies
|
||
- Shader toon subtil au lieu de PBR réaliste
|
||
|
||
---
|
||
|
||
## 13. Mise à jour du profil
|
||
|
||
L'utilisateur ou la personne du profil peut mettre à jour les photos :
|
||
|
||
- **Ajout de photos** : nouvelles vues → amélioration texture + géométrie
|
||
- **Changement d'apparence** : lunettes, coupe de cheveux → re-capture partielle
|
||
- **Vieillissement** : re-capture complète tous les X mois si souhaité
|
||
- **Process** : même protocole de capture (phase 1 + 3), pas besoin de re-filmer le consentement
|
||
- **Versioning** : l'ancien avatar est conservé jusqu'à validation du nouveau
|
||
|
||
---
|
||
|
||
## 14. Simultanéité TTS + Avatar
|
||
|
||
L'avatar et le TTS travaillent ensemble en temps réel :
|
||
|
||
```
|
||
Timeline d'une réponse Kazeia :
|
||
|
||
t=0s LLM génère texte + tag émotion
|
||
t=0.1s Avatar reçoit émotion → transition expression (500ms ease-in)
|
||
t=0.1s TTS démarre génération (Hexagon NPU)
|
||
t=6s Génération terminée → hexStopRunner()
|
||
t=6.5s QNN decode audio (3.5s)
|
||
t=10s Audio prêt → AudioTrack.play()
|
||
→ OVRLipSync analyse en temps réel
|
||
→ Blendshape weights envoyés à Unity à 60fps
|
||
→ Avatar parle avec lip sync + émotion
|
||
t=14s Audio terminé → avatar retour idle (ease-out 500ms)
|
||
```
|
||
|
||
**Pas de streaming pour l'instant** (conflit DSP hexagon/QNN). L'avatar affiche l'émotion et les idle animations pendant la génération TTS, puis commence le lip sync quand l'audio est prêt.
|
||
|
||
Le lip sync est synchrone avec l'audio — Unity lit le même buffer PCM que AudioTrack.
|
||
|
||
---
|
||
|
||
## 15. Consentement et données personnelles
|
||
|
||
### Stockage sur l'appareil
|
||
|
||
| Donnée | Taille | Chiffré | Supprimable | Durée |
|
||
|--------|--------|---------|-------------|-------|
|
||
| Vidéo consentement | ~30 MB | AES-256 | **Non** (preuve légale) | Permanent |
|
||
| Photos capture | ~50 MB | Non (temp) | **Supprimées** après traitement | ~2 min |
|
||
| Audio brut | ~1 MB | Non (temp) | **Supprimé** après extraction x-vector | ~1 min |
|
||
| X-vector voix | 4 KB | AES-256 | Oui (supprime avatar) | Tant que avatar existe |
|
||
| Mesh avatar | ~5 MB | AES-256 | Oui | Tant que avatar existe |
|
||
| Texture avatar | ~15 MB | AES-256 | Oui | Tant que avatar existe |
|
||
| Blendshapes | ~2 MB | AES-256 | Oui | Tant que avatar existe |
|
||
|
||
### Principes RGPD
|
||
|
||
- **Rien ne quitte l'appareil** — tout le traitement est on-device
|
||
- **Consentement explicite** — vidéo avec déclaration orale comme preuve
|
||
- **Droit à l'effacement** — l'utilisateur peut supprimer son avatar (sauf vidéo consentement)
|
||
- **Minimisation** — photos et audio brut supprimés dès que traités
|
||
- **Pas de biométrie stockée** — le x-vector seul ne permet pas de reconnaître une voix (vecteur de 1024 dimensions, non réversible)
|
||
|
||
---
|
||
|
||
## 16. Architecture d'intégration
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ App Kazeia │
|
||
│ │
|
||
│ ┌──────────────────┐ ┌───────────────────────┐ │
|
||
│ │ ChatActivity │ │ UnityPlayerActivity │ │
|
||
│ │ (Conversation) │◄──►│ (Avatar 3D) │ │
|
||
│ │ │ │ │ │
|
||
│ │ - Chat UI │ │ - Rendu avatar │ │
|
||
│ │ - Contrôles │ │ - Blendshape anim. │ │
|
||
│ │ - État session │ │ - Lip sync │ │
|
||
│ └───────┬──────────┘ │ - Idle anims │ │
|
||
│ │ │ - Émotions │ │
|
||
│ │ └───────┬───────────────┘ │
|
||
│ │ │ │
|
||
│ ┌───────▼───────────────────────▼───────────────┐ │
|
||
│ │ KazeiaService │ │
|
||
│ │ │ │
|
||
│ │ Whisper STT (NPU) → LLM Qwen3 (NPU) │ │
|
||
│ │ → TTS Qwen3 (Hexagon + QNN) │ │
|
||
│ │ │ │
|
||
│ │ Events émis : │ │
|
||
│ │ ├── onTtsAudioChunk(pcm) → lip sync │ │
|
||
│ │ ├── onEmotion(tag) → expression avatar │ │
|
||
│ │ ├── onSpeechStart() → avatar attentif │ │
|
||
│ │ └── onSpeechEnd() → avatar retour idle │ │
|
||
│ └────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Communication KazeiaService ↔ Unity
|
||
|
||
- **Java → C#** : `UnityPlayer.UnitySendMessage("AvatarController", "OnEmotion", "joie")`
|
||
- **Audio → lip sync** : SharedMemory ou AudioTrack partagé — Unity lit le même buffer audio
|
||
- **C# → Java** : callback via `AndroidJavaObject` pour les événements Unity (avatar ready, etc.)
|
||
|
||
---
|
||
|
||
## 17. Phases d'implémentation
|
||
|
||
### Phase 1 — Proof of concept (2-3 semaines)
|
||
|
||
- [ ] Projet Unity avec UaaL export Android
|
||
- [ ] Asset ours en peluche avec 15 blendshapes
|
||
- [ ] Lip sync basique (OVRLipSync ou uLipSync)
|
||
- [ ] Intégration dans kazeia-android (UnityPlayerActivity)
|
||
- [ ] Bridge : audio TTS → lip sync Unity
|
||
- [ ] Idle animations (clignements, respiration)
|
||
|
||
**Livrable** : ours en peluche qui parle avec lip sync depuis le TTS Kazeia
|
||
|
||
### Phase 2 — Face cloning (3-4 semaines)
|
||
|
||
- [ ] UI de capture guidée (MediaPipe Face Mesh)
|
||
- [ ] Vidéo consentement + extraction audio
|
||
- [ ] Voice cloning : extraction x-vector, remplacement de l'embedding
|
||
- [ ] DECA/EMOCA inference on-device
|
||
- [ ] Multi-view FLAME fitting
|
||
- [ ] Subdivision mesh + projection texture UV
|
||
- [ ] Super-résolution texture
|
||
- [ ] Export mesh + blendshapes vers Unity
|
||
|
||
**Livrable** : avatar personnalisé depuis selfies, voix clonée
|
||
|
||
### Phase 3 — Photoréalisme (2-3 semaines)
|
||
|
||
- [ ] Skin shader PBR + subsurface scattering
|
||
- [ ] Normal map pore-level
|
||
- [ ] Eye shader (iris, cornée, reflets)
|
||
- [ ] Cheveux (cards alpha ou cadrage serré)
|
||
- [ ] Émotions LLM → expressions faciales
|
||
- [ ] Blending émotions + lip sync
|
||
- [ ] Polish : micro-expressions, transitions fluides
|
||
|
||
**Livrable** : avatar photoréaliste avec expressions émotionnelles
|
||
|
||
### Phase 4 — Polish et optimisation (1-2 semaines)
|
||
|
||
- [ ] Profiling GPU (vérifier budget <15%)
|
||
- [ ] Optimisation mémoire (LOD, texture streaming)
|
||
- [ ] Gestion lifecycle Unity ↔ Android robuste
|
||
- [ ] Chiffrement données avatar
|
||
- [ ] UI de gestion avatar (créer, supprimer, changer)
|
||
- [ ] Test uncanny valley → décision photoréaliste vs semi-stylisé
|
||
|
||
---
|
||
|
||
## 18. Risques et mitigations
|
||
|
||
| Risque | Impact | Mitigation |
|
||
|--------|--------|------------|
|
||
| Uncanny valley (visage réaliste mal animé) | Rejet utilisateur | Fallback semi-stylisé préparé en parallèle |
|
||
| Texture basse qualité depuis caméra frontale | Avatar flou en gros plan | Super-résolution + normal map halluciné |
|
||
| DECA insuffisant pour photoréalisme | Géométrie approximative | Multi-view fitting + calibration expressions |
|
||
| UaaL lifecycle complexe | Crashs, fuites mémoire | Isolation stricte, tests intensifs |
|
||
| Lip sync saccadé sur grand écran | Effet robotique | 52 blendshapes + cubique Hermite + 60fps |
|
||
| Cheveux difficiles à rendre | Apparence artificielle | Cadrage serré (front→menton) pour v1 |
|
||
| Taille APK Unity (+40-80 MB) | Download lourd | Asset bundles, chargement à la demande |
|
||
| Performance GPU inattendue | Framerate bas | Budget large (15% estimé), marge 85% |
|
||
|
||
---
|
||
|
||
## 19. Résumé
|
||
|
||
| Aspect | Choix |
|
||
|--------|-------|
|
||
| Moteur 3D | Unity (UaaL) embarqué dans app Android native |
|
||
| Capture | 10 photos guidées + vidéo consentement (~60s) |
|
||
| Reconstruction | DECA/FLAME multi-view → 80K vertices subdivisé |
|
||
| Texture | Projection multi-vue 4096×4096 + super-résolution |
|
||
| Blendshapes | 52 ARKit-compatibles, personnalisés par expressions |
|
||
| Lip sync | OVRLipSync → 52 blendshapes, interpolation cubique, 60fps |
|
||
| Émotions | Tag LLM → expressions faciales blendées avec lip sync |
|
||
| Voice cloning | X-vector extrait de la vidéo de consentement |
|
||
| Style | Photoréaliste (fallback semi-stylisé si uncanny valley) |
|
||
| Mode enfant | Asset pré-fait (ours en peluche), même pipeline lip sync |
|
||
| Données | 100% on-device, chiffré, RGPD-compatible |
|
||
| GPU | Adreno 830, <15% utilisé, 100% dédié avatar |
|