ComfyUI Node

GetCrossSim

The matchmaker between your reference and your new render

By thatname·Created 10 months ago·Updated 9 months ago· 1
GetCrossSim
  • subject_attn
  • curr_attn
  • id_mask
  • curr_mask
  • cross_sim
cross_sim_step
sim_threshold0.50

GetCrossSim is the node that answers the question the whole pack depends on: which parts of the new image correspond to which parts of the reference subject? ExtractAttn gives you attention caches, but two caches on their own are just two big piles of tensors. Somebody has to decide that a patch of shoulder in the current render matches a patch of shoulder in the reference before GenConsistent knows where to splice anything in. That's this node's job, and it's the middle third of the CharaConsist two-pass pipeline: ExtractAttn → GetCrossSim → GenConsistent.

You'll notice it needs two ATTN inputs, subject_attn and curr_attn. That's the subtle part most people trip on the first time. subject_attn is the cache from your reference pass. curr_attn is the cache from the current generation you're matching against - in the shipped example workflows, the current pass is itself run through an ExtractAttn-instrumented sampler. So the workflow grows a second ExtractAttn branch just to feed this node. It costs more RAM, but it's how the pack knows what the target image is actually doing at each layer.

How it works

For each subject in subject_attn, at the step named by cross_sim_step, it compares hidden states layer by layer. The subject's attention output vectors and the current image's vectors get L2-normalized, then multiplied together to get a similarity matrix - essentially, "how alike is every subject token to every current token." It sums those similarities across layers and averages, then takes the argmax to find each current token's best match in the subject.

Then two filters decide what actually counts as a match:

  • sim_threshold (default 0.5): the match must score above this. Crank it up and you get fewer, higher-confidence matches; crank it down and GenConsistent gets more material but more noise. 0.5 is a reasonable place to start.
  • The foreground masks: matches only survive where both id_mask and curr_mask mark the token as foreground. This is where the masks from ExtractAttn's fg_condition_mask (or your SAM masks) earn their keep - it stops the matching from gluing your character to the background.

Inputs and outputs that matter

Required: subject_attn (ATTN), curr_attn (ATTN), id_mask (MASK - one per subject), curr_mask (MASK), cross_sim_step (INT - which denoising step to compare at), sim_threshold (FLOAT). The masks are indexed per subject, so id_mask[i] must correspond to subject i.

Output is a single CROSSSIM - a custom pack type, a dict holding id_fg_inds and curr_fg_inds (the matched token indices on each side), max_sim (the similarity scores), and a debug_mask with the raw similarity values. That dict feeds straight into GenConsistent's cross_sim input.

Install and troubleshooting

Same pack install as always - Manager search "Comfyui_CharaConsist", or git clone https://github.com/thatname/Comfyui_CharaConsist.git into custom_nodes, restart, find it under chara_consist. No pip deps; Flux/Chroma/Qwen-Image only.

Two failure modes worth knowing. First, GetCrossSim raises a ValueError if cross_sim_step isn't present in the current attention cache - if your ExtractAttn ran with a kv_end_step/x_end_step below the step you ask for here, the cache never recorded it and the node dies loudly. That's actually friendly behavior; it's the silent failures that are worse. Second, if sim_threshold is too high or your masks don't overlap the subject, you'll get zero surviving matches and GenConsistent will run as a no-op with no error at all. If your consistent character looks exactly like a plain generation, blame the threshold or the masks before you blame the sampler. It's an obscure, under-documented node, so expect to tune it by feel - but when the argmax lands right, the whole pipeline snaps together.

Categorychara_consist

Inputs (6)

NameTypeDefaultDescription
subject_attnATTN
curr_attnATTN
id_maskMASK
curr_maskMASK
cross_sim_stepINT
sim_thresholdFLOAT0.500–2

Outputs (1)

NameTypeDescription
cross_simCROSSSIM