AO Approximator
Ambient occlusion without a 3D scene
- height
- normal
- ao
Ambient occlusion - the darkening in corners, crevices, and anywhere geometry traps light - is one of those maps that's easy to want and annoying to get. Real AO is baked by ray-tracing a 3D model. If all you have is a flat texture with a height map, you can't bake. AO Approximator is the cheat: it fakes AO from your height and normal maps in pure torch, no 3D scene required.
It's not a substitute for a proper engine bake on a hero asset - nobody's pretending a 2D approximation beats real geometry. But for game textures, quick materials, or when you need a roughness/AO set without opening Blender, it produces a perfectly serviceable occlusion map.
How it works
The core algorithm is a height-sampling approximation. It picks samples (default 16) directions around each pixel, steps radius pixels out in each direction, and compares the sampled height against the center. Wherever the neighbor is higher than the center, that direction is occluded. More directions and a larger radius both mean softer, broader occlusion; fewer samples are faster but can leave visible artifacts. The collected occlusion is scaled by strength and pushed through a contrast pass.
Then the normal map refines it. If you connect a normal and keep use_normal on, the node biases the AO with surface orientation - upward-facing surfaces get less occlusion, steeper faces get more, which is the part that makes the result read as 3D rather than as a blurry copy of the height map.
The inputs
radius(1–64, default 8) - sample distance in pixels. 8–16 is the typical zone.strength(0–3, default 1) - overall AO intensity.samples(4–64, default 16) - quality vs. speed. 16 is a good default; drop to 8 for drafts.contrast(0–3, default 1) - punch up or soften the result.use_normal(default on) - use the normal map for the orientation bias.heightandnormal- both optional, but the magic happens when you feed both. Height alone works; normal alone produces a cruder orientation-based AO.
Output: ao - a grayscale IMAGE where white is fully lit and black is fully occluded (the standard convention).
Two things to know
The pack's README explicitly recommends feeding both height and normal at 24–32 samples for the best quality, and the cost is worth it on a 2K texture. And if you feed neither height nor normal, the node doesn't error - it returns a flat 0.7 gray with a warning. That's the "I forgot to connect anything" failure mode; it'll silently pass a featureless map down the graph, so check your wires if your AO suddenly looks like a blank fill.
Installation
Part of amtarr/ComfyUI-TextureAlchemy, under Add Node → Texture Alchemist → Maps. Install via ComfyUI Manager (search "TextureAlchemy") or:
cd ComfyUI/custom_nodes
git clone https://github.com/amtarr/ComfyUI-TextureAlchemy
Restart ComfyUI. No dependencies - it's torch math over the maps you already have.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| radius | INT | 81–64 | Sampling radius in pixels (larger = broader occlusion) |
| strength | FLOAT | 1.000–3 | AO intensity multiplier |
| samples | INT | 164–64 | Number of sampling directions (more = better quality, slower) |
| contrast | FLOAT | 1.000–3 | Contrast adjustment for AO |
| use_normal | BOOLEAN | true | Use normal map to improve AO quality (if provided) |
| heightopt | IMAGE | — | |
| normalopt | IMAGE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| ao | IMAGE | — |