Nodes/DepthDiff/DepthDiff
ComfyUI Node

DepthDiff

Tell the sampler how much to change each pixel — depth-driven Differential Diffusion in one node

By spiritform·Created about a month ago·Updated 29 days ago· 1
DepthDiff
  • model
  • image
  • vae
  • mask
  • model
  • latent
  • mask
depth_modefalse
depth_ckptdepth_anything_v2_vitl_fp32.safetensors
depth_max_size1024
inverttrue
input_black0
input_white255
gamma1.00
brightness0.00
contrast1.00
image_blur0
mask_blur0
strength1.00
diff_diffusion_multiplier1.00

Regular img2img gives you one global dial: a denoise value that applies to the whole frame. Crank it and your subject changes but so does your background; drop it and nothing moves. Differential Diffusion is the upgrade - every pixel gets its own dial, so you can keep the sky while repainting the ground, or swap an outfit while leaving the face alone. DepthDiff is the whole technique squeezed into a single ComfyUI node.

What it actually does

The mask is everything. DepthDiff builds a grayscale mask from your input image, then uses it two ways at once: it patches the model and it attaches the mask to the latent. Where the mask is bright, the sampler re-noises that region hard; where it's dark, those pixels are essentially frozen. Default is invert = true, so dark regions get more diffusion, bright regions get preserved - flip it to reverse. The name isn't the full story: by default the mask comes from luma (brightness), which is great for relighting-style edits where you keep the highlights. Turn on depth_mode and it runs Depth Anything V2 first, so the mask comes from scene geometry instead - near objects re-drawn, far objects kept.

How the mechanism works

Differential Diffusion (Chen et al., arXiv 2306.00950 - the "give each pixel its strength" paper) runs entirely at inference, no training. DepthDiff implements it via ComfyUI's set_model_denoise_mask_function patch. Each sampling step, the patch computes how far through denoising you are and re-noises only pixels where mask × multiplier is above that threshold. Early steps have a high threshold, so only the strongest mask regions get touched; as sampling progresses the threshold falls and more of the image gradually comes in. Net effect: mask value = edit strength, from "don't touch" to "full renoise." That's the difference between a hard binary inpainting mask and the soft, gradient-driven result that makes seamless edits work.

The node is unusually self-contained. It VAE-encodes your image internally, so there's no separate Encode node. In depth_mode it downsizes to depth_max_size (default 1024 long side) for the depth pass, then upscales the map back - a nice touch that keeps VRAM sane. It even saves a preview of the mask and shows it in the UI, a godsend when you're dialing in levels.

Inputs that matter

You feed it model, image, and vae - that's it for the plumbing. The widgets you'll actually touch:

  • invert - defaults true. Dark = more diffusion. Get this backwards and you'll wonder why your edits target the wrong thing.
  • input_black / input_white - levels remap on the mask, in 0–255. Your first move when the mask is too washed out or too dark.
  • gamma, brightness, contrast - tone shaping. Brightness is additive, gamma is a power curve; gamma is usually the one that feels right.
  • strength - clips the whole mask down; effectively a global "how aggressive" knob.
  • diff_diffusion_multiplier - a second global dial, 1.0 default, >1 more aggressive, <1 more preservation. Think strength = mask gain, this = sampler-side throttle.
  • The optional mask input gates the whole thing - handy if you want depth-driven diffusion only inside a region you already have.

Outputs

All three matter: model (the patched model), latent (with the noise mask attached), and mask (the raw mask, in case you want to feed it somewhere else). Wire model and latent into your KSampler and you're done.

Install

Via ComfyUI Manager: search DepthDiff and hit Install. Or:

cd ComfyUI/custom_nodes
git clone https://github.com/spiritform/Comfy-DepthDiff.git

Then restart ComfyUI. The core node has zero Python dependencies - it runs out of the box. The catch: depth_mode requires Kijai's comfyui-depthanythingv2 pack too (Manager: search "DepthAnythingV2"), and the V2 weights auto-download to ComfyUI/models/depthanything/ on first use. The dropdown offers VIT-S/B/L plus the Giant, each in fp16/fp32. To just test, skip depth_mode entirely: feed the node any image (a precomputed depth map or a luma render works) and it never touches the depth dependency. Stick with VIT-L, the community daily driver, unless you have headroom - the Giant is the quality ceiling but it's slow and OOMs on modest VRAM.

Where people get burned

Running depth_mode without Kijai's pack raises a clear RuntimeError - it won't silently degrade, so you'll know. The subtler trap is invert. On a photo with a bright subject on a dark background, the defaults preserve the subject and re-paint the background - often exactly backwards for a portrait edit. Check the preview mask before you burn a batch. And remember this is a soft edit by design: near-black regions aren't untouched, just barely touched. If you want a hard boundary, drop the blur to 0 and use the optional mask input as the gate.

Categoryconditioning/depthdiff

Inputs (17)

NameTypeDefaultDescription
modelMODEL
imageIMAGE
vaeVAE
depth_modeBOOLEANfalse
depth_ckptCOMBOdepth_anything_v2_vitl_fp32.safetensors7 options: depth_anything_v2_vitl_fp32.safetensors, depth_anything_v2_vitl_fp16.safetensors, depth_anything_v2_vitb_fp32.safetensors, depth_anything_v2_vitb_fp16.safetensors, depth_anything_v2_vits_fp32.safetensors, depth_anything_v2_vits_fp16.safetensors, +1
depth_max_sizeINT1024256–4096
invertBOOLEANtrue
input_blackFLOAT00–255
input_whiteFLOAT2550–255
gammaFLOAT1.000.1–5
brightnessFLOAT0.00-1–1
contrastFLOAT1.000–4
image_blurINT00–128
mask_blurINT00–128
strengthFLOAT1.000–1
diff_diffusion_multiplierFLOAT1.000–10
maskoptMASK

Outputs (3)

NameTypeDescription
modelMODEL
latentLATENT
maskMASK