Nodes/ComfyUI-Unblend/Unblend Dynamic Sampler (Bounded Attention)
ComfyUI Node

Unblend Dynamic Sampler (Bounded Attention)

The Unblend Dynamic Sampler

By LatentDesireAI·Created 3 months ago·Updated 3 months ago· 0
Unblend Dynamic Sampler (Bounded Attention)
  • model
  • clip
  • latent_image
  • vae
  • latent
  • char_masks
  • mask_preview
  • info
  • model
  • positive
  • negative
prompt[QUALITY] masterpiece, best quality [STYLE] anime style [SCENE] simple background [CHAR1] columbina (genshin impact), black hair, white dress [CHAR2] fischl (genshin impact), blonde hair, eyepatch [INTERACT] embracing, face to face
negative_promptlowres, worst quality, low quality, bad anatomy, bad hands
seed0
steps32
cfg5.5
sampler_name
scheduler
warmup_at0.15
refresh_every4
mask_source
map_threshold0.35
bound_strength1.00
self_attn_jailtrue
jail_strength1.00
identity_lock1.00
subject_wordgirl
divider
init_ratios1,1
char_points
early_jailfalse

Prompt two characters, hit generate, and one of three things happens: the hair colors mix, the eyepatch migrates to the wrong face, or you get twins - two people who have clearly spent their lives sharing one face. The closer they're posed, the worse it gets. UnblendDynamicSampler is this pack's answer to that, and it's the node you'll build your whole workflow around.

Its display name, Bounded Attention, is the honest one. The sampler watches where each character's tokens are attending in the model's own cross-attention maps, rebuilds a live mask for every [CHARn] every few steps, and keeps those tokens locked inside their own zone. No hand-drawn masks, no regional-prompting spaghetti. The README demos it on a deliberately brutal case - Ningguang × Shenhe, two white-haired Genshin characters, exactly where a plain sampler blurs identities into mush.

How it works

For the first chunk of steps (warmup_at, default 0.15 of the schedule) the characters form anywhere. After that, every refresh_every steps the node reads the cross-attention maps, thresholds them (map_threshold), and rebuilds each character's mask from where its tokens actually are. Then it constrains sampling so CHAR1's tokens only influence CHAR1's pixels. Two knobs tune the strictness:

  • identity_lock - bonus attention to a character's own distinctive tokens inside its zone. 0 = off, 1 = moderate, up to 4 if you're feeling strict. Crank it when signatures keep leaking to the wrong face.
  • self_attn_jail / jail_strength - cuts self-attention between characters so they stop peeking at each other. Sounds great, but here's the trap: hugs and touches form through cross-body attention. For [INTERACT] scenes, leave early_jail off.

The real input, though, is the prompt. Unblend uses tagged prompts - [QUALITY], [STYLE], [SCENE], [CHAR1]/[CHAR2], [INTERACT] - and the author's own bug list (in PROMPTING.md) gives you three rules that save most of the pain:

  1. Keep each [CHARn] compact, ~35–45 tokens. A long one breaks across the 77-token CLIP boundary and you get CHARn tokens not found in the log - a square instead of a silhouette.
  2. Put the other character's name only in [INTERACT], never inside a [CHARn], or it binds to the wrong mask and you're back to identity mixups.
  3. Don't write 1girl yourself - the node sets the count. Mixed cast? Put girl, boy in subject_word and each character keeps its own gender.

What comes out

This node is a pipeline in one box. latent is your generated image - decode and look at it. char_masks and mask_preview are the masks it built along the way. The interesting pair is model and positive: a couple+jail-patched model and the conditioning that goes with it, intended for the detail pass. That's the hand-off to the second stage - either a manual hi-res KSampler or, per the intended pipeline, Sequential Refine. There's also a solo fallback: give it zero or one [CHARn] and it plain-samples without bounded attention, no crash, outputs still compatible with the graph.

Install

The pack installs through ComfyUI Manager - search "Unblend", Install, restart, dependencies handled. Manual:

cd ComfyUI/custom_nodes
git clone https://github.com/LatentDesireAI/ComfyUI-Unblend
pip install -r ComfyUI-Unblend/requirements.txt

Then restart. This is an SDXL / Illustrious node: the code runs an SDXL check on every execution, so a Flux checkpoint will just fail. The dghs-imgutils / dghs-realutils deps do the silhouette and head detection and pull their ONNX weights automatically on first run - expect a short download the first time.

Troubleshooting

Read the info string every run. A healthy one says characters: N with no CHARn tokens not found. If your masks come back as a clean 50/50 vertical split, that's the column fallback (init_ratios) kicking in because char_points is empty - set anchors like 0.3,0.45; 0.7,0.45 (normalized, in CHARn order). If identities still swap, the characters need more contrast - different hair, eyes, clothes, the things the model tells people apart by. If the style drifts between scenes, it's almost always [STYLE], not the sampler. And if it all just works, enjoy it - this is the node that makes the rest of the pack worth having.

CategoryUnblend

Inputs (24)

NameTypeDefaultDescription
modelMODEL
clipCLIP
latent_imageLATENT
promptSTRING[QUALITY] masterpiece, best quality [STYLE] anime style [SCENE] simple background [CHAR1] columbina (genshin impact), black hair, white dress [CHAR2] fischl (genshin impact), blonde hair, eyepatch [INTERACT] embracing, face to face
negative_promptSTRINGlowres, worst quality, low quality, bad anatomy, bad hands
seedINT00–18446744073709550000
stepsINT328–200
cfgFLOAT5.50.5–20
sampler_nameCOMBO44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38
schedulerCOMBO9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
warmup_atFLOAT0.150.03–0.6
refresh_everyINT41–16
mask_sourceCOMBO2 options: attn_maps+silhouette, attn_maps
map_thresholdFLOAT0.350.05–0.95
bound_strengthFLOAT1.000–1
self_attn_jailBOOLEANtrue
jail_strengthFLOAT1.000–1
identity_lockFLOAT1.000–4
subject_wordSTRINGgirlBooru count word. One word = all characters (e.g. 'girl'). Comma list for a mixed cast: 'girl, boy' -> CHAR1 girl, CHAR2 boy (padded with the last).
dividerCOMBO2 options: watershed, nearest_center
init_ratiosSTRING1,1
char_pointsSTRING
early_jailBOOLEANfalse
vaeoptVAE

Outputs (7)

NameTypeDescription
latentLATENTresult latent
char_masksMASKcharacter masks
mask_previewIMAGEmask preview
infoSTRINGlog
modelMODELpatched model (couple+jail with the final masks) — for the detail/hires KSampler; masks recompute themselves for the new size
positiveCONDITIONINGdraw conditioning (REQUIRED as the second KSampler's positive — the bias is tied to its token positions)
negativeCONDITIONINGnegative (for convenience)