2013-05-16 17 views
5

I parametri per mul di HLSL (x, y) indicato here: dire cheHLSL mul() variabili chiarimento

  • se x è un vettore, viene trattata come un vettore riga.
  • se y è un vettore, viene considerato come vettore di colonna.

Questo poi seguire attraverso senso che:

a.

  • se x è un vettore, y viene considerato come row-major matrix
  • se y è un vettore, x è trattato come un column-major matrix

b.

dal ID3DXBaseEffect :: SetMatrix() passa in un row-major matrix, quindi userei la matrice passata nel shader seguente ordine:

es. Output.mPosition = mul(Input.mPosition, SetMatrix()value);?

Sono appena agli inizi con gli shader e sto imparando a utilizzare la matematica della matrice. Sarebbe bello se qualcuno potesse chiarirlo.

risposta

8

Sì, se x è un vettore, x viene trattato come un vettore principale di riga e y viene trattato come una matrice maggiore di riga; viceversa per la colonna principale così per un sistema a matrice per righe prossima:

float4 transformed = mul(position, world); 

e per colonna prossima:

float4 transformed = mul(world, position); 

causa del modo in cui moltiplicazione matriciale funziona, se la matrice è column-major quindi devi postare moltiplicare per un vettore colonna per ottenere il risultato corretto. Se la matrice è riga-principale, è necessario moltiplicare per un vettore riga.

Quindi, davvero, a hlsl non importa se la matrice è una riga o una colonna maggiore, spetta a te applicare la moltiplicazione vettoriale nell'ordine corretto per ottenere il risultato corretto.

+0

+1 Grazie, credo che sia tutto su come ordinare poi. Ottimo layout di risposta! – dk123

+1

Questo non è giusto. C'è una differenza tra "row-major" (che riguarda i componenti della matrice degli ordini sono memorizzati in memoria) e "convenzione vettoriale delle righe" (che è circa l'ordine di moltiplicazione). La matrice qui è * memorizzata * in ordine di riga principale in entrambi i casi. Il primo caso utilizza un vettore riga e il secondo caso un vettore colonna (e la matrice dovrebbe essere stata costruita in modo appropriato per ciascuno). –

12

No. I termini "riga-maggiore" e "colonna-maggiore" si riferiscono esclusivamente all'ordine di memoria dei componenti della matrice nella memoria. Non hanno nulla a che fare con l'ordine di moltiplicazione di matrici e vettori. In effetti, la chiamata D3D9 HLSL mul interpreta gli argomenti della matrice come colonna principale in tutti i casi. La chiamata ID3DXBaseEffect::SetMatrix() interpreta il suo argomento di matrice come riga principale e traspone dietro le quinte per l'ordine di colonna principale previsto di mul.

Se si dispone di una matrice che sembra astrattamente simili:

[ a b c d ] 
[ e f g h ] 
[ i j k l ] 
[ m n o p ] 

poi quando memorizzate in ordine row-major, la sua memoria aspetto:

a b c d e f g h i j k l m n o p 

cioè gli elementi di una riga sono tutti contigui in memoria.Se conservato in modo column-major, la sua memoria sarebbe simile a questa:

a e i m b f j n c g k o d h l p 

con gli elementi di una colonna di tutti contigui. Tuttavia, questo ha esattamente l'effetto zero su quale elemento è quello. L'elemento b è ancora nella prima riga e nella seconda colonna, in entrambi i casi. L'etichettatura degli elementi non è cambiata, solo il modo in cui sono mappati alla memoria.

Se si dichiara una matrice come float matrix[rows][cols] in C, si utilizza la memoria di riga maggiore. Tuttavia, alcuni altri linguaggi, come FORTRAN, utilizzano l'archiviazione a livello di colonna per i loro array multidimensionali per impostazione predefinita; e OpenGL utilizza anche l'archiviazione principale delle colonne.

Ora, completamente separatamente, c'è un'altra scelta della convenzione, che è se utilizzare la matematica vettore riga o vettore colonna. Questo non ha nulla a che fare con il layout di memoria delle matrici, ma influenza il modo in cui costruisci le tue matrici e l'ordine di moltiplicazione. Se si utilizzano vettori riga, farete vettore-matrice di moltiplicazione:

  [ a b c d ] 
[x y z w] * [ e f g h ] = [x*a + y*e + z*i + w*m, ... ] 
      [ i j k l ] 
      [ m n o p ] 

e se si utilizza vettori colonna, poi farete matrice-vettore moltiplicazione:

[ a b c d ] [ x ] 
[ e f g h ] * [ y ] = [x*a + y*b + z*c + w*d, ... ] 
[ i j k l ] [ z ] 
[ m n o p ] [ w ] 

Questo perché in matematica vettoriale riga, un vettore è in realtà una matrice 1 × n (una singola riga), e in matematica vettore colonna è una matrice n × 1 (una singola colonna) e la regola su quali dimensioni delle matrici possono essere moltiplicato insieme determina l'ordine. (Non è possibile moltiplicare una matrice 4 × 4 con una matrice 1 × 4, ma è possibile moltiplicare una matrice 4 × 4 con una 4 × 1.)

Si noti che la matrice non è cambiata tra i due equazioni sopra; solo l'interpretazione del vettore è cambiata.

Quindi, per tornare alla tua domanda iniziale:

Quando si passa un vettore di HLSL di mul, interpreta automaticamente "in modo corretto", secondo cui argomento è. Se il vettore è a destra, è un vettore riga e, se è a sinistra, è un vettore colonna.

Tuttavia, la matrice viene sempre interpretata allo stesso modo. Una matrice è una matrice, indipendentemente dal fatto che venga moltiplicata con un vettore riga sul lato sinistro o un vettore colonna sulla destra. Puoi decidere liberamente se utilizzare la matematica riga-vettore o vettore colonna nel codice, a condizione di essere coerenti. HLSL è agnostico su questo punto, sebbene la libreria matematica D3DX utilizzi i vettori di riga.

E si scopre che per qualche motivo, in D3D9 HLSL, mul si aspetta sempre che le matrici vengano archiviate nell'ordine delle colonne. Tuttavia, la libreria matematica D3DX memorizza le matrici nell'ordine delle righe e, come dice la documentazione, ID3DXBaseEffect::SetMatrix() prevede l'immissione in ordine di riga principale. Effettua una trasposizione dietro le quinte per preparare la matrice per l'uso con mul.

BTW, D3D11 HLSL imposta automaticamente l'ordine di colonna principale, ma consente di utilizzare una direttiva del compilatore per indicare di utilizzare invece l'ordine di riga principale. È ancora agnostico rispetto alla matematica vettoriale riga-vettore-riga. E OpenGL GLSL usa anche l'ordine delle colonne, ma non (per quanto ne so) fornisce un modo per cambiarlo.

Ulteriori letture su questi temi:

+0

OpenGL consente di specificare l'ordinamento per riga uniforme della riga/colonna usando un qualificatore 'layout'. Non è spesso utile poiché l'API GL consente già di trasporre le uniformi di matrice quando le si invia, ma può essere utile per i buffer uniformi. Sfortunatamente *** *** *** vale solo per le uniformi. Un costruttore 'mat4', ad esempio, prenderà sempre i suoi componenti nell'ordine delle colonne e non ci sono qualificatori di layout o qualcosa che al momento possa alterare quel comportamento. –

+0

A proposito, sei sicuro che ID3DXBaseEffect :: SetMatrix() effettivamente traspone la matrice prima di inviarla a HLSL? Se lo facesse, allora la matrice sarebbe arrivata in ordine di colonna maggiore e quindi la post-moltiplicazione (matrice * vettore colonna) sarebbe la linea d'azione appropriata. –

+0

@ AndonM.Coleman Non confondere lo spazio tra la riga principale e la memoria principale della colonna con la matematica vettore riga-colonna vs vettore riga. Sono due distinte scelte di convenzione. Il vettore di riga vs vettore di colonna influisce sull'ordine di moltiplicazione; row-major vs column-major influenza la memorizzazione dei componenti della matrice in memoria. Come ho detto, l'ordine di archiviazione predefinito in HLSL è colonna-principale, mentre quello nella libreria matematica D3DX lato CPU è riga-maggiore. Pertanto, 'SetMatrix()' deve trasporre la matrice, indipendentemente dal fatto che si utilizzi pre o post-moltiplicazione nel codice. –