All Resources

R-43

Film Making

From Flat to Film-Ready: Extracting a Full CG/VFX Layer Stack from AI-Generated 4K Video

One flat AI-generated 4K clip in; depth, normals, optical flow and mattes out — a Nuke-ready layer stack, synthesised entirely on a desk-side DGX Spark with no cloud.

PAR2 Labs

August 22, 2026

12 min

From Flat to Film-Ready: Extracting a Full CG/VFX Layer Stack from AI-Generated 4K Video

AI video generators output a flattened image — no depth pass, no camera, no mattes underneath. VFX and CG pipelines need those layers. We built an on-device pipeline on an NVIDIA DGX Spark that synthesises the missing passes with four neural models and delivers them as frame-aligned 4K OpenEXRs. One 361-frame clip in, five production layers out, roughly 47 GB, ready to drop onto a Nuke timeline.

01

The problem: generative video is a photograph, not a render

When a renderer produces a frame, it also produces the scene behind it — a depth (Z) pass, surface normals, motion vectors, object IDs, a camera. Compositors live on those layers: depth for atmosphere and defocus, normals for relighting, motion vectors for retimes and motion blur, mattes for isolation.

An AI-generated clip has none of that. It is a flattened, graded, compressed delivery image with no geometry, no camera and no mattes underneath it. If you want to do real CG/VFX work on top of generative footage, you have to reconstruct those layers.

That is the whole game here: not recovery, but principled inference — synthesise each pass with a purpose-built model, then treat it as if it were a render output, while being honest about where inference is not measurement.

02

What we built

From one clip — 3840×2160, 10-bit 4:2:0, 24 fps, 361 frames — we produced five frame-aligned layers. Everything is numbered 001001–001361 and 1:1 frame-aligned, so all five drop onto one timeline with no conform.

LayerModelChannelsWhat it is for
Plate— (colour pipeline)RGB (scene-linear)The beauty / background
DepthVideo Depth Anything (ViT-L)ZDOF, fog, depth grades, matte assist
NormalsMarigold-Normalsnormal.X / Y / ZRelighting, specular reshaping
Optical flowRAFT-Largeforward/backward.U/V + flow_confidence.ARetimes, motion blur, temporal work
MattesSAM 2.1 (Hiera-Large)ASubject isolation, holdouts, region grades

Every EXR uses standard layer.component naming — depth.Z, normal.X, forward.U — so Nuke's Read node exposes them as pickable layers automatically.

03

The hardware: a supercomputer on the desk

The entire pipeline ran on an NVIDIA DGX Spark — a GB10 Grace-Blackwell machine with 128 GB of unified memory on an ARM64 Ubuntu 24.04 base. Two things make it the right tool.

Unified memory: 4K neural inference is memory-hungry, and 128 GB shared between CPU and GPU meant we could hold a 361-frame video session (SAM 2), a diffusion pipeline (Marigold) and an optical-flow model in memory at once — and even run two at a time. On-device: no footage leaves the building, no per-minute cloud GPU bill, and the iteration loop is a local SSH away.

04

The pipeline: order is a dependency, not a preference

The key rule is that grain and compression blocking destroy inference models, so they come out first. An edge-directed model cannot tell a compression block from real detail — clean the plate, then infer.

LAYER EXTRACTION — CLEAN FIRST, THEN INFER IN PARALLELPlate reconstructioncrop · range-expand · ACEScgShot detectioncut list · per-shot from hereDegrain + grain platenoise poisons every modelDeband / bit-depthdegrain unmasks bandingDepthVDA ViT-LNormalsMarigoldOptical flowRAFT-LargeMattes / IDsSAM 2.1RUN IN PARALLEL ON THE CLEAN PLATECamera solve → Position → STMapoptional · AI footage resists solversEXR packagingnamed channels · per-pass compressionBack to 4K / DCPNuke-ready deliveryGRAIN AND COMPRESSION BLOCKING COME OUT BEFORE ANY MODEL SEES THE FRAME

Fig 1 — the order is a dependency chain, not a preference. Degrain precedes deband because degraining unmasks banding that was previously hidden under noise.

Not recovery, but principled inference — synthesise each pass, then be honest about where inference is not measurement.

05

Layer by layer

Four models, each doing one job on the cleaned plate. The caveats below are stated deliberately — every one of them changes how a compositor should use the pass.

01

Depth

  • TOOL

    Video Depth Anything (ViT-L)

  • USE

    Video variant, not per-frame estimation

  • GET

    Single-channel float Z

Run the video model across the whole shot rather than estimating each frame independently. Output is a single-channel float Z pass, normalised per shot.

Why: Per-frame estimation flickers, and flicker in a depth pass becomes boiling in every downstream defocus and atmosphere effect. Stated loudly: this is relative inverse depth, normalised per shot — not scene units. Superb for cueing and matte work; it is not geometry.

02

Normals

  • TOOL

    Marigold-Normals

  • USE

    Diffusion model estimating surface orientation directly

  • GET

    normal.X / Y / Z in [-1, 1]

Estimate normals directly rather than differentiating the depth pass. Document the convention alongside the delivery — camera-space, +Y up.

Why: Differentiating depth amplifies noise; direct estimation does not. And a relight lit from the wrong side is almost always a flipped axis, which is why the convention goes in the README rather than in someone's head.

03

Optical flow

  • TOOL

    RAFT-Large

  • USE

    Forward and backward flow, per shot

  • GET

    forward/backward.U/V + flow_confidence.A

Compute both forward and backward flow in pixels, plus a forward/backward-consistency confidence channel so compositors can gate occlusions. Run per shot.

Why: Flow across a cut is meaningless. The confidence channel is what lets a compositor trust the vectors where they agree and mask them where they do not.

04

Mattes

  • TOOL

    SAM 2.1 (Hiera-Large)

  • USE

    Prompt on frame 0, propagate through the shot

  • GET

    Soft alpha A

Prompt the subject on frame 0 with a bounding box plus interior points, then let SAM 2's video model propagate the matte through all 361 frames. One prompt, tracked object, whole clip.

Why: Video propagation holds the identity of the object across the shot in a way per-frame segmentation does not, which is the difference between a matte and 361 unrelated masks.

06

The war stories

This is the part people leave out of the glossy version, and it is where the real engineering was.

W1

A locked-down network

  • TOOL

    Sneakernet over the relay

  • USE

    Fetch on a connected PC, push to the box

  • GET

    Models and weights on device

The Spark could reach PyPI and Hugging Face's API, but GitHub, NVIDIA NGC and Hugging Face's weight CDN were all blocked. Model code and multi-gigabyte weights simply would not download on the box, so everything was fetched on an internet-connected PC and pushed over.

Why: Assuming the target has the same network as your laptop is the fastest way to lose a day. Establish what the box can actually reach before planning the install.

W2

Resumable chunked transfer

  • TOOL

    64–128 MB chunks with per-chunk retry

  • USE

    Skip-if-present, reassemble, hash-verify

  • GET

    Transfers that finish

The only link was a Tailscale connection through a relay — flaky, dropping SSH every few minutes. A naïve 1.5 GB copy never finished. Every payload was split into 64–128 MB chunks, each transferred with retry and skip-if-already-there, then reassembled and hash-verified on the far side.

Why: A dropped chunk costs seconds instead of the whole file. Over an unreliable link, resumability is worth more than raw throughput.

W3

Half-float to halve the wire

  • TOOL

    16-bit half EXR

  • USE

    Convert on the Spark before transfer

  • GET

    ~50% less data over a slow link

The return trip — normals plus flow — was roughly 40 GB of float32 EXR. Converting to 16-bit half on the Spark first cut that roughly in half before it ever hit the slow link.

Why: There is no meaningful quality loss for these passes at half precision, and the transfer time saved is real. Convert where the compute is, not where the bandwidth is.

W4

Concurrent GPU orchestration

  • TOOL

    128 GB unified memory

  • USE

    Overlap transfer-bound and compute-bound work

  • GET

    Two models resident at once

Depth transfer, flow inference and normals inference ran overlapping, with jobs sequenced so nothing contended for the GPU while transfers used only network and disk.

Why: The bottleneck alternates between GPU, network and disk. Scheduling against that rather than running strictly in series is where the wall-clock saving comes from.

W5

The one-line model bug

  • TOOL

    SAM 2 video propagator

  • USE

    start_frame_idx, and a better prompt

  • GET

    A matte of the whole figure

SAM 2's video propagator refused to start until the prompted frame was processed first (start_frame_idx). And the first matte prompt — two centre points — segmented only the folded forearms, not the figure. Switching to a bounding box plus head, torso and lap points captured the whole seated body cleanly.

Why: Small fixes, big difference — and the kind you only find by looking at every frame rather than at a contact sheet.

07

Results

Five layers × 361 frames of 4K OpenEXR, frame-aligned, with named channels. Roughly 47 GB delivered, organised one folder per layer with a README and QC previews. Depth inference took about 350 seconds for the full clip at native 4K; mattes about five minutes, propagated across the whole shot. All verified frame by frame.

MeasureResult
Source1 clip · 3840×2160 · 10-bit 4:2:0 · 24 fps · 361 frames (15 s)
Delivered5 layers × 361 frames · 4K OpenEXR · ~47 GB
Depth inference~350 s for the full clip at native 4K
Matte propagation~5 min across every frame from one prompt
HardwareNVIDIA DGX Spark · GB10 Grace-Blackwell · 128 GB unified · ARM64
Cloud usedNone. No footage left the building

08

Honest limits

These are inferred passes on generative footage, and that combination has real edges. Say them before the artist discovers them.

Where inference is not measurement

01

Depth and normals can drift shot-to-shot and boil in motion — judge in motion, at scale, before building shots on them.

02

Generative video often has no consistent underlying camera, so a solve may not hold. Treat depth as a region selector, not geometry.

03

The 4:2:0, low-bit origin is the quality ceiling. These models reconstruct; they do not add detail that was never captured.

What it fully supports

01

Atmosphere, depth of field and depth grading driven by the Z pass.

02

Relighting and specular reshaping from the normals, with the axis convention documented.

03

Retimes, motion blur and temporal work gated by the flow confidence channel.

04

Region grading, removals, matte-driven work and 2.5D set extension — a genuine, Nuke-ready VFX layer set derived from a clip that shipped as a flat image.

09

Why it matters

Generative video is about to flood production. The teams who can reconstruct the missing layers — and do it on-device, cheaply, repeatably — turn a flat AI clip into something a real VFX pipeline can grade, relight, defocus and composite.

That is the bridge between 'AI made a nice clip' and 'AI footage in a finished film'.

The models and formats used

Video Depth Anything

The video-consistent depth model behind the Z pass — the variant that does not flicker.

Marigold

Diffusion-based monocular estimation; the normals variant used for surface orientation.

RAFT

Recurrent all-pairs field transforms — the optical-flow architecture used for forward and backward vectors.

SAM 2

Promptable segmentation with video propagation, used for the tracked matte.

OpenEXR

Multi-layer float imaging, half-float storage, and the layer.component channel naming Nuke reads.

NVIDIA DGX Spark

The GB10 unified-memory box the whole pipeline ran on.

ONNX Runtime

Where these models need porting to other inference targets.

Key Takeaways

01

Clean the plate before inference — grain and compression blocking destroy edge-directed models.

02

Use video-consistent depth, not per-frame: flicker becomes boiling in every downstream effect.

03

Depth here is relative inverse depth normalised per shot — a region selector, not geometry.

04

Package to standard layer.component names so a compositor's Read node just works.


PAR2 Labs · Film Making

Work With Us

Have a problem worth solving?