Nodes/ComfyUI-CustomNodePacks/Control AOV — Multi-Control Fusion (C2C)
ComfyUI Node

Control AOV — Multi-Control Fusion (C2C)

One node, every ControlNet pass you need — depth, canny, pose, normal, motion, and an ID matte, fused for a union control

By Code2Collapse·Created 6 months ago·Updated a day ago· 52
Control AOV — Multi-Control Fusion (C2C)
  • image
  • depth
  • canny
  • pose
  • normal
  • id_matte
  • blended
  • combined
  • channel_packed
  • depth
  • canny
  • pose
  • normal
  • motion
  • id_matte
  • info
blend_modescreen
preview_layouthorizontal_3
depth_modeloff
normal_modeloff
depth_sizesmall
depth_custom_ckpt
pose_modeloff
id_matte_modeloff
edge_modelinternal_canny
run_cannytrue
canny_low100
canny_high200
canny_aperture3
depth_invertfalse
preproc_resolution512
run_motionfalse
depth_weight1.00
canny_weight1.00
pose_weight1.00
normal_weight0.00
match_tolargest

ControlNet changed everything about local generation, and the modern version of the game is stacking conditions - depth for spatial layout, canny for edges, pose for structure, normal for surface, motion for video, an ID matte for identity. That's normally a chain of separate preprocessor packs. ControlAOVC2C collapses it into one node that emits every pass at once, plus a channel-packed image (depth=R, canny=G, pose=B) designed for union ControlNets, plus a preview blend. It's the "all the AOVs, in one stop" node of the C2C Control suite.

The mental model is VFX render passes. In a 3D pipeline you render depth, normals, and ID as separate "arbitrary output variables" and recombine them in comp. This node does the same for ControlNet conditioning: each pass comes out of its own output, so you can feed them to separate ControlNets and stack them for maximum spatial lock, or use the convenience outputs to feed a single union control.

How it works

The node is a fusion hub with two philosophies of preprocessing. Canny and optical-flow motion run internally - OpenCV Canny (no model) and optical flow on your frame batch. Everything else is either vendored (runs inside the pack: DepthAnything v1/v2/v3, MiDaS, Depth Pro, DepthCrafter, NormalCrafter, ViTPose) or delegated to comfyui_controlnet_aux (the depth_anything_*, dwpose, openpose, hed, lineart options). You pick per-pass: leave a pass off and wire in an external map (from your own depth node, a SAM matte, whatever) - the node treats those as passthrough AOVs. Weights per pass (0–2) let you tune how hard each condition bites.

The inputs that matter

  • image - source frames; preprocessors run on these.
  • depth_model / normal_model / pose_model / id_matte_model / edge_model - per-pass backends, mostly off by default so you wire in what you need.
  • run_canny + canny_low / canny_high (100/200) - the internal edge pass.
  • run_motion - optical-flow pass, needs ≥2 frames.
  • preproc_resolution (512) - resolution handed to delegated preprocessors.
  • depth_invert - flip near/far when your source convention doesn't match the ControlNet's.
  • The weight inputs (depth_weight, canny_weight, pose_weight, normal_weight).

Outputs: blended, combined (side-by-side/grid preview), channel_packed, and the separate depth, canny, pose, normal, motion, id_matte passes, plus an info string describing per-pass status.

Installing it

Part of Code2Collapse/ComfyUI-CustomNodePacks. ComfyUI Manager → search "CustomNodePacks", or:

cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git

Be ready for model downloads: the vendored depth/normal/pose backends pull weights from HuggingFace on first use, and the delegated options need comfyui_controlnet_aux installed. This is the heaviest node in the pack.

Gotchas

First: the delegated options quietly depend on another pack (comfyui_controlnet_aux) - if you pick dwpose or lineart without it, expect a missing-module error. Prefer the vendored backends to stay self-contained. Second, run_motion needs at least two frames or it has nothing to compute - wire a video batch, not a single image. Third, depth_invert matters more than people think: a "far=bright" depth source fed to a ControlNet expecting "near=bright" gives you inverted spatial cues and garbage structure. And finally, the combined preview is for your eyes, not the model - for actual conditioning use the separate passes or channel_packed, not the pretty blend.

CategoryC2C/Control

Inputs (27)

NameTypeDefaultDescription
blend_modeCOMBOscreenHow the 'blended' overlay combines passes. screen = least-destructive; linear_dodge clips; multiply darkens.
preview_layoutCOMBOhorizontal_3Layout for the 'combined' output: horizontal_3 = depth | pose | canny; grid_2x2 = depth|pose // canny|original.
imageoptIMAGESource frames — preprocessors below run on this.
depth_modeloptCOMBOoffDepth backend. VENDORED (self-contained, run inside this pack): da_v2/da_v1/midas (transformers), da3 (Depth-Anything-3), depth_pro, depthcrafter (video). The depth_anything_* options delegate to comfyui_controlnet_aux instead. 'off' = wire an external depth map.
normal_modeloptCOMBOoffNormal backend (vendored): sobel_from_depth (no model) or normalcrafter (video). 'off' = wire an external normal map.
depth_sizeoptCOMBOsmallDepthAnything backbone: small=ViT-S (fastest, test default) → giant=ViT-G (best). v1 has no giant (falls back to large). Ignored by metric/zoe.
depth_custom_ckptoptSTRINGCustom DepthAnything .pth filename in the controlnet_aux model dir — overrides depth_size when set (your own fine-tuned weights).
pose_modeloptCOMBOoffPose backend. vitpose = WanV2 ViTPose chain (uses models/detection/*.onnx). dwpose/openpose/... delegate to comfyui_controlnet_aux.
id_matte_modeloptCOMBOoffID/segmentation matte. sam_auto = automatic SAM segmentation (controlnet_aux SAMPreprocessor). 'off' = wire an external matte.
edge_modeloptCOMBOinternal_cannyinternal_canny = OpenCV (no model). Others delegate to controlnet_aux.
run_cannyoptBOOLEANtrueUsed only when edge_model = internal_canny.
canny_lowoptINT1000–255
canny_highoptINT2000–255
canny_apertureoptCOMBO3Sobel aperture for internal Canny (odd 3/5/7).
depth_invertoptBOOLEANfalseInvert depth (1 - depth). Use when source is 'far=bright' but the ControlNet expects 'near=bright'.
preproc_resolutionoptINT51264–4096Resolution passed to delegated preprocessors.
run_motionoptBOOLEANfalseOptical-flow motion-vector pass (needs an image batch ≥ 2 frames).
depthoptIMAGEDepth map (DepthAnything/DepthCrafter/ZoeDepth).
cannyoptIMAGEExternal edge map; overrides internal Canny if provided.
poseoptIMAGEPose render (DWPose/OpenPose/ViTPose).
normaloptIMAGESurface normals (NormalCrafter).
id_matteoptIMAGESegmentation/ID matte (SAM/cryptomatte-style).
depth_weightoptFLOAT1.000–2
canny_weightoptFLOAT1.000–2
pose_weightoptFLOAT1.000–2
normal_weightoptFLOAT0.000–2
match_tooptCOMBOlargest5 options: depth, canny, pose, image, largest

Outputs (10)

NameTypeDescription
blendedIMAGESingle image, all passes OVERLAID via the chosen blend mode.
combinedIMAGESingle image, depth | pose | canny shown SIDE-BY-SIDE (or grid) — the clearest 'all 3 at once' view.
channel_packedIMAGEdepth=R, canny=G, pose=B — lossless packing for union ControlNets.
depthIMAGEDepth AOV (passthrough).
cannyIMAGECanny AOV (run internally if 'image' wired).
poseIMAGEPose AOV (passthrough).
normalIMAGENormal AOV (passthrough).
motionIMAGEMotion-vector AOV (optical flow, run internally on a frame batch).
id_matteIMAGEID / segmentation matte AOV (passthrough).
infoSTRINGPer-pass STATUS + recommended max-control wiring.