Normal Map Combiner
Layering Normal Maps the Right Way (Stop Using Linear Blends)
- base_normal
- detail_normal
- combined_normal
Normal maps don't add like regular images. If you've ever stacked a detail normal onto a base normal with a plain mix or lerp node and gotten a mushy, half-baked result, that's why - the vectors fight each other instead of combining. Normal Map Combiner is the node from TextureAlchemy that does this properly, and once you've seen the difference you'll stop reaching for the blend node.
The use case is straightforward: you have a base normal map (from Lotus, from a photo, from a previous procedural pass) and you want to graft micro-detail onto it - cracks, fabric weave, surface noise - without destroying the base. This is the same operation game engines call "detail normal blending," and it's a daily chore if you're building PBR material sets from AI outputs. The pack's own pitch for the node is "add micro-detail to base normals," and that's exactly what it does.
How it works
Normal maps store surface direction, not color, so the math has to stay in vector space. The node decodes both inputs from 0-1 color space to -1/1 vector space, combines them, re-normalizes to unit length, and packs back to color. You pick the algorithm:
- reoriented (default) - Reoriented Normal Mapping (RNM), the most accurate method and the one that holds up at steep angles. This is the same technique referenced in the classic SelfShadow "Blending in Detail" writeup.
- whiteout - the fast UDN/Unreal blend. Industry-standard and near-identical quality for most uses; this is what a lot of game engines use under the hood.
- linear - a straight interpolation. The README is honest about it: simple, and "not recommended." It's there so you can see why you shouldn't.
The detail_strength slider (0-2) doesn't just fade the detail - it lerps the detail map toward neutral (0.5, 0.5, 1.0) first, so lowering it adds less detail rather than washing out toward a flat average. That's the detail people usually want.
Inputs and outputs that matter
Two images in, one image out. The ones you'll actually touch:
- blend_mode - leave on
reorientedunless you have a reason; drop towhiteoutif you want the same result marginally faster. - detail_strength - 0.5-0.8 for subtle texture, 1.0+ when the detail pass should be obvious.
The output is combined_normal, which drops straight into the normal input of a PBR Combiner, or into a preview/saver for inspection.
One convenience baked in: if the two inputs have different resolutions, the node resizes the detail map to match the base before blending, and it only needs three-channel RGB inputs - no alpha handling to trip over.
Installing it
It ships in the TextureAlchemy pack. Easiest path is ComfyUI Manager (search "TextureAlchemy"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/amtarr/ComfyUI-TextureAlchemy
Then restart ComfyUI. No pip requirements, no model downloads - this node runs on pure PyTorch and only ever sees the images you feed it.
Common issues
The classic gotcha is a green-channel mismatch: if your base is DirectX-flipped and your detail is OpenGL (or vice versa), the combined map will look wrong in a renderer even though it looks fine in the preview. Make sure both inputs are the same format before blending. And if the result looks flat or weak, don't blame the node - check that you're feeding it a real normal map (roughly (0.5, 0.5, 1) average) and not a height map that someone forgot to convert.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| base_normal | IMAGE | — | |
| detail_normal | IMAGE | — | |
| blend_mode | COMBO | reoriented | Blending algorithm: Reoriented (best), Whiteout (fast), Linear (simple) |
| detail_strength | FLOAT | 1.000–2 | Strength of the detail normal map |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| combined_normal | IMAGE | — |