Di RobyDx (del 13/02/2007 @ 09:39:06, in DirectX9, linkato 1512 volte)
La tecnologia shader già affermatasi con l’introduzione di DirectX8 continua ad evolversi e diventare sempre più presente nei giochi e nelle applicazioni di oggi. Molti giochi ormai usano effetti shader che portano la grafica a livelli altissimi e sempre più simili alla realtà. Con DirectX9 vengono introdotte nuove versioni dei linguaggi assembler destinati ai vertex e pixel shader. In questo tutorial vi illustrerò il funzionamento dei pixel shader 2.0 supportato ad oggi solo sulle schede di ultima generazione. La nuova versione shader ritorna come meccanismo di funzionamento alle prime 4 versioni di pixel shader (dalla 1.0 alla 1.3) eliminando la scomoda, seppur utile, doppia fase. Tuttavia i miglioramenti introdotti sono tali da rendere le precedenti versioni completamente antiquate ed inutili.
Pixel Shader 1.3
Pixel Shader 1.4
Pixel Shader 2.0
Max n°istruzioni
4 texture + 8 aritmetiche
6 texture + 8 aritmetiche per fase
32 texture + 64 aritmetiche
Texture caricabili
4
6
16
Registri R#
2
6
Da 12 a 36
Registri C#
8
8
32
Chi di voi ha usato i pixel shader capisce come sia migliorato l’utilizzo degli shader che ora può veramente essere scritto senza limiti (difficilmente scriverete codici più lunghi di 96 istruzioni). Il tutto senza usare la doppia fase che sicuramente avrà confuso molti di voi e senza perdere la possibilità di modificare le coordinate texture del pixel su cui si lavora. I cambiamenti sono abbastanza indolore ma richiedono un po’ di lavoro.
Nuovi registri
I registri pixel shader sono ora aumentati
registro
numero
Read-Write
descrizione
Input register
V0,V1
2
R
I registri contengono i colori diffuce e specular provenienti dal vertex shader
Temporary register
R#
12-36
RW
I registri da usare come variabili, ora il registro r0 è diventato un normale registro
Costant float register
C#
32
R
Costanti da passare dal programma o da definire nel codice assembler
Sampler register
S#
16
R
Usati per definire i sampling stage. DirectX ha come massimo 8 texture caricabili ma una texture può essere letta più volte da sampler diversi. I sampler vengono settati dal programma e consentono ad esempio di settare filtri etc. Inoltre se da codice inserite 16 texture diverse potrete tramite questo registro sceglierne 8 da caricare e usare, in qualsiasi indice si trovino.
Texture coordinate register
T#
8
R
Le coordinate delle texture in quel pixel
Output color register
OC#
#
W
Il registro oC# contiene il colore finale. Vista la possibilità in directX di renderizzare simultaneamente su più texture (multiple render target) potete tramite il suo numero dare ad ogni render target un valore finale differente. Un solo codice shader per più rendering differenziati.
Output depth register
oDepth
1
W
Con questo registro si assegna la profondità per Zbuffer e stencil buffer
Dichiarazioni
Alcuni registri devono essere dichiarati nel codice prima di essere usati. Questo tramite l’istruzione dcl dcl v# ‘dichiarazione registro input dcl t# ‘dichiarazione registro texture dcl_2d s#, dcl_cube s# , dcl_volume s# ‘dichiarazione del sampler. Potete scegliere fra le 3 tipologie di texture a disposizione in modo da poter usare anche le texture volumetriche e cubiche.
Definizione
È possibile dichiarare un registro c# senza doverlo caricare da codice tramite l’istruzione def Es Def c0,1,2,3,4.5
Uso dei registri
I registri contengono 4 valori (rgba). Per specificare di utilizzare una istruzione basta inserire un punto e specificare quale componente usare. Es r0.r, c0.rg, etc.
Istruzioni 2.0
Nome e sintatti
Descrizione
Abs dst,src
Calcola il valore assoluto
Add dst,src1,src2
Esegue la somma
Cmp dst,src1,src2,src3
Inserisce nel registro di destinazione il 2° o il 3° registro se il primo è >=0 o no
Crs dst,src1,src2
Esegue il cross product
Dp2add dst,src1,src2,src3
Esegue il dot product su 2 coordinate e le somma
Dp3 dst,src1,src2
Esegue il dot product su 3 registri
Dp4 dst,src1,src2
Esegue il dot product su 4 registri
Exp dst,src
Calcola 2 elevato al 1° registro
Frc dst,src
Restituisce la parte fratta del registro
Log dst,src
Logaritmo in base 2 del registro
Lrp dst,src1,src2,src3
Calcola l'interpolazione lineare
M3x2 dst,src0,src1
Esegue il dot product applicato ad una matrice (quindi usa più registri costanti )
M3x3 dst,src0,src1
Esegue il dot product applicato ad una matrice (quindi usa più registri costanti )
M3x4 dst,src0,src1
Esegue il dot product applicato ad una matrice (quindi usa più registri costanti )
M4x3 dst,src0,src1
Esegue il dot product applicato ad una matrice (quindi usa più registri costanti )
M4x4 dst,src0,src1
Esegue il dot product applicato ad una matrice (quindi usa più registri costanti )
Mad dst,src0,src1,src2
Prodotto dei primi 2 registri più il terzo
Max dst,src0,src1
Restituisce il massimo fra 2 registri
Min dst,src0,src1
Restituisce il minimo fra 2 registri
Mov dst,src
Copia un registro in un altro
Mul dst,src0,src1
Esegue il prodotto
Nop
Esegue una istruzione a vuoto
Nrm dst
Normalizza un vettore
Pow dst,src0,src1
Elevazione a potenza del 1° registro con il secondo
Rcp dst,src
Restituisce il reciproco
Rsq dst,src
Restituisce il reciproco sotto radice
Sincos dst,src0,src1,src2
Esegue il calcolo di sin e cos di un angolo. Il registro di destinazione deve essere con registri xy, il primo registro deve invece avere solo un registro specificato (l'angolo in radianti). Infine i rimanenti 2 registri devono essere 2 costanti con i seguenti numeri.
Se la coordinata texture è minore di zero esce dal codice
Texld dst,src0,src1
Riceve il colore della texture secondo la coordinata texture specificata nel primo source register (registro t o r) e la texture dichiarata secondo il registro s (normalmente a s0 corrisponde la prima texture e così via)
Texldb dst,src0,src1
Come texld ma la coordinata texture .a (o .w) viene usata per il livello di dettaglio
Texldp dst,src0,src1
Come texld ma coordinata texture .a (o .w) viene usata per dividere le coordinate texture
Per maggiori dettagli vedere la SDK microsoft per C++
Modificatori di registri
Potete fare delle operazioni sui registri direttamente nelle istruzioni aggiungendo dei suffisso ai registri o facendo una operazione. registro_bias : sottrae 0.5 al registro. Es add r0,v0,r1_bias 1-registro : inverte il registro. Es add r0,v0,1-r0 - registro : cambia segno al registro. Es add r0,v0,-r1 registro_x2 : moltiplica per 2 il registro. Es add r0,v0,r1_x2 registro_bx2: moltiplica per 2 dopo aver sottratto 0.5. Es add r0,v0,r1_bx2
Modificatori
Potete usare dei suffissi accanto alla istruzione per moltiplicare, dividere o saturare (ossia rendere i valori compresi tra 0 e 1) i registri di destinazione. _x2, _x4, _x8 moltiplica per 2,4,8 _d2, _d4, _d8 divide per 2,4,8 _sat satura es add_x4 r0,r1,v0 farà in modo che il registro r0 sarà moltiplicato per 4.
Uso
I pixel shader 2.0 si usano come le prime versioni. Ps.2.0 Definizioni costanti Dichiarazioni registri Istruzioni Copia nei registri oC# Il miglior sistema di usare i pixel shader è tramite le istruzioni di texture che permettono di leggere pixel in posizione diversa da quella considerata. Vista poi la possibilità di leggere una texture più volte (usando sempre lo stesso registro s0), potete usare ben 16 pixel da posizioni qualsiasi per elaborare i vostri effetti. Il miglior uso diventa quindi la creazione di filtri ossia di effetti che tramite il calcolo dei pixel vicini elabora l’immagine. Nell’esempio vedete 4 filtri che ho scritto in pixel shader 2.0. 1)Filtro sobel: tramite differenza di colore tra pixel contigui permette di creare il contorno delle figure (ottimo per migliorare il Cell Shading con linee continue e ben delineate) 2)Gaussian Filter: questo serve per sfocare l’immagine, utile per il depth of field e altri effetti. 3)Tap Filter: espande l’immagine 4)Roberts filter: un filtro carino che ho trovato in un articolo di matematica Provate ad inventare effetti. Vi lascio all’esempio (molto leggero in modo da permettere a chi non ha la scheda video adatta di capire comunque il funzionamento dei pixel shader 2.0).