INDICE: it.Of Effects and Shaders
Precedente: Pixels Adiacenti
Prossimo: Passaggi Multipli
Come già detto nel capitolo Coordinate delle Texture, una texture è sempre associata ad un campionatore, sampler. Infatti la texture in sé non è di alcuna utilità se non viene inserita in un campionatore. Infatti nel nostro codice
texture Tex <string uiname="Texture";>;
sampler Samp = sampler_state //Campionatore per il lookup della texture
{
Texture = (Tex); //applica una texture al campionatore
MipFilter = LINEAR; //stati del campionatore
MinFilter = LINEAR;
MagFilter = LINEAR;
};
alla riga 2 viene specificata una variabile di tipo texture chiamata Tex. L'annotazione tra <...> specifica come il corrispondente pin texture sul nodo apparirà come Texture. Di seguito troviamo il blocco del campionatore chiamato Samp a cui è associata la texture Tex come si vede nella riga 5.
Le altre voci sono ulteriori stati del campionatore. Per una lista di tutti gli stati possibili, visitare Effect States (Direct3D 9).
Con i pins texture sugli shaders non è possibile accedere alle slices per effettuare lo spread, avendo un solo pixelshader. Per farlo, è necessario specificare più variabili di tipo texture ed i rispettivi campionatori. Si dovrà quindi copiare il blocco di codice qui sopra per ogni texture in più ed assicurarsi di assegnare nomi unici alle variabili texture e sampler ed alle annotazioni, oltre ad assegnare ad ogni sampler una texture diversa. Per motivi hardware, non è possibile inserire più di 16 texture input pins in un effetto.
Un tipico esempio dell'uso di più textures in un pixelshader è la dissolvenza. Dopo aver duplicato il codice come descritto sopra, il codice per miscelare le textures potrebbe assomigliare a questo:
float Fade = 0.5; float4 PS(vs2ps In): COLOR { float4 colA = tex2D(SampA, In.TexCd); float4 colB = tex2D(SampB, In.TexCd); return lerp(colA, colB, Fade); }
dove la funzione lerp() esegue esattamente questa interpolazione lineare:
colB * Fade + colA * (1 - Fade)
Un altro caso comune è quello in cui si hanno due textures ed una maschera in scala di grigi che definisce le parti da miscelare delle due textures. Per ciascun pixel bianco della maschera sarà visibile il corrispondente pixel della texture A, per quelli neri i corrispondenti della texture B, e per ogni gradazione intermedia i pixels delle due textures miscelati.
Definisci una terza texture col nome di Mask , assegnale un campionatore SampMask ed il pixelshader apparirebbe così:
float4 PS(vs2ps In): COLOR { float4 colA = tex2D(SampA, In.TexCd); float4 colB = tex2D(SampB, In.TexCd); float4 mask = tex2D(SampMask, In.TexCd); return lerp(colA, colB, mask.r); }
Posto che la texture maschera debba essere in scala di grigi, si può accedere a tutti i canali del colore come valori di dissolvenza/miscelazione (nell'esempio viene usato il canale, componente, rosso tramite .r). Nota come si possa semplicemente usare anche la funzione lerp(), in cui ora il terzo parametro può essere un valore differente per pixel, mentre prima veniva usata una costante, che era la stessa per tutta la texture, attraverso il parametro Fade.
Nel capitolo Coordinate delle Texture è stato mostrato come modificare via codice le coordinate di una texture prima di campionare un pixel per ottenere vari effetti di displacement.
Invece che inserire un offset nel pixelshader si possono interpretare i valori dei colori di una texture ed usarli come offset per le coordinate di un'altra. Così si può generare più intuitivamente la texture per l'offset lavorando nella patch. Ecco come ottenere l'effetto di disturbo qui sotto:
float4 PS(vs2ps In): COLOR { float4 offset = tex2D(SampOff, In.TexCd) - 0.5; float4 col = tex2D(SampA, float2(In.TexCd.x + offset.r, In.TexCd.y)); return col; }
In questo esempio si genera un nuovo input per una texture e lo si assegna ad un campionatore SampOff. Come si vede dal codice, questo campionatore per l'offset prima viene campionato e solo dopo il valore (che sappiamo restare nell'intervallo 0...1) offset.r (posto che l'offset che cerchiamo si trovi nel canale rosso della texture da usare per il displacement) viene usato come offset per la componente x delle coordinate della texture in ingresso. Il -0.5 si usa per far sì che il valore di offset che sta tra 0 e 1 si attesti intorno allo 0 così da poter ottenere offsets di .x positivi e negativi.
Nella patch viene usato un nodo DynamicTexture (EX9.Texture Value) con il pin Width impostato su 1 ed il pin Height impostato per corrispondere alla texture per la quale vogliamo l'effetto disturbo. Questo fa sì che l'effetto operi per linee. Connettendo uno spread di valori casuali al pin Red del nodo DynamicTexture (EX9.Texture Value) diventa facile impostare gli offsets per linea.
Diciamo a questo punto che non si vuole un effetto così definito, e che vogliamo solo 10 offsets. Impostando il pin Height a 10 nel nodo DynamicTexture (EX9.Texture Value) ed assegnandogli 10 valori casuali, avremmo questo risultato:
Succede questo: la texture usata come offset, ora di soli 10 px in altezza, viene comunque campionata 512 volte (l'altezza della texture da deformare). Per campionare 10 valori 512 volte deve essere applicato qualche algoritmo di interpolazione/ricampionamento per decidere quale dei 10 valori viene campionato in corrispondenza di ciascuno dei 512 pixels dell'altra texture. Questo algoritmo può essere impostato usando lo stato MagFilter per il campionatore. Immettete POINT ed osservate la differenza.
texture Off <string uiname="Offset Texture";>; sampler SampOff = sampler_state //campionatore per il lookup della texture { Texture = (Off); //applica una texture al campionatore MipFilter = LINEAR; //stati del campionatore MinFilter = LINEAR; MagFilter = POINT; };
anonymous user login
~3d ago
~9d ago
~9d ago
~10d ago
~23d ago
~1mth ago
~1mth ago
~1mth ago
~1mth ago
~2mth ago