Nodes/ComfyUI-NKD-VFX-Tools/😺NKD Projection Pass
ComfyUI Node

😺NKD Projection Pass

One inpainted view, one cable, nothing lined up by hand

By Nekodificador·Created 7 months ago·Updated a day ago· 176
😺NKD Projection Pass
  • image
  • camera_info
  • silhouette
  • mask
  • mask3d
  • projection
â—„weight1.00â–º
â—„feather8â–º
â—„silhouette_erode4â–º
â—„mirrornoneâ–º

Here's the move this node exists for. Your image-to-3D model dumped out a mesh - good silhouette, machine-made UVs, and a texture that looks like a photocopied sticker. You want the text on the label to actually say something, or the face to have an eye that isn't mush. So you render the model from one angle, inpaint that render, and project the edit back onto the geometry from the same camera. No UV editing, no lining anything up by hand.

That loop is the one Stable Projectorz and hunzmusic's Hunyuan3DTools popularised. NKD Projection Pass doesn't render anything itself - 😺NKD Preview 3D does that - and it doesn't merge anything, that's 😺NKD Bake Projection. It's the middle step: it takes one edited view plus the camera it came from and packages them into a single cable. One of these per angle.

That packaging is the whole design argument. The usual way to do projection painting is an accumulator: every run blends the new view on top of whatever's already on the texture, so what you end up with depends on what order you painted in - a good early view gets buried under a mediocre later one, and changing your blend settings means starting over. Batching every view into one merge at the end kills that. Same inputs, same result, every time, and ComfyUI's cache still works because the node is a pure function.

What you actually wire

camera_info is the camera from the 😺NKD Preview 3D that rendered this exact view, and it has to be the same Preview 3D with nothing moved in between. image is the inpainted render. Resolution can differ from the render; the projection is normalised. The framing can't - don't reframe the inpaint.

Then two inputs that the docs beg you to wire, and they're right:

  • silhouette - the mask output of that same Preview 3D. Where the render has model at all. Skip it and a surface that projects just off the edge of the model, or onto a hole in it, gets painted with the backdrop colour. And don't substitute Load3D's mask output - that one isn't a silhouette.
  • mask - normally the same mask you inpainted with. Skip it and the entire view projects, so every pass overwrites good texels with re-rendered ones instead of accumulating retouches.

The rest are knobs. weight is this pass's say in the blend (0 mutes it without unwiring). feather softens the mask inwards - it blurs and then clips back to the hard mask, so the falloff never spills onto geometry you didn't paint. silhouette_erode pulls the silhouette edge in a few pixels, default 4, because edge pixels are a model/backdrop blend sitting exactly where the surface is most edge-on and least trustworthy.

mirror (none/X/Y/Z) is the sleeper: it also paints the view across the model's symmetry plane in the model's own space, so one side view can do both headlights. Leave it at none for a frontal view - that one already covers both sides, and mirroring just doubles it. mask3d is a mask painted on the model in Preview 3D's pencil mode, and it means something different from mask: the 2D mask says where in the picture you may project, mask3d says which geometry may receive it, wherever those pixels land. It's what stops the skin of a face getting printed onto the shoulders behind it.

The single output, projection, is an NKD_PROJ - a package, not an image. Fan each one into a slot on 😺NKD Bake Projection.

Install

Manager, search NKD VFX Tools, install, restart. Or by hand:

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

Nothing to download. The pack's pyproject.toml declares numpy, which you already have, and everything else ships with ComfyUI. Work the graph as one group per view - Preview 3D, inpaint, Projection Pass - then duplicate it for the next angle. Ctrl+M on a group is the per-view switch: a slot fed by a muted group is skipped rather than breaking the bake.

Where people get burned

The mask-edge smudge. Pass a hard-edged inpaint mask with feather at 0 and you get a visible seam where the projection stops; raise it and the edge fades instead.

The mask3d mismatch is a hard error, not a soft one - bake it against a different mesh than it was painted on and you get paint it on the same mesh you bake. That's a feature, not a bug.

And the boring one: if camera_info didn't come from the viewport that rendered this view, nothing lands where you expect. Re-render and re-inpaint.

Category😺NKD Nodes/3D

Inputs (9)

NameTypeDefaultDescription
imageIMAGEThe edited view. Same framing as the render that produced camera_info. Resolution may differ, the projection is normalised.
camera_infoLOAD3D_CAMERAcamera_info from the 😺NKD Preview 3D that rendered this view.
weightFLOAT1.000–10Multiplies this pass's say in the merge. 0 mutes it without unwiring.
featherINT80–256Softens the mask inwards, so the blend never reaches surface you did not paint.
silhouetteoptMASKWhere the render has model at all: the `mask` output of the same 😺NKD Preview 3D. Wire it. Without it a surface that projects just off the model, or onto a gap in it, is painted with the backdrop.
silhouette_erodeoptINT40–64Pulls the silhouette in by this many pixels. Its edge pixels are a blend of model and backdrop, and they sit where the surface is most edge on, which is where a projection is least trustworthy.
maskoptMASKWhere this pass is allowed to paint, normally the same mask you inpainted with. Without one the whole view projects, which overwrites good texels with re-rendered ones.
mask3doptNKD_MASK3DThe geometry this view may paint: a mask painted on the model in 😺NKD Preview 3D. The 2D mask says where in the picture; this says what receives it, wherever the pixels land. Same mesh as the bake.
mirroroptCOMBOnoneAlso paint across the model's symmetry plane, in its own space: X mirrors left and right. For a SIDE view, so one pass does both headlights or carries the near side of a head to the far side. Leave a frontal view at none: it already covers both sides.

Outputs (1)

NameTypeDescription
projectionNKD_PROJ—