Surface Dust Mask
Surface Dust Mask builds the grime without the tedium
- image
- source_mask
- mask
- image
- mask
- dust_info
The last 10% of a weathered prop is always dust, and the last 10% of that is sitting in places you'd rather not paint by hand - on top surfaces, in the creases, where the object actually rests against the world. x1SurfaceDustMask reads your texture and hands you a dust-accumulation mask, complete with natural breakup, without you touching a brush. It's part of a whole family of surface-weathering nodes in the MKRShift pack, and it's the one you start with when a material needs to look like it's been sitting somewhere.
How it works
It scores every pixel for "would dust collect here," then normalizes that into a mask. The key insight is that dust follows geometry: top_bias (0.52) steers the mask toward upward-facing, light/flat regions where dust settles, while cavity_bias (0.44) pulls in the darker creases and recesses where dust gets trapped. The source_mode (combined_dust by default) blends the image's luma, color, and detail signals into that score - switch to a plain channel if your texture has an unusual tell.
Two knobs make it look like real dust rather than a smooth gradient. breakup (0.30) adds organic, noisy variation so the mask isn't a clean blob - dust never distributes evenly. coverage (0.54) is the threshold slider: it decides how much of the surface the dust actually claims. amount (0.82) is how strong the whole effect is, and contrast (1.20) + gamma (1.0) shape the mask's response curve.
The inputs that matter
Settings live in a settings_json string, prefilled when the node drops:
top_bias(0.52) - how much dust favors upward-facing geometry.cavity_bias(0.44) - how much dust favors crevices. In practice these two are the "what kind of dust" control.breakup(0.30) - the natural variation. Zero gives you a sterile gradient; too high turns it to static.amount(0.82) /coverage(0.54) - overall strength and how much surface it claims.invert_values- flip to get a clean mask instead (dust-free regions), useful for layering.
The optional source_mask restricts which pixels are analyzed (so a background doesn't register as a dusty surface), and mask feathers the output. Outputs are image, mask (the dust mask, ready to wire into a roughness map, a blend, or an overlay), and dust_info (settings + coverage log).
Installing it
Part of the MKRShift Nodes pack. ComfyUI Manager: search "MKRShift", install, restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes
Restart after. No models - numpy math on the texture, CPU-friendly.
Gotchas
The honest caveat: on a flat, uniform texture the node has very little signal to work with, and you'll get a mask that's mostly breakup noise. Feed it a texture with some luma/detail contrast, or combine it with a slope or cavity mask from the pack (x1SlopeMaskFromNormal) to supply the geometry it can't see from albedo alone. That combo - slope/cavity for structure, this node for the dust itself - is the real workflow. And as always with these MKRShift nodes: valid JSON in settings_json, or it silently falls back to defaults.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| settings_json | STRING | {"source_mode":"combined_dust","top_bias":0.52,"cavity_bias":0.44,"breakup":0.3,"amount":0.82,"coverage":0.54,"contrast":1.2,"gamma":1.0,"blur_radius":1.2,"invert_values":false,"mask_feather":8.0,"invert_mask":false} | — |
| source_maskopt | MASK | — | |
| maskopt | MASK | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| dust_info | STRING | — |