Il calcolo dell'illuminazione per singolo pixel è una delle funzionalità che non possono essere implementate con la sola Fixed Function Pipeline, che invece si limita ad attribuire il colore ad ogni vertice e ad interpolarlo.
Il calcolo dell'illuminazione per pixel ha il vantaggio di una maggiore precisione. In più, alcuni effetti grafici (tra cui le texture) prevedono di calcolare il colore della primitiva all'interno del fragment shader, perciò alcune parti dell'illuminazione non possono che essere applicati successivamente.
Lo svantaggio consiste ovviamente in un calo delle prestazioni, perché la GPU deve compiere i calcoli dell'illuminazione per singolo pixel e non per vertice.
Il Phong shading è un algoritmo che prevede il calcolo dell'illuminazione per singolo pixel. Deve essere calcolata la normale ad ogni vertice della primitiva, poi tale normale è interpolata su ogni frammento. Si applica poi il solito modello di Phong, con componente ambientale, diffusiva e speculare.
All'inizio, il vertex shader calcola la normale e la posizione (relativa al punto di vista) di ciascun vertice e le passa avanti come variabili varying. Inoltre, deve trasmettere al fragment shader anche i dati sul materiale, perché i fragment shader non possono accedere alle variabili attribute.
#version 120 attribute float matshininess; attribute vec3 matspecular; varying float vmatshininess; varying vec3 vmatspecular; varying vec3 veyeposition; varying vec3 vnormal; void main() { vnormal = gl_NormalMatrix * gl_Normal; vec4 rp = gl_ModelViewMatrix * gl_Vertex; veyeposition = rp.xyz / rp.w; // use cartesian coordinates (works if w != 0) gl_FrontColor = gl_Color; gl_BackColor = vec4(0.0,0.0,0.0,1.0); gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; vmatspecular = matspecular; vmatshininess = matshininess; }
Il contenuto del listato sovrastante è rilasciato nel pubblico dominio.
Il prototipo della funzione ApplyLight deve avere due parametri in più, perché gli attributi matspecular e matshininess non possono più essere letti come variabili globali. Ora, la funzione deve essere caricata come fragment shader, non come vertex shader.
Il fragment shader si limita ad applicare l'illuminazione per ogni pixel. Si noti che la normale deve essere normalizzata prima di essere utilizzata, perché a causa dell'interpolazione può non avere più modulo 1.
#version 120 varying float vmatshininess; varying vec3 vmatspecular; varying vec3 veyeposition; varying vec3 vnormal; vec4 ApplyLight(in vec4 oColor, in vec3 relativepos, in vec3 normal,in vec3 matspecular,in float matshininess); void main() { gl_FragColor = ApplyLight(gl_Color,veyeposition,normalize(vnormal),vmatspecular,vmatshininess); }
Il contenuto del listato sovrastante è rilasciato nel pubblico dominio.
#define SHADER_FOLDER "shaders/pixel_lighting/" // o ../shaders/pixel_lighting/ o altro percorso relativo #define USE_VERTEX_SHADER true #define USE_FRAGMENT_SHADER true #define USE_GEOMETRY_SHADER false #define USE_NORMAL_SHADER false #define USE_VERTEX_LIGHT_SHADER false #define USE_FRAGMENT_LIGHT_SHADER true #define USE_TESSEVAL_LIGHT_SHADER false #define USE_TESSELLATION_SHADERS false #define GEOMETRY_INPUT_TYPE GL_TRIANGLES // irrilevante #define GEOMETRY_OUTPUT_TYPE GL_TRIANGLE_STRIP // irrilevante #define GEOMETRY_MAX_VERTICES 3 // irrilevante #define ENABLE_BACK_FACE_CULLING true #define LOAD_NORMALS true #define TIMER_MS 0
Risultato:
Copyright © 2011 Riccardo Monica
Eccetto ove espressamente indicato altrimenti, il contenuto di questa pagina è disponibile secondo la licenza Creative Commons Attribuzione - Condividi allo stesso modo 3.0.