Realistic Bokeh / Depth of Field (advanced)
Bokeh that does the lens math, not just the blur
- image
- depth_map
- focus_mask
- image
- coc_map
- focus_preview
Most depth-of-field nodes blur by depth and call it a day. Realistic Bokeh / Depth of Field (advanced), from ComfyUI-RealisticBokeh, is the one that does the optics: you give it a lens - f-stop, focal length, sensor size, focus distance - and it computes a real circle of confusion for every pixel. That's why an f/1.4 portrait lens and an f/8 landscape lens on the same image come out looking like different photographs. It's the bigger sibling of the pack's Easy Bokeh node, and the answer when "subject sharp, background soft" isn't specific enough for what you're chasing.
What makes it look real
The physics you actually get, from the pack's own documentation and source:
- Linear-light processing - blur sums light energy rather than gamma-encoded values, which is how real lenses behave.
- Highlight bloom - fakes the HDR a clipped 0–1 image lost, so bright out-of-focus points become glowing bokeh balls instead of grey mush. This is the single biggest realism win.
- A physical circle of confusion from
f_stop,focal_length_mm,sensor_width_mmand focus distance. Wider aperture and longer lens ⇒ shallower DOF, exactly like real life. - Depth-layered occlusion compositing - a blurred foreground bleeds over the in-focus subject, the thing cheap blur always gets backwards.
- Shaped apertures - disk, polygon (aperture blades with
bladesandblade_curvature), anamorphic (vertical oval viaanamorphic_ratio), star, heart, and ring (the mirror-lens donut). Convolution runs as FFTs on the GPU.
The inputs that matter
The plumbing is image + depth_map (resized automatically - depth from Depth Anything, MiDaS or any depth preprocessor). Then three outputs: image, plus coc_map (grayscale; black = in focus) and focus_preview (your image with the sharp region tinted green). Preview that last one - it's the fastest sanity check.
For beginners the set that does 90% of the work:
- focus_mode - set to
point(default) and putfocus_x/focus_yon your subject. The node reads the depth at that point, so this is "tap to focus" and it's immune to whether your depth map is inverted.maskfocuses on the median depth inside a connectedfocus_mask; theauto: nearest / farthest / centeroptions are self-explanatory, though nearest/farthest do depend ondepth_invertbeing right.manualis the fiddly old raw-slider way. - focus_range - the "subject won't go sharp" knob. A real fast lens has a focal plane millimetres deep, so only one slice of the subject is sharp and even the rest of a face blurs. That's physically correct and rarely what you want. Raise
focus_range(a 0–1 band around the focus that stays fully sharp) until the green covers the subject - 0.2–0.5 is the usual landing zone. - f_stop and focal_length_mm - the lens. Lower f-stop / longer focal length = stronger blur.
sensor_width_mmdefaults to 36 (full frame); ~24 is APS-C.blur_scaleis a master multiplier on top if you just want more or less. - blur_model -
physical(the real CoC math) orartistic(the normalised depth-distance model the Easy node uses; more forgiving, less authentic).
Realism extras are all optional toggles: highlight_bloom (on by default - bloom_gain brightens the balls, bloom_threshold sets which highlights bloom), chromatic_aberration colour fringing, and catseye optical vignetting (bokeh squashes toward the frame edges like a real lens). Note catseye uses spatially-varying tiled convolution and is noticeably slower - catseye_grid is the quality knob.
The gotchas that will cost you an hour
Depth direction first. If focus lands on the wrong plane, toggle depth_invert - that's the single most common fix. The default is off, but many common depth maps (including, per the README, the usual Depth Anything/MiDaS output) have the subject bright and the background dark, which wants it on. In point mode the node reads the depth right at your focus point so it can't miss the plane entirely - but auto: nearest/farthest and the foreground-occlusion edges genuinely need depth_invert correct.
Second: razor-thin DOF is not a bug. If "the face is half blurry," don't fight the f-stop - that's a real 85mm f/1.4 rendering. Raise focus_range.
Third: speed. Cost scales with quality_layers (the number of depth slices - 10–16 is the sweet spot, higher = smoother but slower) and max_blur_px. For previews drop quality_layers to ~6 and disable catseye.
Install
ComfyUI Manager, search ComfyUI-RealisticBokeh, or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/marcsole96/ComfyUI-RealisticBokeh.git
Restart ComfyUI. No extra runtime dependencies - everything runs on the torch ComfyUI already ships. It lands under image/postprocessing.
Which node when
Use Easy Bokeh for "sharp subject, soft background" - it's the same engine with the physics hidden. Come here for the anamorphic oval, the mirror-lens ring, an honest f/1.4 falloff, or for matching a specific shot's look. The extra knobs pay off exactly as much as you're willing to tune them.
Inputs (39)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| depth_map | IMAGE | — | |
| bokeh_shape | COMBO | disk | 6 options: disk, polygon, anamorphic, star, heart, ring |
| focus_mode | COMBO | point | 6 options: manual, point, mask, auto: nearest, auto: farthest, auto: center |
| focus_depth | FLOAT | 0.5000–1 | — |
| focus_range | FLOAT | 0.150–1 | — |
| focus_transition | FLOAT | 0.100.001–1 | — |
| f_stop | FLOAT | 2.80.7–32 | — |
| focal_length_mm | FLOAT | 508–600 | — |
| sensor_width_mm | FLOAT | 36.04–70 | — |
| blur_scale | FLOAT | 1.000–8 | — |
| max_blur_px | INT | 481–200 | — |
| quality_layers | INT | 121–48 | — |
| blur_modelopt | COMBO | physical | 2 options: physical, artistic |
| focus_spreadopt | FLOAT | 1.000.1–4 | — |
| focus_maskopt | MASK | — | |
| focus_xopt | FLOAT | 0.5000–1 | — |
| focus_yopt | FLOAT | 0.5000–1 | — |
| depth_invertopt | BOOLEAN | false | — |
| depth_modeopt | COMBO | inverse (disparity) | 2 options: linear, inverse (disparity) |
| near_distance_mopt | FLOAT | 0.300.05–100 | — |
| far_distance_mopt | FLOAT | 20.00.2–1000 | — |
| linear_lightopt | BOOLEAN | true | — |
| highlight_bloomopt | BOOLEAN | true | — |
| bloom_thresholdopt | FLOAT | 0.750–1 | — |
| bloom_gainopt | FLOAT | 4.00–30 | — |
| edge_weightopt | FLOAT | 0.00-1–1 | — |
| bladesopt | INT | 63–12 | — |
| blade_curvatureopt | FLOAT | 0.000–1 | — |
| shape_rotationopt | FLOAT | 00–360 | — |
| anamorphic_ratioopt | FLOAT | 2.001–4 | — |
| star_pointsopt | INT | 53–12 | — |
| star_depthopt | FLOAT | 0.450.1–0.95 | — |
| ring_thicknessopt | FLOAT | 0.350.05–1 | — |
| chromatic_aberrationopt | BOOLEAN | false | — |
| ca_amountopt | FLOAT | 0.300–1 | — |
| catseyeopt | BOOLEAN | false | — |
| catseye_strengthopt | FLOAT | 0.600–1.5 | — |
| catseye_gridopt | INT | 42–10 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| coc_map | IMAGE | — |
| focus_preview | IMAGE | — |