Questo tipo di post-processo è utilizzato soprattutto nel rendering di grandi spazi aperti; simula il fenomeno per cui i colori perdono la loro brillantezza e saturazione con l'aumentare della distanza dall'osservatore. Questo fenomeno è dovuto al fatto che non tutti i spettri della luce solare sono assorbiti e rifratti dall'atmosfera nello stesso modo producendo un decadimento maggiore per le tonalità di colore rosso-arancio.
Anche se di semplice implementazione (in questo caso non fisicamente corretto), aumenta notevolmente il realismo della scena, in special modo se la desaturazione avviene verso un colore in tonalità di azzurro (per i concetti espressi sopra); perchè l'effetto risulti realistico l'intensità della desaturazione deve essere sempre molto contenuta.
L'effetto è diviso in due parti: la prima costruisce una depth-map renderizzando la scena dal punto di vista dell'osservatore, la seconda utilizza questa depth-map per campionare la distanza dei pixels del viewport corrente e determinare la loro desaturazione.
1 float4x4 ViewProj;
2 float4x4 View;
3
4 struct VS_OUTPUT
5 {
6 float4 Position : POSITION0;
7 float2 TexCoords : TEXCOORD0;
8 float3 Normal : TEXCOORD1;
9 float Depth : TEXCOORD2;
10 };
11
12 VS_OUTPUT vs_main(float4 Position : POSITION0,
13 float3 Normal : NORMAL,
14 float2 TexCoords : TEXCOORD0)
15 {
16 VS_OUTPUT Output;
17
18 // Proiezione a schermo dei vertici del modello
19 Output.Position = mul(Position, ViewProj);
20 // Calcolo della distanza (z in view-space)
21 Output.Depth = mul(Position, View).z;
22
23 // Passo coordinate di texture e normale al Pixel Shader
24 Output.TexCoords = TexCoords;
25 Output.Normal = Normal;
26
27 return Output;
28 }
Quello precedente è il Vertex Shader che si occupa di renderizzare la scena e passare la distanza dall'osservatore (linea 21) al Pixel Shader; il Pixel Shader è stato omesso dato che riporta semplicemente la distanza nel render-target prestabilito.
Quello successivo è invece il codice del Pixel Shader utilizzato nel rendering del rettangolo a tutto schermo che realizza l'effetto.
1 // Sampler dell'immagine sorgente e della depth map
2 sampler2D sceneSampler;
3 sampler2D depthSampler;
4
5 // Intensità della desaturazione
6 uniform float desatStrength;
7 // Colore di desaturazione
8 uniform float4 desatColor;
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(sceneSampler, TexCoords);
17 float depth = tex2D(depthSampler, TexCoords).r;
18
19 // Calcolo intensità corrispondente
20 float intensity = dot(color, luminanceConstants);
21 // Calcolo la quantità di desaturazione
22 float desat = saturate(depth * desatStrength);
23
24 // Interpolazione tra colore ed intensità equivalente
25 return lerp(color, intensity * desatColor, desat);
26 }
Risultato dell'implementazione:
