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.

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.

Cosa i motion vector NON catturano
Questo è critico, ed è dove ogni upscaler moderno sanguina artefatti:
| Fenomeno | Catturato dai MV? | Perché |
|---|---|---|
| Pan della camera | Sì | Pura matematica analitica |
| Personaggio che cammina | Sì | 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.

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.

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.