Cavity Map
The crease detail your PBR set is missing
- image
- source_mask
- mask
- image
- mask
- cavity_info
A cavity map is the short-range cousin of ambient occlusion - it catches the fine detail, the tight creases and pores, that wide-radius AO smears away. x1CavityMap extracts that detail from an albedo, grayscale, height-like, or mask input, and it's one of the handiest derivations in MKRShift Nodes' Surface/Maps branch. The author's own docs sum up the positioning neatly: it's tighter and more detail-focused than x1AOFromHeight.
The pack overall is young (no impressions, no community chatter I could find), but these map nodes are its most self-consistent section - each one is a "derive a scalar, normalize it, mask it" pipeline that feeds the same downstream pack nodes, so once you've used one, the rest feel familiar.
How it works
Three steps, straight from the author's docs: sample a grayscale source from the chosen channel or mask, compare each pixel against a blurred local average, and extract the difference as your cavity signal. polarity picks what you keep - concave favors dark creases (the classic cavity/dirt response), convex favors bright ridges, and both gives unsigned micro-detail. radius (default 2.5) sets the neighborhood size for the comparison, so it stays short-range by design. Then the usual shaping controls - normalize_mode, gamma, contrast - turn the raw signal into a usable map.
Outputs: image (grayscale map as an image), mask (the scalar map itself), and cavity_info (resolved settings + the normalization range used).
What it's for
The author's list is the right list: a roughness driver (creases read rougher), a wear mask seed (dirt collects in cavities), or an extra channel into x1PBRPack. It's also a nice fast sanity-check on a generated heightmap before you commit to baking.
Inputs that matter
polarity-concaveis the default and the one you'll reach for first;bothis there when you want unsigned detailradius- keep it small; this node's whole point is short-rangecontrast(default 1.35) - the main "how punchy is the detail" knobsource_mode-lumais the sane default; the other channels are for when the creases live in a specific color channel
Installing
ComfyUI Manager → search MKRShift Nodes, or:
cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes
Restart ComfyUI. No model downloads, no new Python deps.
Where people get burned
- Using it where you want AO.
x1AOFromHeightis the broad contact-shadow node;x1CavityMapis the fine-detail one. People reach for cavity first because it's impressive, then wonder why the broad occlusion is missing. They're a pair, not replacements. - The
maskoutput is the derived cavity scalar - the optionalmaskinput (withmask_feather) only gates where the output is emitted. Pack-wise, don't wire the output mask back into the input mask expecting a loop to work. - A corrupted
settings_jsonsilently falls back to defaults, so if your map suddenly goes generic, that's the first suspect.
Feed it a decent albedo and it'll hand you a roughness/wear channel in a second. That's the whole pitch.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| settings_json | STRING | {"source_mode":"luma","polarity":"concave","normalize_mode":"auto_percentile","value_min":0.0,"value_max":1.0,"percentile_low":2.0,"percentile_high":98.0,"radius":2.5,"gamma":1.0,"contrast":1.35,"blur_radius":0.0,"invert_values":false,"mask_feather":8.0,"invert_mask":false} | — |
| source_maskopt | MASK | — | |
| maskopt | MASK | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| cavity_info | STRING | — |