VR Face Unrectify
Put the swapped VR faces back — distortion and all
- patches
- rectify_map
- image
VR Face Rectify gave you flat patches to swap. This node is what makes the result look like it was never flat. VR Face Unrectify takes the swapped patch batch from your face swapper plus the VR_RECTIFY_MAP that Rectify produced, projects each swapped patch back into its exact original frame, eye, and position, and composites it onto the untouched source frames.
It's the second half of the pair, and it has exactly one job: make the swap disappear back into the lens distortion instead of floating on top of it. If you've ever seen a face swap that looks "stuck on," that's what skipping this step looks like in VR.
How it works
Every patch Rectify cut has a corresponding entry in the map - which frame it came from, which eye (L/R/T/B/M), which projection, the yaw/pitch it was viewed from, and the patch geometry. Unrectify walks those entries in order and does the inverse projection (p2e, or fisheye_p2e for fisheye sources) to bend each swapped patch back into the shape that lens originally imposed, then alpha-composites it into place.
Two implementation details are worth knowing because they explain the behavior you'll see:
- The reprojection is windowed - it only processes the eye sub-region the patch actually covers, so cost tracks the face footprint rather than the whole frame. Big 4K SBS batches stay reasonable.
- If no faces were found at rectify time, the map is empty and the frames pass through byte-for-byte unchanged. The node degrades gracefully instead of crashing.
Like its partner, the geometry runs on torch (GPU) when available and falls back to numpy/cv2 otherwise; the node logs which backend it used.
Inputs and outputs
Both inputs are required, and both come from the same run of the pipeline:
- patches - the swapped patch batch, straight from ReActor (or whatever swapper you're running).
- rectify_map - the
VR_RECTIFY_MAPfrom VR Face Rectify. Same wire, same run.
Output is a single image: the composited frames, same batch shape as the originals, ready to be saved or fed back into a video-encode path.
The gotcha: batch order is sacred
Unrectify matches patches[i] to map entry i, so the swapper must preserve the batch order and count it received. If it doesn't - if a swapper drops frames, re-sorts them, or is set to process one image per run - you'll get a hard error:
VR Face Unrectify: N patches expected from the map but only M arrived; the swapper must preserve batch order/count
That error is the friendly version. The unfriendly version is subtle: if the swapper reorders instead of dropping, you get a face composited into the wrong spot with no complaint at all. Practical rules:
- Run the whole batch through Rectify → swapper → Unrectify in one shot; don't split or shuffle in between.
- Use a swapper with batch support (ReActor handles batches) and keep its batch settings aligned with what Rectify emitted.
- Both the map and the patches come from the same Rectify run - rewire the pair together if you change any rectify settings, or the geometry won't match the patches.
Installing and troubleshooting
cd ComfyUI/custom_nodes && git clone https://github.com/zyquon/ComfyUI-Stash
or search "Stash" in ComfyUI Manager and restart. No extra model downloads - the pack's deps are just pillow/numpy/requests, and the face detection side already ran upstream in Rectify. If you're hitting the count mismatch error, the fix is almost always on the swapper side: batch order in, batch order out. And if everything "works" but the faces look wrong, check that input_layout and projection on the Rectify node match the actual source footage - the unrectify can only faithfully undo what rectify actually did.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| patches | IMAGE | Swapped patch batch from ReActor | |
| rectify_map | VR_RECTIFY_MAP | From VR Face Rectify |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |