Nodes/MKRShift_Nodes/Specular Map
ComfyUI Node

Specular Map

Specular Map derives it from the albedo

By criskb·Created 7 months ago·Updated 5 months ago· 0
Specular Map
  • image
  • source_mask
  • mask
  • image
  • mask
  • specular_info
settings_json{"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}

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_specular is usually right; switch to detail or mask when 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.

CategoryMKRShift Nodes/Surface/Maps

Inputs (4)

NameTypeDefaultDescription
imageIMAGE
settings_jsonSTRING{"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_maskoptMASK
maskoptMASK

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
specular_infoSTRING