BD Derive PBR Maps
Fake a full PBR set from one image + depth
- image
- depth
- normal_map
- silhouette_mask
- aux_shading_alpha
- aux_detail_texture
- metallic_zone_mask
- albedo
- normal
- roughness
- metallic
- ao
- packed_orm
- packed_arm
- status
You've got a single stylized character image and you want it to light correctly in a game engine. BD Derive PBR Maps is the node that gets you from "one picture" to "albedo, normal, roughness, metallic, and AO, plus pre-packed ORM/ARM" without any 3D baking. It's heuristic - explicitly not a measurement - which sounds like a caveat and is actually the whole point: it's the fastest way to give a background character believable material response, and it's honest about where you should hand-tune.
How it works
Everything derives from the two required inputs: image and depth (from any IMAGE-typed estimator - DepthAnythingV2, Lotus, MiDaS, Metric3D; darker = closer is the convention here). The recipe:
- Roughness - high-frequency detail in the image (busy areas get rougher) via
roughness_mode(defaultcombined), boosted by optional line art / detail texture throughdetail_to_roughness. - Metallic -
metallic_modedefaults tooff(flatmetallic_default), butlow_sat_high_lumcatches bright, desaturated metal candidates (gold, chrome) withmetallic_lum_threshold/metallic_sat_threshold. Restrict where metal can appear with metallic_zone_mask - the README's recommended pipeline feeds an accessories mask in here so only the buckle and zips go metallic. - AO - from depth gradients (
ao_strength,ao_blur). - Normal - derived from depth gradients unless you supply an explicit normal_map (Metric3D-NormalMapPreprocessor is the recommended source), scaled by
normal_strength.
Then the outputs: albedo, normal, roughness, metallic, ao, plus packed_orm and packed_arm (AO/roughness/metallic stacked into the R/G/B channels the way Unreal and Unity like them), and status.
The two optional inputs that take it from "meh" to "good enough"
- silhouette_mask (white = subject) - multiplies everything so background pixels don't pollute the maps and, crucially, keeps transparent-PNG edge garbage out.
albedo_treatment(defaultedge_pad) extends foreground colors into the transparent border so you don't get halo bleed at UV seams. - aux_shading_alpha - this is the secret weapon for stylized art. Feed it the alpha output of a shading pass (like the pack's skin-details GLSL shader: low alpha = highlights, high alpha = shaded zones) and shaded areas get +roughness, +AO, −metallic, and highlights get the opposite. The README says this is far more accurate than the image-only heuristic, and it's right.
Installing and wiring
ComfyUI Manager → search "BrainDead" → install, or clone + pip:
cd ComfyUI/custom_nodes
git clone https://github.com/BizaNator/ComfyUI-BrainDead
cd ComfyUI-BrainDead
pip install -r requirements.txt
Restart, then wire: character image → depth estimator → this node, with silhouette + shading alpha if you have them. The pack's own example runs all seven outputs into BD Bulk Save with one save-context so you get albedo/normal/roughness/metallic/ao/orm/arm files in a single run.
Where people get burned
The README is refreshingly blunt: these are heuristics for background characters - for hero assets you hand-tune downstream. People also forget that metallic_mode is off by default, so their "metal" reads as rough paint until they flip it on and feed a metallic_zone_mask. And if your normal map looks wrong, wire an explicit normal_map instead of arguing with normal_strength.
Inputs (24)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Source character/object image. Used for roughness (high-freq detail) and metallic (low-sat / high-lum heuristic) and as albedo passthrough. | |
| depth | IMAGE | Depth map IMAGE from upstream estimator (DepthAnythingV2 / Lotus / MiDaS / Metric3D — all output IMAGE type). Closer surfaces darker by convention. Used for AO (cavity detection) and normal (when no explicit normal_map provided). | |
| normal_mapopt | IMAGE | Optional explicit normal map IMAGE (e.g. from Metric3D-NormalMapPreprocessor or BAE-NormalMapPreprocessor). When provided, used directly. When NOT provided, normals are derived from the depth map's gradients. | |
| silhouette_maskopt | MASK | Optional character/object silhouette MASK (white = subject, black = background). Multiplies all output maps so background pixels are zeroed in roughness/metallic, set to 1.0 in AO (no occlusion outside subject), and set to neutral (0.5, 0.5, 1.0) in normal map. Source: BiRefNetRMBG, BodySegment, or your existing skin/body chain. | |
| aux_shading_alphaopt | MASK | Optional shading alpha map — e.g. the alpha output of your skin_details GLSL shader, where low alpha = highlights, high alpha = shaded zones. When provided: shaded areas get +roughness +AO -metallic; highlights get the opposite. This is FAR more accurate than the image-only heuristic for stylized art. | |
| aux_detail_textureopt | IMAGE | Optional surface detail texture (lineart, manga lines, surface bumps). When provided, edge-detected lines boost roughness — useful for stylized character art where line detail represents real surface variation. | |
| invert_shading_alphaopt | BOOLEAN | false | Set True if your shading alpha uses the opposite convention (low alpha = shaded, high alpha = highlight). |
| shading_to_roughnessopt | FLOAT | 0.400–2 | How much shaded areas (high alpha) add to roughness. 0 = ignore shading for roughness; 0.4 = moderate boost; 1.0+ = strong (shaded → fully rough). |
| shading_to_aoopt | FLOAT | 0.500–2 | How much shading darkens AO (multiplicatively combined with depth-based AO). 0 = ignore; 0.5 = moderate; 1.0 = full (deeply shaded → near-black AO). |
| detail_to_roughnessopt | FLOAT | 0.500–2 | How much detail texture lines boost roughness. Lines = surface detail = rougher. 0 = ignore; 0.5 = moderate; >1 = strong line emphasis. |
| depth_sharpenopt | FLOAT | 0.00–3 | Unsharp mask the depth map before AO/normal derivation. Useful when your depth estimator (Lotus, Metric3D) gives smooth/chunky depth. 0 = no sharpen, 0.5-1.0 = moderate edge enhancement, 2-3 = aggressive. |
| roughness_modeopt | COMBO | combined | high_freq_detail: Laplacian magnitude → busy areas rougher (good for stylized art). luminance_inverted: bright = smooth, dark = rough (works for photo-lit subjects). combined: average of both. off: skip (output uses roughness_default). |
| roughness_defaultopt | FLOAT | 0.500–1 | Used when roughness_mode=off, or as a baseline blended with the heuristic. |
| roughness_strengthopt | FLOAT | 1.000–2 | Multiplier on the computed roughness map. <1 makes everything smoother, >1 boosts roughness contrast. |
| metallic_modeopt | COMBO | off | off: outputs metallic_default everywhere (typically 0). low_sat_high_lum: detect metallic candidates by bright + desaturated pixels. STRONGLY recommend wiring metallic_zone_mask too — heuristic alone gets false positives on bright skin/white cloth. With zone_mask=clothing+accessories, the heuristic becomes useful (bright desaturated pixels INSIDE clothing/accessories = metal candidates). |
| metallic_zone_maskopt | MASK | Optional MASK restricting where metallic CAN occur. Multiplies the metallic output, so only pixels inside the zone can be metal. Wire your clothing or accessories mask here (from a SAM3 'accessories,jewelry,metal' prompt, ClothesSegment, MaskResolver, etc.) — most game-character metal lives on jewelry/buckles/armor/details which align with the accessories category. Without this, metallic detection fires everywhere and produces false positives. | |
| metallic_defaultopt | FLOAT | 0.000–1 | Constant metallic value used everywhere when metallic_mode=off. |
| metallic_lum_thresholdopt | FLOAT | 0.600–1 | Luminance above this counts toward metallic (when metallic_mode=low_sat_high_lum). |
| metallic_sat_thresholdopt | FLOAT | 0.200–1 | Saturation below this counts toward metallic (when metallic_mode=low_sat_high_lum). |
| ao_strengthopt | FLOAT | 0.700–2 | How much the depth gradients affect AO. 0 = pure white AO (no occlusion), 1 = full strength, >1 = exaggerated. AO is OUTPUT WHITE = no occlusion, DARK = occluded (Unreal/Unity convention). |
| ao_bluropt | FLOAT | 2.00–20 | Gaussian blur radius for depth before computing gradients. Higher = softer AO. |
| normal_strengthopt | FLOAT | 2.00.1–10 | Strength multiplier when deriving normals from depth. Higher = more pronounced normals. Only used when normal_map is NOT provided. |
| albedo_treatmentopt | COMBO | edge_pad | How to clean up the albedo output (was passing input through raw, which leaked transparent-area garbage colors as halo). edge_pad — extend foreground colors outward into background using Voronoi nearest-neighbor (game-engine standard 'alpha bleed'). Prevents UV edge halos. Requires silhouette_mask. silhouette_clip — multiply by silhouette_mask (background goes to black). Quick but causes black halos at UV edges in-engine. passthrough — original behavior (use input RGB as-is). |
| albedo_edge_pad_pixelsopt | INT | 320–512 | When albedo_treatment=edge_pad: how far to extend foreground colors into transparent area. 0 = unlimited (pad everywhere — slow on huge images), 16-32 = typical for game textures, 64+ = aggressive. |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| albedo | IMAGE | — |
| normal | IMAGE | — |
| roughness | MASK | — |
| metallic | MASK | — |
| ao | MASK | — |
| packed_orm | IMAGE | — |
| packed_arm | IMAGE | — |
| status | STRING | — |