Il mondo shader del vertice si trasforma, perché utilizziamo i vettori a 4 dimensioni?

StackOverflow https://stackoverflow.com/questions/1605703

  •  05-07-2019
  •  | 
  •  

Domanda

Da questo sito: http://www.toymaker.info/Games/html /vertex_shaders.html

Abbiamo il seguente frammento di codice:

// transformations provided by the app, constant Uniform data
float4x4 matWorldViewProj: WORLDVIEWPROJECTION;

// the format of our vertex data
struct VS_OUTPUT
{
  float4 Pos  : POSITION;
};

// Simple Vertex Shader - carry out transformation
VS_OUTPUT VS(float4 Pos  : POSITION)
{
  VS_OUTPUT Out = (VS_OUTPUT)0;
  Out.Pos = mul(Pos,matWorldViewProj);
  return Out;
}

La mia domanda è: perché la struttura VS_OUTPUT ha un vettore a 4 dimensioni come posizione? La posizione non è solo x, ye z?

È stato utile?

Soluzione

Perché hai bisogno della coordinata w per il calcolo della prospettiva. Dopo l'output dal vertex shader di DirectX esegue una divisione in prospettiva dividendo per w.

Essenzialmente se hai 32768, -32768, 32768, 65536 come posizione del vertice di output, dopo la divisione w ottieni 0,5, -0,5, 0,5, 1. A questo punto w può essere scartato perché non è più necessario. Queste informazioni vengono quindi passate attraverso la matrice del viewport che le trasforma in coordinate 2D utilizzabili.

Modifica: se osservi come viene eseguita una moltiplicazione di matrici usando la matrice di proiezione puoi vedere come i valori vengono posizionati nei posti corretti.

Presa della matrice di proiezione specificata in D3DXMatrixPerspectiveLH

2*zn/w  0       0              0
0       2*zn/h  0              0
0       0       zf/(zf-zn)     1
0       0       zn*zf/(zn-zf)  0

E applicandolo a un casuale x, y, z, 1 (Nota per una posizione del vertice w sarà sempre 1) valore di input del vertice si ottiene il seguente

x' = ((2*zn/w) * x) + (0 * y) + (0 * z) + (0 * w)
y' = (0 * x) + ((2*zn/h) * y) + (0 * z) + (0 * w)
z' = (0 * x) + (0 * y) + ((zf/(zf-zn)) * z) + ((zn*zf/(zn-zf)) * w)
w' = (0 * x) + (0 * y) + (1 * z) + (0 * w)

Immediatamente puoi vedere che w e z sono diversi. Il coordino w ora contiene solo la coordinata z passata alla matrice di proiezione. z contiene qualcosa di molto più complicato.

Quindi .. supponiamo di avere una posizione di input di (2, 1, 5, 1) abbiamo uno zn (Z-Near) di 1 e uno zf (Z-Far di 10) e aw (larghezza) di 1 e ah (altezza) di 1.

Passando questi valori otteniamo

x' = (((2 * 1)/1) * 2
y' = (((2 * 1)/1) * 1
z' = ((10/(10-1)  * 5 + ((10 * 1/(1-10)) * 1)
w' = 5

espandendo che poi otteniamo

x' = 4
y' = 2
z' = 4.4
w' = 5

Eseguiamo quindi la divisione della prospettiva finale e otteniamo

x'' = 0.8
y'' = 0.4
z'' = 0.88
w'' = 1

E ora abbiamo la nostra posizione finale delle coordinate. Ciò presuppone che x e y siano compresi tra -1 e 1 e z che sia compreso tra 0 e 1. Come puoi vedere, il vertice è sullo schermo.

Come bizzarro bonus puoi vedere che se | x '| oppure | y '| oppure | z '| è maggiore di | w '| o z 'è minore di 0 che il vertice è fuori schermo. Queste informazioni vengono utilizzate per ritagliare il triangolo sullo schermo.

Comunque penso che sia una risposta abbastanza completa: D

Modifica2: attenzione che sto usando le matrici principali ROW. Le matrici principali della colonna vengono trasposte.

Altri suggerimenti

La rotazione è specificata da una matrice tridimensionale e la traslazione da un vettore. Puoi eseguire entrambe le trasformazioni in un "singolo". operazione combinandoli in un'unica matrice 4 x 3:

rx1 rx2 rx3 tx1
ry1 ry2 ry3 ty1
rz1 rz2 rz3 tz1

Tuttavia, poiché questo non è quadrato, ci sono varie operazioni che non possono essere eseguite (inversione per una). Aggiungendo una riga aggiuntiva (che non fa nulla):

0   0   0   1

tutte queste operazioni diventano possibili (se non facili).

Come spiega Goz in la sua risposta facendo il "1" " un valore non identitario la matrice diventa una trasformazione prospettica.

Il ritaglio è una parte importante di questo processo, poiché aiuta a visualizzare ciò che accade alla geometria. La fase di ritaglio essenzialmente scarta qualsiasi punto in una primitiva che è al di fuori di un cubo di 2 unità centrato attorno all'origine (OK, devi ricostruire le primitive che sono parzialmente ritagliate ma non importa qui).

Sarebbe possibile costruire una matrice che mappasse direttamente le coordinate del tuo spazio mondiale su tale cubo, ma il movimento graduale dal piano lontano al piano vicino sarebbe lineare. Vale a dire che uno spostamento di un piede (verso lo spettatore) quando un miglio di distanza dallo spettatore causerebbe lo stesso aumento di dimensioni di uno spostamento di un piede quando diversi piedi dalla telecamera.

Tuttavia, se abbiamo un'altra coordinata nel nostro vettore (w), possiamo dividere il vettore componente saggiamente per w, e i nostri primitivi non mostreranno il comportamento sopra, ma possiamo ancora farli finire all'interno del 2 -unit cubo sopra.

Per ulteriori spiegazioni consultare http://www.opengl.org /resources/faq/technical/depthbuffer.htm#0060 e http: // it .wikipedia.org / wiki / Transformation_matrix # Perspective_projection .

Una semplice risposta sarebbe quella di dire che se non si dice alla pipeline cos'è w allora non gli si sono fornite abbastanza informazioni sulla propria proiezione. Questo può essere verificato direttamente senza capire cosa ci fa la pipeline ...

Come probabilmente saprai, la matrice 4x4 può essere suddivisa in parti in base a ciò che ciascuna parte fa. La matrice 3x3 in alto a sinistra viene modificata quando si eseguono operazioni di rotazione o ridimensionamento. La quarta colonna viene modificata quando si esegue una traduzione. Se mai ispezionate una matrice prospettica, questa modifica la riga inferiore della matrice. Se poi osservi come viene eseguita una moltiplicazione Matrix-Vector, vedi che la riga inferiore della matrice influisce SOLO sul risultante w componente del vettore. Quindi se non comunichi alla pipeline w non avrà tutte le tue informazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top