Normal Map Normalize
Your normal map looks flat and grey — the Z channel is lying to you
- image
- IMAGE
A tangent-space normal map stores its X and Y components in the red and green channels and derives Z (blue) from them: z = sqrt(1 - x² - y²). The trick is that most tools write X and Y and then just... approximate the blue channel. Photoshop filters, some exporters, even hand-touched maps. The result is a normal map whose vectors aren't unit length, and the renderer shades it wrong - flat, washed-out, or with lighting that doesn't match the bumps. Normal Map Normalize throws out the bad Z and rebuilds it from X and Y, so every pixel is a properly normalized vector again.
You reach for it after anything that shouldn't touch a normal map but did: blending two maps together, running it through a resample, or trusting a generator that ships a sloppy Z. The tell is lighting that looks "off" in a way you can't quite pin down. Run it through this node, and if that fixes it, the Z channel was your culprit.
How it works
The node maps image values (0–1) into vector space (−1 to 1), keeps your red and green channels untouched, computes z = sqrt(1 - x² - y²) per pixel, and maps the result back to an image. The only real decision is what to do with that freshly computed Z:
- Recalculate (Standard) - maps Z into the 0.5–1.0 range, which is what standard tangent-space normal maps expect. This is the one you want 95% of the time.
- Recalculate (0-1 Range) - same math, but outputs the raw Z (0–1). Use it when your shader or tool chain expects unmapped values, which some exporters do.
- Set to 0 / 0.5 / 1 - forces Z to a fixed value. These are debugging tools: force Z and the map becomes flat shading, which is a fast way to confirm which channel is breaking your lighting.
Inputs and output
Only two inputs: image (the normal map) and output_z (the five-choice enum above). One output, an IMAGE with your corrected normal map, ready to plug into the normal input of your material, a ControlNet normal preprocessor chain, or the pack's other normal tools.
If you're using this for a ControlNet normal workflow rather than game assets, the same rules apply - normalize before the model sees it and you get cleaner conditioning, though honestly most well-made normal maps won't need it.
Install
Leputen Utils is lilquail's Windows-oriented game-dev texture toolkit. Install with ComfyUI Manager (search "ComfyUI-Leputen-Utils") or:
cd ComfyUI/custom_nodes
git clone https://github.com/lilquail/ComfyUI-Leputen-Utils
Restart ComfyUI. This node is pure torch math - it doesn't touch the pack's DeepBump, DDS, or ONNX machinery, so you don't need any of the optional GPU bits for it.
Where people get burned
The wrong output_z choice is the classic trap. If you pick "Recalculate (0-1 Range)" for a map your engine expects in the standard 0.5–1 range, you've just made the lighting worse. When in doubt, try both and compare the render. And don't treat this as a fix-everything button: it only corrects Z, so if your X and Y channels are themselves garbage (a badly compressed map, for instance), normalizing just makes tidy garbage.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | The input normal map to be normalized. | |
| output_z | COMBO | Recalculate (Standard) | How to set the Blue (Z) channel. 'Recalculate' derives Z from X/Y for valid normals. Fixed values useful for specific shaders. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |