Motion Vectors: La Texture Più Importante dei Giochi Moderni

Frecce per-pixel che puntano al passato. Ogni tecnica temporale dipende da loro.

Se TAA, DLSS, FSR, XeSS e PSSR hanno una cosa in comune, è che tutti crollerebbero completamente senza i motion vector. Un motion vector è un vettore 2D per pixel che dice: "questo pixel era nella posizione (x', y') nel frame precedente." È il ponte tra il frame di oggi e quello di ieri, e l'intera industria ha passato dieci anni a migliorarne la produzione.

Definizione

Per ogni pixel sullo schermo con coordinate attuali (x, y), il motion vector MV(x, y) è un offset 2D tale che:

posizione_precedente = (x, y) + MV(x, y)

Alcuni motori lo memorizzano al contrario (current = previous + MV); la convenzione varia. La magnitudine è in unità di pixel, o a volte in normalized device coordinates (NDC) così è indipendente dalla risoluzione.

Una texture di motion vector è solitamente memorizzata come una texture a due canali R16G16_FLOAT o R16G16_SNORM alla risoluzione piena dello schermo. Rosso è l'offset X, verde è l'offset Y, scalati per stare nel formato.

Una scena in stile gioco con un'auto in movimento. Sovrapposta, una griglia rada di piccole frecce: frecce lunghe che puntano a sinistra dove l'auto si muove rispetto alla camera, frecce corte sullo sfondo statico dove la parallasse causa un flow lieve. Sotto, la stessa scena mostrata come visualizzazione di flow a falsi colori (rosso = X, verde = Y) tipo optical flow. Due pannelli affiancati. Diagramma tecnico pulito.
Ogni pixel porta un vettore 2D che punta a dove era nel frame precedente.

Da dove vengono i motion vector

Ci sono due sorgenti, e un motore vero le combina entrambe.

1. Movimento della camera (analitico, per-pixel)

Se conosci la matrice view-projection della camera per questo frame e il precedente, e conosci la posizione mondo del pixel (dalla profondità), puoi calcolare esattamente dove era quel pixel nel frame precedente. Matematica pura, precisione assoluta, gratis.

vec4 worldPos = reconstructWorld(uv, depth, invViewProj);
vec4 prevClip = prevViewProj * worldPos;
vec2 prevUV   = prevClip.xy / prevClip.w * 0.5 + 0.5;
vec2 motion   = prevUV - uv;

Questo gestisce perfettamente rotazione, traslazione e cambio di FOV della camera. Non gestisce gli oggetti in movimento, perché assume che il mondo sia statico.

2. Movimento degli oggetti (renderizzato per-object)

Per ogni oggetto in movimento personaggi, veicoli, proiettili, fogliame ondeggiante il motore renderizza un pass aggiuntivo nel buffer dei motion vector. Per ogni vertice calcola la posizione in clip-space attuale e quella del frame precedente (usando le matrici di skinning del frame precedente per le mesh skinnate), e il fragment shader scrive il delta in screen-space.

Questo buffer combinato è uno dei canali del G-buffer che abbiamo menzionato prima. Produrlo correttamente per ogni cosa in movimento nella scena è una delle parti più soggette ad errori di un motore, e i motion vector sbagliati sono la causa di circa l'80% degli artefatti degli upscaler.

Diagramma a due colonne. Colonna sinistra 'Camera Motion': una scena statica con la camera in movimento, che mostra come la parallasse produce motion vector via matematica matriciale, con l'equazione matriciale mostrata. Colonna destra 'Object Motion': una camera statica con un personaggio in movimento, che mostra come le posizioni per-vertice del frame precedente producono motion per-pixel. Entrambe confluiscono in una singola texture di motion vector combinata mostrata in basso. Infografica tecnica.
I motion vector del motore combinano la matematica analitica della camera con i delta per-oggetto in screen-space in una singola texture.

Cosa i motion vector NON catturano

Questo è critico, ed è dove ogni upscaler moderno sanguina artefatti:

Fenomeno Catturato dai MV? Perché
Pan della camera Pura matematica analitica
Personaggio che cammina Movimento oggetto per-bone
Particelle A volte Il motore deve scriverle esplicitamente
Ombre No Un'ombra è un risultato, non geometria
Riflessioni No L'oggetto riflesso si muove nello spazio-specchio
Highlight speculari No Scivolano sulla superficie al muoversi della camera
Trasparenza Parziale Solo il movimento dello strato più vicino viene registrato
Caustiche, rifrazione No La luce si muove, la geometria no
Animazione procedurale negli shader No Lo shader cambia tra i frame, ma la geometria non si muove

Quindi quando guardi un output TAA o DLSS e vedi un riflesso che ghostha, un'ombra che sbava o un fuoco che lascia scie quello è l'upscaler che fallisce nell'invalidare la history perché il motion vector ha detto che il pixel non si è mosso, ma l'aspetto è cambiato comunque.

Per questo DLSS, FSR 2+, XeSS e PSSR si affidano tutti a reti neurali: la rete impara a rilevare questi casi di "il motion vector ha mentito" e a rifiutare la history in un modo più intelligente di quanto un'euristica calibrata a mano potrebbe mai fare.

Precisione sub-pixel e risoluzione

I motion vector sono normalmente renderizzati alla risoluzione interna (bassa) del renderer, non a quella di output. Va bene quando l'upscaler è basato su campioni campiona il motion alla risoluzione interna e lavora lì ma significa che la quantizzazione del MV può causare jitter visibile per oggetti che si muovono lentamente, dove il MV si arrotonda a zero un frame e a un pixel quello dopo.

Alcuni motori ora renderizzano i motion vector a risoluzione più alta del colore, o alla risoluzione piena di output anche quando il colore è a risoluzione interna, solo per dare all'upscaler dati di motion puliti.

Primo piano che mostra un oggetto sottile in movimento lento (un cavo o un palo). In alto: motion vector renderizzati a 1080p, quantizzati a frecce a pixel intero, alternando tra 0 e 1 pixel. In basso: motion vector renderizzati a 4K, lisci e frazionari. La versione 1080p causa jitter visibile nell'output ricostruito, mostrato come una scia a singhiozzo. Diagramma tecnico pulito.
I motion vector low-res si quantizzano a pixel interi, causando jitter visibile su oggetti sottili in movimento lento.

Reverse reprojection vs forward reprojection

Due scuole:

  • Reverse reprojection (quello che fanno TAA e DLSS Super Resolution): per ogni pixel di output, cerca da dove veniva nel frame precedente. Facile, deterministico, non produce mai buchi.
  • Forward reprojection (quello che fanno alcune tecniche di frame generation): per ogni pixel di input, spedisci dove sarà nel prossimo frame. Può produrre buchi e sovrapposizioni, ma è essenziale quando devi predire il futuro, non riproiettare il passato.

La DLSS 3 Frame Generation usa entrambe: ha i motion vector del passato (frame "real" N e frame "real" N+1), ma deve forward-warpare a metà strada tra loro per produrre il frame generato N.5. Vedremo esattamente come nel capitolo 9.

Un'alternativa puramente visiva: optical flow

E se non hai motion vector? E se hai solo due immagini e devi capire il movimento tra loro? Quel problema è l'optical flow una tecnica classica di computer vision che risale agli algoritmi Horn–Schunck (1981) e Lucas–Kanade (1981). Gli acceleratori hardware di optical flow moderni (come l'Optical Flow Accelerator sulle GPU NVIDIA Ada/Blackwell) calcolano il movimento per-pixel tra due immagini arbitrarie in meno di un millisecondo.

Questo è il secondo pilastro della DLSS 3 Frame Generation: motion vector del motore più optical flow hardware, fusi insieme, danno alla rete un campo di movimento migliore di quanto entrambe le sorgenti potrebbero da sole.

Comparazione fianco a fianco. Pannello sinistro 'Engine motion vectors': accurato per camera e oggetti rigidi, vuoto/zero per ombre, riflessi, particelle. Pannello destro 'Optical flow (vision-based)': cattura tutto ciò che si muove visivamente   movimento delle ombre, slittamento speculare, riflessi. Sotto, una freccia 'fusion' combina entrambi in un singolo campo di motion denso e completo. Diagramma tecnico pulito, sfondo scuro.
Motion vector del motore più optical flow hardware ognuno copre i buchi che l'altro lascia.

Nel prossimo capitolo guardiamo l'upscaling vero e proprio: spaziale vs temporale, perché l'upscaling spaziale da solo è destinato a fallire, e cosa aggiunge davvero la ricostruzione neurale sopra al TAA upsampling.