Added models: - Wan2.2 diffusion models: T2V, Animate 14B, T2V Low Noise - Wan2.2 LoRAs: Lightning 4-step, Lightx2v, Relight, Distill - Text encoders: UMT5-XXL (fp8 and bf16 variants) - CLIP Vision H for Wan workflows - InsightFace buffalo_l model for face detection - IP-Adapter Plus SDXL VIT-H - RealESRGAN x4 upscaler - Wan 2.1 VAE Updated file permissions to executable for all Python files and documentation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
16 KiB
Executable File
ControlNet Character Face Swap Node - Implementation Plan
Concept Overview
Create a ComfyUI node that takes a reference image (for pose, clothing, background, scene) and applies a character's face from your AI model collection. This lets you place your consistent AI characters into any pose/scene while maintaining their identity.
Use Case Example
Input 1: Reference image of a person sitting at a café (pose + scene)
Input 2: Your AI character model/LoRA or reference face image
Output: Your character sitting at the café in the same pose
Technical Approach
1. Multi-ControlNet for Structure Transfer
Extract structure from reference image:
- OpenPose - Body pose and skeleton (PRIMARY - most important)
- Depth - Spatial depth and 3D structure
- Canny Edge - Sharp outlines and composition
- Normal Map - Surface details and lighting direction
- Softedge - Softer structural guidance
2. Character Face Application Methods
Option A: LoRA-Based (Best for consistent characters)
- Use character-specific LoRA trained on your AI character
- ControlNets guide pose/scene
- LoRA ensures consistent face/identity
- Strength: LoRA weight 0.7-1.0
Option B: IP-Adapter FaceID (Best for flexibility)
- Use IP-Adapter with FaceID model
- Input: Reference image structure + Character face reference
- Maintains face identity across different scenes
- Strength: IP-Adapter weight 0.8-1.0
Option C: Reactor/ReActor Face Swap
- Generate image with ControlNets
- Use face swap to replace generated face with character face
- Most accurate face transfer
- Works with any character reference
3. Recommended Hybrid Approach
Combine multiple methods for best results:
Reference Image (pose/scene)
↓
┌─────────────────────────────────┐
│ ControlNet Preprocessing │
│ - OpenPose skeleton │
│ - Depth map │
│ - Canny edges │
│ - Normal map │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Initial Generation │
│ - Base model + Character LoRA │
│ - Guided by ControlNets │
│ - Prompt: character description│
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Face Identity Reinforcement │
│ Option 1: IP-Adapter FaceID │
│ Option 2: ReActor Face Swap │
│ - Apply character face │
│ - Blend seamlessly │
└─────────────────────────────────┘
↓
Output: Character in reference pose/scene
Node Architecture
Input Ports
Required
- reference_image - Source image for pose/background/scene
- model - Base Stable Diffusion checkpoint
- character_face_image - Your character's face reference
Character Method (Choose One)
- character_lora - LoRA file for your character (optional)
- lora_strength - Float (0.0-1.5, default 0.8)
ControlNet Settings
- pose_strength - Float (0.0-1.5, default 1.0) - Most important
- depth_strength - Float (0.0-1.5, default 0.7)
- canny_strength - Float (0.0-1.5, default 0.5)
Generation Settings
- positive_prompt - Character description + scene details
- negative_prompt - Quality negatives
- face_method - Choice ["IP-Adapter FaceID", "ReActor", "Both"]
- face_strength - Float (0.0-1.0, default 0.85)
- seed - Random seed
Optional
- preserve_clothes - Boolean (try to keep reference clothing)
- preserve_background - Boolean (keep original background)
- style_prompt - Override style (anime, realistic, etc.)
Output Ports
- image - Final generated image
- pose_preview - OpenPose skeleton preview
- depth_preview - Depth map preview
- face_mask - Face region mask (debugging)
Processing Pipeline
class ControlNetCharacterSwap:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"reference_image": ("IMAGE",),
"character_face": ("IMAGE",),
"model": ("MODEL",),
"positive_prompt": ("STRING", {"multiline": True}),
"pose_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0}),
"face_strength": ("FLOAT", {"default": 0.85, "min": 0.0, "max": 1.0}),
},
"optional": {
"character_lora": ("LORA",),
"lora_strength": ("FLOAT", {"default": 0.8}),
"depth_strength": ("FLOAT", {"default": 0.7}),
"canny_strength": ("FLOAT", {"default": 0.5}),
"face_method": (["IP-Adapter FaceID", "ReActor", "Both"],),
}
}
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "MASK")
RETURN_NAMES = ("image", "pose_preview", "depth_preview", "face_mask")
FUNCTION = "generate_character"
CATEGORY = "PMA Utils/Character"
def generate_character(self, reference_image, character_face, model,
positive_prompt, pose_strength, face_strength,
character_lora=None, lora_strength=0.8,
depth_strength=0.7, canny_strength=0.5,
face_method="IP-Adapter FaceID"):
# STEP 1: Extract ControlNet Maps
pose_map = openpose_detector(reference_image)
depth_map = depth_estimator(reference_image)
canny_map = canny_detector(reference_image)
# STEP 2: Prepare Model
working_model = model
if character_lora:
working_model = apply_lora(model, character_lora, lora_strength)
# STEP 3: Apply ControlNets
# OpenPose is primary - controls body structure
latent = apply_controlnet(
model=working_model,
controlnet=openpose_controlnet,
image=pose_map,
strength=pose_strength
)
# Depth adds spatial awareness
latent = apply_controlnet(
latent=latent,
controlnet=depth_controlnet,
image=depth_map,
strength=depth_strength
)
# Canny for fine details (lower strength to allow character features)
latent = apply_controlnet(
latent=latent,
controlnet=canny_controlnet,
image=canny_map,
strength=canny_strength
)
# STEP 4: Generate Base Image
generated_image = generate(
latent=latent,
positive=positive_prompt,
negative=negative_prompt,
model=working_model
)
# STEP 5: Apply Character Face
if face_method == "IP-Adapter FaceID":
final_image = apply_ipadapter_faceid(
image=generated_image,
face_reference=character_face,
strength=face_strength
)
elif face_method == "ReActor":
final_image = reactor_face_swap(
target_image=generated_image,
source_face=character_face,
strength=face_strength
)
elif face_method == "Both":
# First IP-Adapter, then ReActor for maximum accuracy
temp_image = apply_ipadapter_faceid(
image=generated_image,
face_reference=character_face,
strength=face_strength * 0.7
)
final_image = reactor_face_swap(
target_image=temp_image,
source_face=character_face,
strength=face_strength
)
# STEP 6: Generate Previews
face_mask = detect_face_mask(final_image)
return (final_image, pose_map, depth_map, face_mask)
Workflow Example
Basic Workflow
┌─────────────────┐
│ Reference Image │ (person at café)
└────────┬────────┘
│
┌────▼─────────────────────┐
│ ControlNet Preprocessors │
│ - OpenPose │
│ - Depth │
│ - Canny │
└────┬─────────────────────┘
│
┌────▼────────────┐ ┌──────────────────┐
│ SD Generation │◄─────┤ Character LoRA │
│ + ControlNets │ └──────────────────┘
└────┬────────────┘
│
┌────▼────────────┐ ┌──────────────────┐
│ IP-Adapter │◄─────┤ Character Face │
│ FaceID │ │ Reference │
└────┬────────────┘ └──────────────────┘
│
┌────▼────────────┐
│ Final Output │ (Your character at café)
└─────────────────┘
Prompt Strategy
Positive Prompt Template
[CHARACTER NAME/DESCRIPTION], [CHARACTER FEATURES],
[REFERENCE SCENE DESCRIPTION], [POSE DESCRIPTION],
[STYLE KEYWORDS], high quality, detailed face, 8k
Example:
Emma, young woman with long brown hair, blue eyes, fair skin,
sitting at outdoor café table, holding coffee cup, relaxed pose,
photorealistic, natural lighting, bokeh background, professional photo
Negative Prompt
bad face, deformed, ugly, blurry, low quality, bad anatomy,
extra limbs, wrong proportions, watermark
Required Models & Dependencies
ControlNet Models (SD 1.5 or SDXL)
- control_sd15_openpose.pth - ESSENTIAL
- control_sd15_depth.pth - ESSENTIAL
- control_sd15_canny.pth - Recommended
- control_sd15_normal.pth - Optional
Face Models
-
IP-Adapter FaceID Plus v2 - For face identity transfer
- Model:
ip-adapter-faceid-plusv2_sdxl.bin - CLIP:
clip_vision_SDXL_vit-h.safetensors
- Model:
-
ReActor - For face swapping
- InsightFace models (buffalo_l)
ComfyUI Custom Nodes
- ComfyUI-ControlNet-Aux - Preprocessors
- ComfyUI-IPAdapter-Plus - IP-Adapter support
- ReActor Node - Face swapping
- ComfyUI-Impact-Pack - Face detection utilities
Your Character Assets
- Character LoRAs - Trained on your AI characters
- Character Face References - Clean face shots of each character
Character Library Management
Suggested Structure
/models/loras/characters/
emma_character.safetensors
john_character.safetensors
sarah_character.safetensors
/inputs/character_faces/
emma_face.png
john_face.png
sarah_face.png
Node Enhancement: Character Selector
Add dropdown to select from saved characters:
"character_preset": (self.get_character_list(),)
def get_character_list(self):
# Scan character directory
return ["Emma", "John", "Sarah", "Custom..."]
Advanced Features
1. Outfit Preservation Mode
- Extract clothing from reference with segmentation
- Apply clothing ControlNet or inpainting
- Keep character face + reference outfit
2. Background Swapping
- Segment background from reference
- Replace with custom background
- Keep character + pose
3. Multi-Character Scenes
- Detect multiple people in reference
- Apply different character faces to each
- Maintain relative positions
4. Expression Transfer
- Detect facial expression from reference
- Apply expression to character face
- Use expression ControlNet if available
5. Batch Processing
- Process multiple references with same character
- Generate character pose library
- Automatic prompt generation from reference
Testing Scenarios
| Scenario | Reference | Character | Expected Result |
|---|---|---|---|
| Portrait | Professional headshot | Emma | Emma in professional setting |
| Action | Person jumping | John | John jumping, same pose |
| Group | 3 people at party | Sarah (1 person) | Sarah in same scene/pose |
| Historical | Vintage photo | Emma | Emma in vintage style/setting |
| Fashion | Model on runway | John | John as fashion model |
Optimization Tips
For Best Quality
- OpenPose Strength: 0.9-1.2 (maintain pose)
- Character LoRA: 0.7-1.0 (strong character features)
- Face Method: "Both" (IP-Adapter + ReActor)
- Resolution: Match reference or use 1024x1024 for SDXL
For Speed
- Reduce ControlNets: Use only OpenPose + Depth
- Lower Steps: 20-25 steps sufficient
- Skip ReActor: Use only IP-Adapter FaceID
- Batch Process: Queue multiple generations
For Consistency Across Images
- Use Same LoRA + Weight for all generations
- Use Same Face Reference image
- Lock Seed for similar variations
- Save Workflow as template
Common Issues & Solutions
| Problem | Cause | Solution |
|---|---|---|
| Wrong face | Weak face strength | Increase face_strength to 0.9-1.0 |
| Wrong pose | Weak pose ControlNet | Increase pose_strength to 1.2 |
| Blurry face | ControlNet conflict | Lower canny/depth, keep pose high |
| Wrong clothing | Strong clothing from ref | Lower depth_strength, use outfit prompt |
| Background wrong | ControlNets too strong | Lower all except pose, focus prompt on BG |
| Face doesn't match character | LoRA not strong enough | Increase lora_strength or use "Both" face method |
Implementation Phases
Phase 1: Core Functionality
- Plan architecture
- Implement OpenPose ControlNet integration
- Implement Depth ControlNet integration
- Basic generation pipeline
Phase 2: Face Integration
- IP-Adapter FaceID integration
- ReActor face swap integration
- Face blending quality improvements
Phase 3: LoRA Support
- Character LoRA loading
- LoRA strength controls
- Character library management
Phase 4: UI/UX
- Character preset selector
- Preview outputs for each stage
- Workflow templates
Phase 5: Advanced Features
- Outfit preservation mode
- Expression transfer
- Batch processing
Expected Results
Quality Metrics:
- Face Similarity: 90%+ match to character reference
- Pose Accuracy: 95%+ match to reference pose
- Scene Coherence: Natural integration of character into scene
- Processing Time: 15-30 seconds per image (RTX 3090)
Conclusion
This node solves the problem of placing consistent AI characters into arbitrary poses and scenes. By combining ControlNet for structure transfer with face identity models (IP-Adapter/ReActor), you can maintain character consistency while achieving any pose or setting.
Perfect for:
- Building character portfolio/lookbooks
- Storytelling with consistent characters
- Virtual fashion/product modeling
- Character-based content creation
- AI influencer content
Estimated Development Time: 1-2 weeks
Complexity: Medium-High
Value: Extremely high for character-based workflows