Il processo di colorizzazione ha la caratteristica di alterare la tonalità, la saturazione o l'intensità dei colori dell'immagine; può essere effettuato seguendo metodi differenti con risultati altrettanto diversi.
Il metodo più semplice è quello di integrare nel Pixel Shader di desaturazione la modulazione dell'intensità calcolata con un colore specificato dall'utente: questo processo genera un'immagine monocromatica con tonalità basata sul colore impostato (esempio fotografia invecchiata tendente al seppia):
1 // Sampler dell'immagine sorgente
2 sampler2D sourceSampler;
3
4 // Inverso della dimensione del viewport
5 uniform float2 invViewSize;
6
7 // Gestione intensità componenti in modo dipendente
8 uniform float4 hue;
9
10 // Costanti per l'influenza delle singole componenti
11 const float4 luminanceConstants = float4(0.2125, 0.7154, 0.0721, 0.0000);
12
13 float4 ps_main(float2 TexCoords : TEXCOORD0) : COLOR0
14 {
15 // Recupero le informazioni dai render-targets per il pixel corrente
16 float4 color = tex2D(sourceSampler, TexCoords);
17
18 // Calcolo intensità corrispondente
19 float intensity = dot(color, luminanceConstants);
20
21 return hue * intensity;
22 }
Visualizzazione dell'effetto:

Un secondo metodo può essere quello di specificare delle costanti differenti per ognuna delle tre componenti di colore in modo da far risaltare maggiormente alcune tinte rispetto ad altre; questo tipo di elaborazione è spesso utilizzato per dare risalto a scene particolari secondo la loro caratteristica (interni, esterni, ecc...) o secondo il loro significato riguardo la trama o il gameplay.
1 // Sampler dell'immagine sorgente
2 sampler2D sourceSampler;
3
4 // Inverso della dimensione del viewport
5 uniform float2 invViewSize;
6
7 // Gestione intensità componenti in modo dipendente
8 uniform float3 rgbMultiplier;
9
10 float4 ps_main(float2 TexCoords : TEXCOORD0) : COLOR0
11 {
12 // Recupero le informazioni dai render-targets per il pixel corrente
13 float4 color = tex2D(sourceSampler, TexCoords);
14
15 // Moltiplico con le costanti
16 color.rgb *= rgbMultiplier;
17
18 return color;
19 }
Visualizzazione dell'effetto:

Un terzo metodo, il più complesso tra quelli presentati in questo capitolo, prevede l'elaborazione cromatica del colore tramite conversioni da e verso spazi colore differenti (in genere i più utilizzati sono RGB e HSV (Hue Saturation Value - Tonalità Saturazione Valore). Tramite questi processi si possono elaborare in modo indipendente: la luminosità, la saturazione del colore, la distorsione cromatica dell'immagine; di questi l'ultima possibilità è sicuramente la più interessante per la capacità di creare effetti particolari legati ad esempio allo stato del giocatore senza richiedere l'uso di una segnalazione nell'interfaccia con l'utente tramite grafica specifica.

A differenza del metodo precedente richiede l'utilizzo dello Shader Model 3.0 dato che la conversione viene effettuata tramite operazioni aritmetiche e blocchi condizionali, oggi trattati dalle GPU in modo molto efficiente. Precedentemente per realizzare questi effetti erano utilizzate delle textures precalcolate che permettevano (tramite il corretto indirizzamento con le coordinate di texture) la conversione istantanea da uno spazio colore all'altro.
1 // Sampler dell'immagine sorgente
2 sampler2D sourceSampler;
3
4 // Inverso della dimensione del viewport
5 uniform float2 invViewSize;
6
7 // Spostamento della tonalità
8 uniform float hueShift;
9 // Intensità della saturazione
10 uniform float saturationStrength;
11 // Intensità del valore
12 uniform float valueStrength;
13
14 // Funzione per la conversione dallo spazio colore HSV a quello RGB
15 float3 HSVToRGB(float3 HSV)
16 {
17 // Porta il range della tonalità (HSV.x) da 0.0 ... 1.0 a 0 ... 360
18 // convertendola in gradi sessagesimali
19 float h = (HSV.x * 360.0) % 360.0;
20 float s = HSV.y;
21 float v = HSV.z;
22
23 // Se la saturazione è zero allora ritorna una sfumatura di grigio
24 if (s == 0.0) return HSV.zzz;
25
26 // La ruota dei colori è costituita da sei settori.
27 // Calcola il settore corrente e la sua parte frazionale.
28 float sectorPos = h / 60.0;
29 int sectorNumber = (int)(floor(sectorPos));
30 float fractionalSector = sectorPos - sectorNumber;
31
32 // Calcola i valori dei tre assi dello spazio colore RGB
33 float p = v * (1.0 - s);
34 float q = v * (1.0 - (s * fractionalSector));
35 float t = v * (1.0 - (s * (1.0 - fractionalSector)));
36
37 // Assegna le componenti in base al settore contenente
38 // l'angolo specificato nella tonalità di colore.
39 if (sectorNumber == 0)
40 return float3(v, t, p);
41 else if (sectorNumber == 1)
42 return float3(q, v, p);
43 else if (sectorNumber == 2)
44 return float3(p, v, t);
45 else if (sectorNumber == 3)
46 return float3(p, q, v);
47 else if (sectorNumber == 4)
48 return float3(t, p, v);
49 else if (sectorNumber == 5)
50 return float3(v, p, q);
51
52 return float3(0.0, 0.0, 0.0);
53 }
54
55 // Funzione per la conversione dallo spazio colore RGB a quello HSV
56 float3 RGBToHSV(float3 RGB)
57 {
58 float h;
59 float s;
60 float v;
61
62 // Calcola la componente minima e massima del colore
63 float cmin = min(min(RGB.r, RGB.g), RGB.b);
64 float cmax = max(max(RGB.r, RGB.g), RGB.b);
65 float delta = cmax - cmin;
66 v = cmax;
67
68 // Se le componenti di colore sono zero o tutte dello stesso valore
69 // la saturazione è zero e la tonalità indefinita.
70 if (cmax == 0.0 || delta == 0.0)
71 {
72 s = 0.0;
73 h = 1.0;
74 }
75 else
76 {
77 s = delta / cmax;
78 if (RGB.r == cmax)
79 {
80 // Tonalità tra giallo e magenta
81 h = (RGB.g - RGB.b) / delta;
82 }
83 else if (RGB.g == cmax)
84 {
85 // Tonalità tra ciano e giallo
86 h = 2.0 + (RGB.b - RGB.r) / delta;
87 }
88 else
89 {
90 // Tonalità tra magenta e ciano
91 h = 4.0 + (RGB.r - RGB.g) / delta;
92 }
93 }
94
95 // Ridimensiona h nel range 0.0 ... 1.0 e aggiunge 1.0
96 // finchè il valore risulta negativo.
97 h *= 1.0 / 6.0;
98 while (h < 0.0)
99 h += 1.0;
100
101 return float3(h, s, v);
102 }
103
104 // Funzione principale del Pixel Shader
105 float4 ps_main(float2 TexCoords : TEXCOORD0) : COLOR0
106 {
107 // Recupero le informazioni dai render-targets per il pixel corrente
108 float4 color = tex2D(sourceSampler, TexCoords);
109
110 // Converto lo spazio colore da RGB a HSV
111 float3 hsv = RGBToHSV(color.rgb);
112
113 // Modifico i parametri di tonalità, saturazione e valore
114 hsv.x = (hsv.x + hueShift) % 1.0;
115 hsv.y = saturate(hsv.y * saturationStrength);
116 hsv.z = saturate(hsv.z * valueStrength);
117
118 // Riconverto in RGB per la visualizzazione
119 return float4(HSVToRGB(hsv), 1);
120 }
Come è possibile notare questa è la prima volta che nel codice appaiono più di una funzione, in questo caso le funzioni che verranno richiamate da un metodo devono essere definite prima dei metodo stesso.
Di seguito è visibile un possibile risultato di tale elaborazione:

In questo capitolo più che negli altri dedicati agli effetti in post-processo, analizzare tutte le possibili elaborazioni è praticamente impossibile, invito quindi il lettore a sperimentare liberamente cercando effetti particolari che catturino l'attenzione.