Perché le GPU dividono lo spazio di clip Z per W, per posizione?


8

Sfondo:
ho scoperto che è molto facile usare un buffer di profondità lineare, usando solo una leggera modifica alla trasformazione del vertice canonico. Il metodo più semplice si trova in fondo a https://www.mvps.org/directx/articles/linear_z/linearz.htm .

Tuttavia, l'avvertimento è che funziona solo per triangoli che non hanno bisogno di essere ritagliati contro i piani vicini o lontani. (E una soluzione alternativa, di eseguire la divisione della prospettiva nello shader di vertice, produrrà un problema simile per gli altri quattro piani di frustum.)

Poiché il ritaglio richiede interpolazione lineare per funzionare su tutte e quattro le coordinate dello spazio della clip, penso che sia impossibile lavorare con profondità lineare, usando solo uno shader di vertice. Ma la ragione di tutto ciò dipende dal fatto che Z è divisa per W.

Perché è fatto? X e Y devono essere divisi per distanza dalla fotocamera, ma non le coordinate Z, per adattarsi perfettamente al riquadro NDC.

Risposte:


13

Se stai realizzando un'immagine prospettica e il tuo modello ha intersezioni implicite, quindi, se usi "Z lineare", tali intersezioni appariranno nei punti sbagliati.

Ad esempio, considera un semplice piano di massa con una linea di poli telefonici, che si allontana in lontananza, che perfora il terreno (e continua sotto). Le intersezioni implicite saranno determinate dai valori di profondità interpolati. Se quelli non sono interpolati 1/Z, quindi quando i vertici proiettati sono stati calcolati con la prospettiva, l'immagine apparirà errata.

Mi scuso per la qualità non estetica delle seguenti illustrazioni, ma le ho fatte nel '97.

La prima immagine mostra l'effetto di rendering richiesto. (Si noti che i "tralicci" blu vanno abbastanza lontano sotto il piano terra, quindi vengono ritagliati nella parte inferiore delle immagini)

inserisci qui la descrizione dell'immagine

Questa seconda immagine mostra il risultato dell'utilizzo di un buffer di profondità non reciproco: (Chiedo scusa per il cambio di scala: questi sono stati copiati da un vecchio documento MS Word e non ho idea di cosa sia successo con il ridimensionamento.)

inserisci qui la descrizione dell'immagine

Come puoi vedere, i risultati non sono corretti.

In un'altra nota, sei sicuro di voler davvero una rappresentazione Z lineare? Se stai eseguendo il rendering in prospettiva, sicuramente vuoi una maggiore precisione più vicino alla fotocamera che a distanza?

Per il tuo commento successivo:

"Se quelli non sono interpolati con 1 / Z" che non capisco. Che interpolazione è quella?

La prima cosa da notare è che, con una proiezione prospettica standard, le linee rette nello spazio mondiale rimangono rette nello spazio prospettico. Le distanze / lunghezze, tuttavia, non vengono conservate.

Per semplicità, supponiamo che venga utilizzata una trasformazione prospettica banale per proiettare i vertici, ovvero Si dovrebbe anche calcolare una profondità reciproca schermo-spazio, ad esempio ma Z lineare nel buffer di profondità sarebbe, per me, richiedono qualcosa di simile: (Possiamo assumere qui che scala = 1)

XScreen=XWorldZWorld
YScreen=YWorldZWorld
ZScreen=1ZWorld
ZScreen=Scun'le*ZWorld

Supponiamo di avere una linea con i punti finali dello spazio mondiale Con la mappatura prospettica queste mappe sono coordinate dello spazio dello schermo

[001]un'nd[200010]
[001]un'nd[2000.1]

Il sistema di rendering / hardware interpoleranno linearmente lo spazio dello schermo z, quindi nel punto 1/2 della linea, come appare sullo schermo, cioè in pixel (10, 0), otterremmo una Z proiettata (inversa) valore di 0,55, che corrisponde a un valore del valore Z dello spazio mondiale di ~ 1.818. Dati i valori Z iniziale e finale, questo è di circa il 20% lungo la lunghezza della linea.

Se invece provassimo a interpolare usando i valori Z originali, finiremmo con Z corrispondente a un valore dello spazio mondiale di 5,5. Finché nulla si interseca, potresti essere a posto (non ci ho pensato troppo a fondo) ma qualsiasi cosa con intersezioni implicite sarà errata.

Quello che non ho menzionato è che una volta introdotto il texturing corretto in prospettiva (o anche l'ombreggiatura corretta in prospettiva), è necessario eseguire l'interpolazione per pixel di 1 / w e, inoltre, calcolare, per pixel, il reciproco di quel valore interpolato.


Non credo che sarò in grado di capire questa risposta senza più matematica / diagrammi. E sì, più precisione, più vicino, probabilmente ha senso, ma un ridimensionamento da lineare di far / z, che è standard, non ha senso. Produce un buffer di profondità che diventa più lineare quanto più i due piani di clip si avvicinano. Sembra una fusione di due concetti: Z lineare nello spazio dello schermo e una mappatura del buffer di profondità non costante per un hack delle prestazioni.
Jessy,

In particolare, è il "se quelli non sono interpolati con 1 / Z" che non capisco. Che interpolazione è quella?
Jessy,

1
Aggiungerò del testo aggiuntivo per spiegare, spero
Simon F,

Grazie! Penso che il problema si riduce a "Il sistema di rendering / hardware interpoleranno linearmente lo spazio dello schermo z". Avevo l'impressione che la posizione NDC sarebbe stata calcolata come (x, y, z) / wper frammento, ma apparentemente, invece, dobbiamo fare i conti con una versione interpolata linearmente di (x/w, y/w, z/w)? Questo non mi sembra ragionevole nel 2018, ma sarebbe bello sapere se questo è l'hack con cui dobbiamo convivere comunque per ora!
Jessy,

Per eseguire il texturing / shading / prospettiva corretti in prospettiva, è necessario interpolare linearmente i valori (Val / w) e quindi, per frammento, eseguire una divisione per l'interpolato linearmente 1 / w. È un po 'difficile da spiegare solo in un commento, ma c'è una piccola spiegazione in computergraphics.stackexchange.com/a/4799/209 . In alternativa, fai una ricerca per l'articolo di Jim Blinn "Interpolazione iperbolica"
Simon F

6

L'uso di Z / W per il buffer di profondità è più profondo del semplice ritaglio rispetto ai piani vicino e lontano. Come ha accennato Simon, ciò ha a che fare con l'interpolazione tra i vertici di un triangolo, durante la rasterizzazione.

Z / W è l'opzione unica che consente di calcolare correttamente i valori di profondità NDC per i punti all'interno del triangolo, semplicemente interpolando linearmente i valori di profondità NDC dai vertici, nello spazio dello schermo . In linea di principio, potremmo utilizzare qualsiasi funzione che ci piace per mappare lo spazio della telecamera Z sul valore del buffer di profondità, ma qualsiasi altra scelta diversa da Z / W richiederebbe una matematica più complicata da fare per pixel, che sarebbe più lenta e più difficile da costruire in hardware.

Nota che se usi un buffer di profondità lineare, ovviamente l'interpolazione lineare dei valori di profondità sarà corretta nello spazio del mondo ... ma non, in generale, nello spazio dello schermo! Ed è lo spazio dello schermo che conta per la rasterizzazione, poiché dobbiamo essere in grado di generare valori di profondità corretti in prospettiva (e altri valori di attributo, come gli UV) per ciascun centro di pixel o altro punto di campionamento, all'interno dei limiti dello spazio dello schermo di un triangolo rasterizzato.


Non so come progettare una GPU, ma mi sembra che tutto ciò che serve sia interpolare Z invece di Z / W, per profondità lineare, e l'interpolazione Z / W potrebbe ancora accadere in seguito per qualcosa di visibile. Non riesco ancora a capire se si tratti di un buon ragionamento o di uno di "nessuno si preoccupa, quindi non ci preoccupiamo di aggiornare".
Jessy,

L'interpolazione di Z anziché Z / W non fornisce risultati corretti nello spazio dello schermo. Z / W.
Nathan Reed,

Giusto. Ma se il buffer di profondità è quantizzato con una precisione inferiore rispetto alla posizione, quindi, oltre a essere performante quando funziona, non è una buona idea memorizzare una porzione ridimensionata dello spazio dello schermo Z. Se l'interpolazione lineare è tutto ciò che otteniamo, allora il clipping richiede accadere nello spazio visivo. E Z deve essere interpolato prima della divisione per W, per il buffer di profondità e, successivamente, per ciò che hai superato. Quindi è la risposta alla mia domanda "perché le GPU si sono sempre interpolate solo nello spazio delle clip perché era l'unica soluzione pratica sulle prime GPU e da allora ha funzionato abbastanza bene"?
Jessy,

Non sto seguendo ciò che intendi per "quantizzare con una precisione inferiore rispetto alla posizione", o "memorizzare un pezzo ridimensionato dello spazio dello schermo Z".
Nathan Reed,

1
Inoltre, "Z deve essere interpolato prima della divisione per W, per il buffer di profondità" —no. Questo è quello che ho cercato di spiegare. Ottieni le risposte sbagliate se interpoli Z (o qualsiasi altra cosa) nello spazio dello schermo senza prima dividerlo per W. Sembra che tu sia bloccato su questa idea che un buffer Z lineare funzionerebbe solo se non ci dividessimo per W. Ma non funzionerà, non interpolerà correttamente nello spazio dello schermo.
Nathan Reed,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.