Latent Upscale (Hires Fix) πΌ
Hires Fix in One Node β The Second Pass, and When It's a Waste of Time
- samples
- model
- positive
- negative
- latent
- summary
"Hires fix" is one of the most misunderstood terms in this hobby, so let's be precise: it is not an upscaler. It's two-pass generation. You generate at the resolution the model was trained for, blow the latent up, and re-sample at low denoise so the model fills in coherent detail at the new size. Skip it and your 1536px generation comes back with repeated anatomy and tiled texture, which is the single most common "my images are broken" report there is.
This node does the second half of that - latent upscale plus optional refine pass - in one step, with no VAE decode-and-re-encode round trip in between.
What it's doing under the hood
Step one always runs: it hands your samples to ComfyUI's own core LatentUpscaleBy, scaling the latent spatially in latent space. Step two runs only if resample is True: it calls core KSampler with your model, conditioning and settings, at denoise strength. Neither step is reimplemented - this is a wiring shortcut plus a summary, not new sampling math.
Because the upscale happens on the latent grid rather than on pixels, the resolution numbers in the summary look small: latents run at one-eighth of pixel scale, so a 1.5x latent upscale is a 1.5x image.
Inputs worth setting
Required inputs are samples, upscale_method (five choices: nearest-exact, bilinear, area, bicubic, bislerp), scale_by and resample. Everything for the refine pass - model, positive, negative, seed, steps, cfg, sampler_name, scheduler, denoise - is optional, which is how the node supports its two modes.
scale_bydefaults to 1.5. Keep it there or go to 2.0. One hop to 4x doesn't work; you're asking the second pass to invent an image's worth of detail it has no basis for.denoisedefaults to 0.5, and 0.3β0.5 is the useful band. Under 0.3 you've paid for a sampling pass that changed nothing. Over 0.6 it stops being a refine and starts being a re-roll, and your composition drifts.upscale_method-bislerpandbicubicare the usual hires-fix picks.nearest-exactis for when you want raw block fidelity, not for this job.stepsdefaults to 20, but the second pass tolerates fewer; 10β15 is often enough since you're refining, not building.
The output is latent (wire it into VAE Decode, or into another upscale pass) plus summary.
Set resample to False more often than you think
Flip resample off and this becomes a plain latent upscaler with a summary attached - useful when you want to wire your own sampler onto the upscaled latent, which is what you'll do for anything with extra conditioning (a stacked ControlNet pass, a masked regional re-sample). The pack has four other KSampler variants for exactly that.
Installing it
Nothing in the Sampling category needs extra Python packages.
cd ComfyUI/custom_nodes/
git clone https://github.com/TensorVizion/OmniNodes
# restart ComfyUI, then search the node menu for "Latent Upscale (Hires Fix)"
It lands under TensorVizion/Sampling. The terminal shows [OmniNodes] β
Loaded per file on startup - if the node doesn't appear, that log line and its absence is your first clue.
Where people get burned
If resample is True but model, positive or negative isn't connected, the node does not error. It quietly returns the upscaled-only latent and tells you about the missing inputs in the summary string. If your image looks like a soft first pass with no added detail, read that string before you blame the sampler.
The other one is the seed. This is a real seed INT with the usual control_after_generate attached, and it defaults to 0 - fixed. Randomize the seed on your first-pass sampler and leave this one alone, and every refine pass in the batch uses the same noise. If you've ever been bitten by ComfyUI's seed widget firing after the run, this is another place to check.
Two honest limits. A typo'd sampler_name or scheduler (both free-text fields here, not dropdowns) won't be caught until sampling runs. And this node is step two of the generative rung - it adds detail; it can't clean up a compressed JPEG or repair a face. For the pixels-only job, follow with a plain 4x ESRGAN pass at the end. Generative detail first, cheap interpolator last, is the order that actually looks good.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| samples | LATENT | β | |
| upscale_method | COMBO | 5 options: nearest-exact, bilinear, area, bicubic, bislerp | |
| scale_by | FLOAT | 1.500.01β8 | β |
| resample | BOOLEAN | true | β |
| modelopt | MODEL | β | |
| positiveopt | CONDITIONING | β | |
| negativeopt | CONDITIONING | β | |
| seedopt | INT | 00β18446744073709550000 | β |
| stepsopt | INT | 201β10000 | β |
| cfgopt | FLOAT | 7.00β100 | β |
| sampler_nameopt | STRING | dpmpp_2m | β |
| scheduleropt | STRING | karras | β |
| denoiseopt | FLOAT | 0.500β1 | β |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | β |
| summary | STRING | β |