Nodes/ComfyUI-NKD-Basic-Tools/😺NKD Normal Detail
ComfyUI Node

😺NKD Normal Detail

Normal maps from Marigold have no pores — this node reads them off the photo

By Nekodificador·Created 2 months ago·Updated a day ago· 124
😺NKD Normal Detail
  • normals
  • image
  • mask
  • normals
  • detail
â—„resolutionimageâ–º
â—„amount1.00â–º
â—„blendReorientedâ–º
â—„fine_radius2â–º
â—„fine_strength4.0â–º
â—„medium_radius8â–º
â—„medium_strength2.0â–º
â—„noise_reduction0â–º
â—„flip_detail_yfalseâ–º

The pores are gone, and you know exactly who took them

Run an image through Marigold Normals, DSINE or NormalBEA and you get a beautiful map of the big shapes - cheekbone, nose, brow - and absolutely no skin. Pores, stubble, single hairs: smoothed into one surface, because a net trained to estimate orientation optimizes for the shape it can be confident about. That's the "beauty filter" tell the community has been complaining about since 2023, one layer deeper in the pipeline. And if that map is going into a relight, a ControlNet normals pass or Blender, the flatness comes along for the ride.

The obvious fix is to derive normals from the photo directly. Don't - luminance is not height. A freckle becomes a dent, a specular highlight becomes a bump, and the photo's lighting turns into fake relief. 😺NKD Normal Detail takes the sane version: base map keeps the shape, photo supplies only the frequency that is micro-detail, and the two get combined the way normal maps are supposed to be.

How it actually works

The photo's luminance gets high-passed per band - luminance − gaussian(luminance, radius) - so the medium and broad shading never enters. Each band is differentiated with a Scharr kernel (better rotational symmetry than Sobel, same cost), then run through tanh as a soft clip. That last bit matters: a hair against a bright background is a monstrous gradient, and without the clip it would flatten the base map underneath it.

The resulting (nx, ny, 1) gets normalized into the detail map, then blended onto the base by one of three methods:

  • Reoriented (default): rotates the detail into the base's tangent frame, Barré-Brisebois & Hill style. A pore on the jaw tilts with the jaw - correct on slopes, which is why it's the default.
  • UDN: just add the XY and keep the base's depth. Cheap, and noticeably flatter on steep areas.
  • Overlay: the per-channel Photoshop blend, there so you can compare against a hand-built ImageBlend chain rather than because you want it.

Both the base and the detail are re-normalized, because resizing shortens unit vectors and flat bands are what you get if you skip that.

The inputs that matter

  • normals / image - the base map and the photo. They don't have to be the same size.
  • resolution - image (default) works at the photo's size, normals at the base's with the photo downscaled. Radii are in pixels of that working size, so this setting changes what radius 2 means.
  • fine_radius / fine_strength - pores and stubble (2px, strength 4). medium_radius / medium_strength - wrinkles, hair locks, fabric weave (8px, 2). Set a radius to 0 to switch that band off, and the pack's JS hides the matching strength widget.
  • amount - 0 hands the base back byte-for-byte, which makes it a safe bypass when you're A/B-ing.
  • blend, noise_reduction (blur the photo first if grain or JPEG blocks are becoming bumps), flip_detail_y if your base is DirectX, and an optional mask to confine the detail, feathered by its values.

Outputs are normals (the blended map) and detail (the micro-detail alone). The node previews the blended result in-node; wire detail to a Preview Image while you tune radii - it's the only way to see what each band is grabbing without the base in the way. Note the Y flip only affects the detail: the base passes through untouched.

Install

It ships in NKD Basic Tools, which is on the ComfyUI registry - search NKD Basic Tools in ComfyUI Manager and install, or:

cd ComfyUI/custom_nodes
git clone https://github.com/Nekodificador/ComfyUI-NKD-Basic-Tools

Restart ComfyUI. There's no requirements.txt; the pack's declared dependencies are onnxruntime and huggingface_hub, and those are for the Face Rig / Face Crop side. Normal Detail is pure torch and downloads nothing - no model files, no checkpoint.

The author is worth knowing: Nekodificador is a working retoucher and VFX artist who ships these as extensions of the tools he builds for studios, and the pack's r/comfyui release posts pull 130–270 upvotes. This is a craft pack, not a weekend experiment.

Where people get burned

Aspect mismatch. If the normals and the photo are cropped differently, you get a console warning and detail that doesn't line up. Fix the crop upstream rather than resizing here.

Cranking the strengths. The soft clip and the normalization mean you need a fairly large fine strength before detail reads at all, so beginners pile on medium_strength too and get sandpaper. Tune the fine band against the detail output first.

Grain. Denoised AI images still carry grain; at radius 2 that grain is signal. noise_reduction of 1–2 fixes it and costs you the finest pores - worth it. Downstream, an image-space resize or sharpen breaks unit length and flattens the map, so do your scaling before this node.

Brightness-as-height, one last time. On skin and hair the approximation is invisible. On a printed pattern, a tattoo or a logo, a dark area reads as a groove and it will not. The mask input exists for exactly this.

Green channel convention. If your base is DirectX-style (+Y down), tick flip_detail_y - otherwise your new pores are lit from the wrong side and the whole thing reads as embossed.

Category😺NKD Nodes/Basic

Inputs (12)

NameTypeDefaultDescription
normalsIMAGEThe base normal map (Marigold, DSINE, any tangent-space map).
imageIMAGEThe photo the micro-detail is read from.
resolutionCOMBOimageimage: output at the photo's size — the base is upscaled and the detail is read at full resolution, where the pores live. normals: output at the base's size, photo downscaled. Radii are in pixels of this working size.
amountFLOAT1.000–2How much detail lands on the base. 0 = base untouched.
blendCOMBOReorientedReoriented rotates the detail onto the base's surface (correct on slopes). UDN is the cheap sum. Overlay is the per-channel Photoshop blend, for comparison.
fine_radiusINT20–32Size of the finest detail in pixels (pores, stubble). 0 turns the band off.
fine_strengthFLOAT4.00–20Slope strength of the fine band.
medium_radiusINT80–128Size of the medium detail in pixels (wrinkles, hair locks, fabric). 0 turns the band off.
medium_strengthFLOAT2.00–20Slope strength of the medium band.
noise_reductionINT00–8Blur the photo before reading detail, so grain and compression do not become bumps.
flip_detail_yBOOLEANfalseInvert the detail's green channel for a DirectX-style base (+Y down).
maskoptMASKOptional — confine the detail to the mask, feathered by its values.

Outputs (2)

NameTypeDescription
normalsIMAGEThe base with the detail blended in.
detailIMAGEThe micro-detail normal on its own — preview it to tune the radii.