Specular Map
Specular Map derives it from the albedo
- image
- source_mask
- mask
- image
- mask
- specular_info
Most texture sets you get from AI or photo scans are albedo-only - color, no idea where the material actually reflects. Painted specular maps are the old-school manual fix, and they're a pain. x1SpecularMap derives one straight from the diffuse image: it looks at where the image is bright and desaturated, where the material reads as glossy, and hands you a specular/reflection mask you can wire into a PBR pack or a renderer without opening a paint program.
How it works
The core assumption is that specularity leaves traces in a diffuse image: glossy surfaces show compressed, bright, low-saturation highlights, while matte surfaces read darker and more saturated. The node combines several signals to score every pixel: brightness, saturation, and high-frequency detail, weighted by source_mode (the combined_specular default blends them; you can also drive it from a single channel like value, luma, detail, or mask if your image has a particular tell).
detail_radius (2.0) and detail_strength (0.35) pull in fine micro-highlight variation - the difference between "polished plastic" and "machined metal sparkle." saturation_suppress (0.75) deliberately pushes color out of the map, because a specular map is about how strongly a surface reflects, not what color it is. Then normalize_mode (auto_percentile by default) stretches the result across the usable range, and gamma (0.75) + contrast (1.25) shape the final response curve - note the gamma is below 1.0 by default, which lifts the midtones so reflections don't vanish in the middle of the range.
The inputs that matter
This one takes a settings_json string (prefilled with sensible defaults) rather than a wall of widgets:
source_mode-combined_specularis usually right; switch todetailormaskwhen the albedo is flat but the micro-structure carries the reflectivity.saturation_suppress(0.75) - how hard to strip color. Crank toward 1.0 for a clean grayscale map.gamma(0.75) - the midtone lift. This is the knob that decides whether your map is "everything slightly reflective" or "only the bright spots."invert_values- flip it if you want a diffuse/matte map instead (the same signal, inverted), which some renderers' packing expects.
The optional source_mask restricts which pixels get analyzed (so the background doesn't read as glossy), and mask feathers the final output. Outputs are image (the map, previewable), mask (the same scalar as a MASK for wiring), and specular_info (settings + the normalize range it found).
Installing it
It ships in the MKRShift Nodes pack, so install the pack. ComfyUI Manager: search "MKRShift", install, restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes
Restart after. No models - pure numpy math on the diffuse, runs on CPU.
Gotchas
The honest limit: a specular map derived from albedo is an estimate. A pure albedo can't tell you a surface is mirror-finish if nothing in the image is bright - a matte black leather and a glossy black plastic might read identically. Use this to bootstrap a map from a good photo or an AI texture, then expect to push gamma and maybe paint a few highlights if the material is important. It slots naturally into the pack's x1PBRPack for a full map set, and it's dramatically better than leaving specular at a flat white constant.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| settings_json | STRING | {"source_mode":"combined_specular","normalize_mode":"auto_percentile","value_min":0.0,"value_max":1.0,"percentile_low":2.0,"percentile_high":98.0,"detail_radius":2.0,"detail_strength":0.35,"saturation_suppress":0.75,"gamma":0.75,"contrast":1.25,"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 | — |
| specular_info | STRING | — |