Upscale to Resolution (Multi-Pass)
Hit a target resolution, not a guess multiplier
- image
- image
- scale_per_pass
- final_width
- final_height
- total_scale
- info
Sometimes "4x" is the wrong way to ask. What you actually want is "this texture needs to be 2048×2048 because that's what the game's material budget says." Scale-based upscaling makes you do the arithmetic; UpscaleToResolution does it for you, then hands you the per-pass scale factors for a multi-pass chain.
It's the resolution-targeting sibling of the pack's UpscaleCalculator. Same family, same DNA: it doesn't resample anything itself. The image output is a passthrough - the node's real output is a set of numbers you feed into your actual upscaler nodes. But it answers the question you actually ask: "my map is 1024×1024, my target is 2048, how should I set up a two-pass 4x chain?"
How it works
Given a target width/height and your upscaler's native multiplier, it computes the total scale needed, then splits it across the passes with the same scale_per_pass = target_scale^(1/passes) / upscaler_multiplier math the Calculator uses. The maintain_aspect toggle matters a lot here:
- ON (default) - it uses the smaller of the width/height scale factors so the result fits inside your target box without distortion. Your output may be a bit under 2048 on one axis, and the node tells you so in the console.
- OFF - it averages the width and height scales and warns you when the two diverge, because that's how you get a stretched texture. Most of the time you don't want this.
It also sanity-checks the plan: if your target is bigger than input × upscaler_multiplier^passes, it warns that the target may be unreachable and suggests more passes or a bigger multiplier. Nice touch - that's the "your chain can't physically get there" case that usually bites people silently.
The inputs
- target_width / target_height (64–16384) - where you want to land.
- upscaler_multiplier (1–8) - your upscaler's native scale.
- number_of_passes (1–10) - how many upscalers are in the chain.
- maintain_aspect - keep the shape or not.
Outputs: image (passthrough), scale_per_pass, final_width, final_height, total_scale (the overall multiplier the math landed on), and info (a STRING summary).
Installing it
UpscaleToResolution is part of ComfyUI-TextureAlchemy. ComfyUI Manager → search "Texture Alchemy" → install → restart. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/amtarr/ComfyUI-TextureAlchemy
# restart ComfyUI
No extra dependencies, no models - pure PyTorch. Under Add Node → Texture Alchemist → Texture. (The README's copy-the-ComfyUI_PBR_MaterialProcessor-folder line is a pre-rebrand leftover; ignore it.)
Where people get burned
Two habits to avoid. First, assuming the node upscales - it doesn't, so if you wire its image output straight to Save Image you'll get your input back unchanged and think it's broken. Second, leaving maintain_aspect on and then being surprised the output isn't exactly your target box - that's the feature, not a bug; it's the price of not squashing the texture. For texture work this "more pixels, faithfully" framing is exactly right: you don't want a generative upscaler inventing grain on a normal or roughness map, you want a correctly-sized resample chain, and this node is the calculator for building it.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| target_width | INT | 204864–16384 | Desired final width in pixels |
| target_height | INT | 204864–16384 | Desired final height in pixels |
| upscaler_multiplier | FLOAT | 4.01–8 | The multiplier of each upscaler (e.g., 4.0 for 4× upscaler) |
| number_of_passes | INT | 21–10 | How many upscalers will be chained |
| maintain_aspect | BOOLEAN | true | Maintain original aspect ratio (scale to fit within target dimensions) |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| scale_per_pass | FLOAT | — |
| final_width | INT | — |
| final_height | INT | — |
| total_scale | FLOAT | — |
| info | STRING | — |