Fragment Shader è una fase programmabile della pipeline grafica che determina il colore finale di ogni frammento (pixel) di un'immagine. Secondo Khronos Group, 2025, lo shader di frammenti riceve dati interpolati dal Vertex Shader ed esegue calcoli di illuminazione, texturing ed effetti di colore. Fragment Shader viene invocato per ogni pixel, rendendolo la fase più dispendiosa in termini di risorse della pipeline grafica.
Punti chiave
Fragment Shader (shader di frammenti o pixel) è una fase programmabile della pipeline grafica che calcola il colore finale di ogni frammento dell'immagine. Un frammento è un pixel potenziale che diventa un pixel visibile sullo schermo dopo aver superato i test di profondità e stencil.
Fragment Shader viene eseguito dopo la rasterizzazione, quando i primitivi 3D (triangoli) sono già stati convertiti in un insieme di frammenti. Lo shader riceve attributi interpolati — coordinate di texture, normali, colori che sono stati calcolati nel Vertex Shader per i vertici del triangolo e interpolati linearmente per ogni pixel all'interno del triangolo.
Prima dell'avvento degli shader programmabili (prima di DirectX 8 / OpenGL 2.0), il calcolo del colore dei pixel veniva eseguito da una pipeline fissa con un insieme limitato di operazioni. Il Fragment Shader programmabile è apparso nel 2001 e ha radicalmente ampliato le capacità grafiche: gli sviluppatori hanno ottenuto il controllo completo sul colore di ogni pixel, consentendo di implementare illuminazione fotorealistica, materiali complessi e post-effetti.
Fragment Shader viene avviato dalla GPU per ogni frammento generato dal rasterizzatore. Ogni invocazione dello shader elabora un frammento, legge i suoi dati di input, esegue il codice utente e scrive il valore di output — il colore del frammento in formato RGBA.
I dati di input di Fragment Shader includono attributi interpolati dal Vertex Shader (coordinate di texture, normali, colori), variabili uniform (fonti di luce, matrici) e sampler di texture. I dati di output sono il vettore di colore (gl_FragColor in OpenGL ES 2.0 o una variabile definita dall'utente in ES 3.0), che viene scritto nel buffer di colore.
#version 300 es
precision mediump float;
in vec2 vTexCoord;
uniform sampler2D uTexture;
out vec4 fragColor;
void main() {
fragColor = texture(uTexture, vTexCoord);
}
Fragment Shader è responsabile della qualità visiva dell'immagine. Tutti gli effetti che l'utente vede sullo schermo — colore, ombre, riflessi, trasparenza — vengono calcolati in questa fase della pipeline grafica.
L'operazione più frequente è il campionamento del colore da una texture utilizzando coordinate UV interpolate. Sampler2D e la funzione texture() permettono di ottenere il colore di un pixel da un atlas di texture. Il filtraggio (bilineare, trilineare, anisotropico) è controllato attraverso i parametri del sampler e influisce sulla nitidezza dell'immagine a diversi angoli di visuale.
Il modello di illuminazione Phong viene calcolato in Fragment Shader per pixel, fornendo riflessi più morbidi rispetto all'illuminazione per vertici (ombreggiatura Gouraud). L'illuminazione Phong include tre componenti: ambiente, diffusa e speculare.
// Fragment shader with Phong lighting
in vec3 vNormal;
in vec3 vPosition;
uniform vec3 uLightDir;
uniform vec3 uLightColor;
void main() {
vec3 norm = normalize(vNormal);
float diff = max(dot(norm, uLightDir), 0.0);
fragColor = vec4(uLightColor * diff, 1.0);
}
Fragment Shader consente di applicare post-elaborazione: correzione del colore tramite tabelle di lookup (LUT), sfocatura (blur), effetto bagliore (bloom) e tonemapping per il rendering HDR. Tutti questi effetti funzionano a livello di pixel e vengono eseguiti in tempo reale.
Le prestazioni di Fragment Shader sono il fattore principale che limita gli FPS nei giochi mobili moderni. Poiché lo shader viene invocato per ogni pixel, anche un piccolo aumento della complessità del codice può portare a un notevole calo del frame rate.
Per GPU mobili (Qualcomm Adreno, ARM Mali) si raccomanda di: usare mediump precision per variabili float, combinare campionamenti di texture, applicare test early-z per scartare frammenti invisibili prima dell'esecuzione dello shader.
| Metodo | Descrizione | Guadagno |
|---|---|---|
| Mediump precision | Precisione a 16 bit invece di 32 bit | Fino a 2x velocità |
| Early-Z | Test di profondità prima dello shader | Riduzione invocazioni |
| Texture atlasing | Una texture invece di più | Meno cambi |
Entrambi i tipi di shader sono programmabili dallo sviluppatore, ma lavorano in fasi diverse della pipeline e risolvono compiti diversi. Fragment Shader è significativamente più dispendioso in termini di risorse a causa del numero di invocazioni.
| Parametro | Fragment Shader | Vertex Shader |
|---|---|---|
| Numero di invocazioni | Milioni (risoluzione schermo) | Migliaia (numero di vertici) |
| Dati di input | Attributi interpolati | Attributi dei vertici |
| Funzione principale | Calcolo del colore del frammento | Trasformazione della geometria |
| Accesso alle texture | Completo (più sampler) | Limitato |
| Impatto sulle prestazioni | Alto (dipende dalla risoluzione) | Moderato (dipende dalla geometria) |
Fragment Shader può essere semplice (campionamento di texture) o complesso (illuminazione multistrato). Consideriamo due esempi pratici: texturing di base e un effetto gradiente usando il tempo.
#version 300 es
precision mediump float;
in vec2 vTexCoord;
in vec3 vColor;
uniform sampler2D uDiffuseMap;
out vec4 fragColor;
void main() {
vec4 texColor = texture(uDiffuseMap, vTexCoord);
fragColor = texColor * vec4(vColor, 1.0);
}
#include <metal_stdlib>
using namespace metal;
struct FragmentIn {
float2 texCoord;
float3 normal;
};
fragment float4
fragmentMain(FragmentIn in [[stage_in]],
texture2d<float> tex [[texture(0)]]) {
constexpr sampler s(filter = linear);
float4 color = tex.sample(s, in.texCoord);
return color;
}
Domande frequenti
Fragment Shader è un mini-programma sulla GPU che determina di che colore sarà ogni pixel sullo schermo. Se Vertex Shader determina la forma dell'oggetto, allora Fragment Shader determina l'aspetto di quell'oggetto — texture, illuminazione, colore.
Fragment Shader viene invocato per ogni pixel sullo schermo. Su un dispositivo con risoluzione 2532x1170 (iPhone) si tratta di quasi 3 milioni di invocazioni per frame. A 60 FPS lo shader viene eseguito 180 milioni di volte al secondo, richiedendo un'enorme potenza di calcolo.
In Fragment Shader si implementano: texturing, illuminazione (Phong, PBR), ombre, riflessi, rifrazioni, bloom, profondità di campo, correzione del colore, filtri LUT e generazione procedurale di texture.
Usa mediump precision per float, riduci il numero di campionamenti di texture, applica early-z culling, combina le operazioni dello shader ed evita rami condizionali all'interno dello shader.
È la stessa cosa. Il termine Fragment Shader viene usato in OpenGL / Vulkan, mentre Pixel Shader viene usato nella terminologia Direct3D (Microsoft). Funzionalmente sono identici: entrambi calcolano il colore di ogni frammento/pixel.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche