Shaders

Knowledge
Aided
Engineering
Manufacturing
and
Related
Technologies
INFORMATICA GRAFICA!
11 giugno!
Shaders – OpenGL Shading Language!
Michele Antolini – [email protected]!
Shaders!
•  “Ombreggiatura”!
•  Uno shader permette di definire come un
materiale reagisce alla luce!
•  Necessario per ottenere effetti fotorealistici!
•  Si possono fare anche altre cose (es. bump
mapping, effetti particellari, animazioni)!
KAEMaRT – Michele Antolini!
Shaders!
http://www.realtime-technology.com
KAEMaRT – Michele Antolini!
Shaders!
•  Le textures non bastano!
•  E’ necessario un controllo maggiore sulle caratteristiche
della scena!
•  I primi shaders erano programmati direttamente sulla
scheda video (es. flat, smooth shaders)!
•  Prima di OpenGL 2.0, alcune schede grafiche erano
programmabili in linguaggio assembler, il cui codice
binario doveva essere copiato sulla scheda!
•  Con OpenGL 2.0 è stato definito un linguaggio di
programmazione per shaders!
KAEMaRT – Michele Antolini!
Shaders!
•  Le schede grafiche diventano una logica programmabile!
•  Il consorzio OpenGL ARB (Architecture Review Board)
detta le specifiche per il linguaggio di alto livello (C-like)
con cui programmare le schede!
•  Il compilatore è integrato nei driver OpenGL (se
compatibile 2.0) di ogni scheda, quindi ottimizzato a
seconda dell’hardware sottostante!
KAEMaRT – Michele Antolini!
Shaders!
•  Gli shaders seguono il paradigma di programmazione
definito stream processing!
•  La GPU permette centinaia, migliaia di operazioni
contemporanee su dati multipli: Single Instruction Multiple
Data (SIMD)!
•  Uno shader è un vero e proprio programma che sfrutta le
capacità di calcolo parallelo della GPU!
KAEMaRT – Michele Antolini!
Shaders!
•  Categorie di shaders!
•  Vertex shaders!
!
•  Fragment shaders!
•  Geometry shaders (OpenGL 3.2)!
KAEMaRT – Michele Antolini!
Vertex shaders!
•  Eseguiti per ogni vertice!
•  Es. rettangolo: vertex shader eseguito 4 volte,
una per ogni vertice generato per disegnarlo!
•  Usi: !
•  trasformazioni di vertici!
•  normalizzazione di vettori normali!
•  generazione di texture coordinates!
•  illuminazione!
•  applicazione di attributi (es. il colore del
materiale)!
!
KAEMaRT – Michele Antolini!
Fragment shaders!
•  Eseguiti per ogni pixel dell’oggetto rasterizzato!
•  Es. rettangolo: fragment shader eseguito per
ogni pixel visibile dell’area del rettangolo!
•  Usi: !
•  operazioni su attributi interpolati (varying)!
•  accesso a textures!
•  applicazione di textures!
•  effetto nebbia!
•  calcolo e applicazione colore pixel!
•  bump mapping!
!
KAEMaRT – Michele Antolini!
Geometry shaders!
•  Eseguiti per ogni vertice!
•  Permettono di creare nuove primitive (vertici) a
partire da quelli esistenti!
•  Utilizzo più comune è la tassellazione di curve
o superfici!
!
KAEMaRT – Michele Antolini!
GLSL!
•  Il consorzio OpenGL ARB ha definito un
linguaggio standard di alto livello per la
programmazione di shaders!
•  Sono stati tenuti in considerazione molti requisiti:!
•  Buona integrazione con specifiche OpenGL!
•  Possibilità di sfruttamento di hardware futuro!
•  Indipendenza dall’hardware sottostante!
•  Semplicità e longevità!
•  Compatibilità con calcolo parallelo massivo!
KAEMaRT – Michele Antolini!
Shaders execution!
2.5 System Overview
Application
Shader source code
OpenGL API
Shader source code
OpenGL Driver
Shader
Object
Compiler
compiled code
rogram
Object
Linker
executable code
Graphics hard are
Provided by application developer
rovided by graphics hardware vendor
Figure 2.4
R. Rost, OpenGL Shading Language 2nd Edition, Addison-Wesley
Execution model for OpenGL shaders
KAEMaRT – Michele Antolini!
Shaders execution!
•  Il punto di partenza è quindi il sorgente dello shader!
•  Avviene una compilazione a run-time nel linguaggio
assembly della scheda grafica!
•  Il compilatore prende come argomenti degli array di
stringhe, è quindi possibile la manipolazione per il
riutilizzo di frammenti di codice!
KAEMaRT – Michele Antolini!
GLSL Language Definition!
•  Il GLSL (OpenGL Shading Language) è stato creato
intenzionalmente ispirandosi al C!
•  Un programma possiede tipicamente due shaders: vertex
e fragment!
•  E’ possibile utilizzare tre tipi di variabili globali all’interno di
uno shader!
•  uniform: può essere modificata una volta per ogni
chiamata allo shader!
•  attribute: varia solitamente per ogni vertice (es. colore)!
•  varying: serve a far comunicare vertex e fragment
shader!
•  Esiste anche una serie di variabili built-in, aventi
prefisso gl_!
KAEMaRT – Michele Antolini!
Variabili!
•  uniform: le variabili uniform vengono utilizzate per
definire proprietà che cambiano al più ogni frame!
•  attribute: gli attribute si usano per definire proprietà che
possono cambiare per ogni vertice!
•  Usiamo già attributi predefiniti come glNormal,
glColor, glTexCoord!
•  varying: le variabili di tipo varying servono a definire
proprietà il cui valore verrà automaticamente interpolato
durante l’esecuzione del fragment shader (es. colore di un
pixel dato il colore dei vertici adiacenti!
KAEMaRT – Michele Antolini!
GLSL – Simple Example!
Semplice esempio di vertex e fragment
shader che permettono l’assegnazione di
una temperatura ad ogni vertice e
visualizzarla sotto forma di colore!
KAEMaRT – Michele Antolini!
GLSL – Simple Example – Vertex Shader!
// Global variables
// uniform qualified variables are changed at most once per primitive
uniform float CoolestTemp;
uniform float TempRange;
// attribute qualified variables are typically changed per vertex
attribute float VertexTemp;
// out qualified variables communicate from the vertex shader to
// the fragment shader
varying float Temperature;
void main() {
// compute a temperature to be interpolated per fragment,
// in the range [0.0, 1.0]
Temperature = (VertexTemp - CoolestTemp) / TempRange;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
KAEMaRT – Michele Antolini!
GLSL – Simple Example – Vertex Shader!
•  Le variabili uniform CoolestTemp e TempRange
definiscono parametri di tipo generale per lo shader!
•  L’attribute VertexTemp viene assegnato per ogni vertice
specificato!
•  La variabile varying Temperature viene
automaticamente interpolata tra i valori dei vertici
adiacenti quando verrà eseguito il fragment shader!
•  Notare l’uso di tre variabili built-in: !
•  gl_Position, gl_ModelViewProjectionMatrix e gl_Vertex!
KAEMaRT – Michele Antolini!
GLSL – Simple Example – Fragment Shader!
// Global variables
// vec3 declares a vector of three floating-point numbers
uniform vec3 CoolestColor;
uniform vec3 HottestColor;
// Temperature contains the now interpolated per-fragment
// value of temperature set by the vertex shader
varying float Temperature;
void main() {
// get a color between coolest and hottest colors, using
// the mix() built-in function
vec3 color = mix(CoolestColor, HottestColor, Temperature);
// make a vector of 4 floating-point numbers by appending an
// alpha of 1.0, and set this fragment’s color
gl_FragColor = vec4(color, 1.0);
}
KAEMaRT – Michele Antolini!
GLSL – Simple Example – Fragment Shader!
•  Le variabili uniform sono diverse dal vertex shader. !
•  Si possono infatti impostare più variabili uniform
nell’applicazione, ed utilizzarne solo alcune all’interno
degli shader!
•  La variabile varying Temperature ha già un valore
interpolato (0, 1) in base alla distanza dai vertici adiacenti!
•  Il colore del pixel viene calcolato con una semplice
formula (built-in) di interpolazione tra due vettori di 3
elementi (la funzione mix)!
•  L’esecuzione dei fragment shader è parallela!
KAEMaRT – Michele Antolini!
GLSL – Data Types!
•  I tipi di dati utilizzabili per il GLSL sono raggruppati in:!
• scalari!
• vettori!
• matrici!
• samplers!
• struct!
• array!
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Scalari!
!
float: singola precisione, virgola mobile!
int: numero intero!
bool: flag booleano!
!
•  non supportati operatori sui bit come shift (<<, >>)
o and bit a bit (&)!
•  gli interi hanno precisione di 16bit più il segno,
quindi [-65535, 65535]!
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Vettori!
!
vec2, vec3, vec4: vettore di 2,3 o 4 float!
ivec2, ivec3, ivec3: vettore di 2,3 o 4 int!
bvec2, bvec3, bvec4: vettore di 2,3 o 4 bool!
!
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Vettori!
!
•  Le componenti di un vettore si possono
richiamare con i suffissi:!
§  .x, .y, .z, .w: il vettore viene trattato come
posizione o direzione!
§  .r, .g, .b, .a: il vettore viene trattato come un
colore!
§  .s, .t, .p, .q: il vettore viene trattato come
coordinate texture!
•  Oppure tramite l’indice tra [] ( es. p[0] )!
!
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Matrici!
!
mat2, mat3, mat4: matrici 2x2, 3x3, 4x4 di float!
!
•  Le matrici vengono indicizzate per colonna, riga!
•  m[0] restituisce un vec* contenente gli elementi
della colonna 0 della matrice m!
•  m[0][1] indica l’elemento 1 della colonna 0 di m!
•  I prodotti con scalari, vettori matrici vengono
trattati secondo le regole dell’algebra
(convenzione: le matrici premoltiplicano i vettori)!
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Samplers!
!
sampler1D, sampler2D, sampler3D: texture mono,
bi o tridimensionale!
samplerCube: texture cube-map!
sampler1DShadow, sampler2DShadow: depth
texture mono o bidimensionale per shadow
mapping!
!
I sampler possono essere solo variabili di tipo
uniform!
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Samplers!
<vertex shader>!
uniform sampler2D my_texture;
...
void main( void ) {
vec3 texColor = texture2D( my_texture,
gl_MultiTexCoord0.st )
...
}
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Samplers (vertex shader)!
!
uniform sampler2D my_texture;
varying vec2 my_texCoord0;
void main( void ) {
//ricava il colore della texture 0 alle coordinate del
vertice corrente
vec3 texColor = texture2D( my_texture,
gl_MultiTexCoord0.st )
//manda al fragment shader le coordinate texture del
vertice (verranno automaticamente interpolate dato che si
tratta di una variabile varying
my_texCoord0 = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
}
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Samplers (fragment shader)!
!
uniform sampler2D my_texture;
varying vec2 my_texCoord0;
void main( void ) {
//ricava il colore del pixel corrente in base alle
coordinate texture interpolate
gl_FragColor = texture2D(my_texture, my_TexCoord0);
}
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Struct!
!
E’ possibile definire struct come in C:!
struct light {
vec3 position;
vec3 color;
}
Non solo ammessi tipi union, enum, class
KAEMaRT – Michele Antolini!
GLSL – Data Types!
Array!
!
E’ possibile creare array di qualunque tipo !
vec4 points[10]
!
•  Se gli array non sono parametri di una funzione, possono
essere dichiarati senza dimensione.!
vec4 points[]
!
•  Possono essere ridichiarati con la dimensione specificata,
altrimenti viene calcolata la dimensione in base all’indice
più alto utilizzato!
KAEMaRT – Michele Antolini!
GLSL – Inizializzazione/Costruttori!
vec4 v = vec4(1.0, 2.0, 3.0, 4.0);
vec4 v2;
v2 = vec4(1.0, 2.0, 3.0, 4.0);
vec3 color = vec3(0.2, 0.5, 0.8);
vec4 color4 = vec4(color, 1.0);
KAEMaRT – Michele Antolini!
GLSL – Inizializzazione/Costruttori!
struct light
{
vec4 position;
struct tLightColor {
vec3 color;
float intensity;
} lightColor;
} light1 = light(v, tLightColor(color, 0.9));
vec4 p = light1.position;
float f = light1.lightColor.intensity;
float a[4] = float[4](1.0, 1.0, 0.0, 1.0 );
KAEMaRT – Michele Antolini!
GLSL – Inizializzazione/Costruttori!
•  mat2 Matrix0 = mat2( 1.0, 2.0, 3.0, 4.0 );
!risulta:
"1.0 3.0 %
$
'
#2.0 4.0 &
•  vec3 v = vec3(0.6);!
!equivalente a!
vec3 v = vec3(0.6, 0.6, 0.6);
€
•  mat2 m = mat2(1.0); //matrice identità 2x2
KAEMaRT – Michele Antolini!
GLSL – Type Matching – Type Conversion!
•  In GLSL non c’è il casting automatico dei tipi, ma ogni
variabile deve essere utilizzata seguendo le intestazioni
formali delle funzioni!
•  I passaggi da un tipo all’altro devono essere esplicite!
float f = 2.3;
bool b = bool(f);
float f = float(3); // integer 3 to floating-point 3.0
float g = float(b); // Boolean b to floating point
vec4 v = vec4(2);
// set all components of v to 2.0
KAEMaRT – Michele Antolini!
GLSL - Swizzling!
•  Utilizzando l’operatore . è possible riarrangiare i
componenti di una struttura elencandone i nomi!
•  Questa procedura si chiama swizzling !
!
vec4 v4;
v4.rgba; //
v4.rgb; //
v4.b;
//
v4.xy;
//
v4.xgba; //
come from
is a vec4 and the same as just using v4
is a vec3
is a float
is a vec2
is illegal - the component names do not
the same set
KAEMaRT – Michele Antolini!
GLSL - Swizzling!
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0);
vec4 swiz = pos.wzyx; // swiz = (4.0, 3.0, 2.0, 1.0)
vec4 dup = pos.xxyy; // dup = (1.0, 1.0, 2.0, 2.0)
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0);
pos.xw = vec2(5.0, 6.0); // pos = (5.0, 2.0, 3.0, 6.0)
pos.wx = vec2(7.0, 8.0); // pos = (8.0, 2.0, 3.0, 7.0)
pos.xx = vec2(3.0, 4.0); // illegal - 'x' used twice
KAEMaRT – Michele Antolini!
GLGL – Operazioni su componenti!
Vettore/Scalare:!
!
vec3 v, u;
float f;
v = u + f;
!
Equivalente a:!
!
v.x = u.x + f;
v.y = u.y + f;
v.z = u.z + f;
KAEMaRT – Michele Antolini!
GLGL – Operazioni su componenti!
Vettore/Vettore:!
!
vec3 v, u, w;
w = v + u;!
!
Equivalente a:!
!
w.x = v.x + u.x;
w.y = v.y + u.y;
w.z = v.z + u.z;
KAEMaRT – Michele Antolini!
GLGL – Operazioni su componenti!
!
Tutte le operazioni aritmetiche agiscono elemento per elemento, tranne il
prodotto vettore/matrice, matrice/vettore e matrice/matrice (eseguito
secondo le regole dell’algebra lineare)!
!
vec4 v, u;
mat4 m;
v * u; // Prodotto componente per componente
v * m; // Prodotto vettore riga con matrice
m * v; // Prodotto matrice con vettore colonna
m * m; // Prodotto matrice con matrice
KAEMaRT – Michele Antolini!
GLSL – Uso nell’applicazione!
Per installare ed utilizzare uno shader è necessario:!
!
1.  Creare uno o più shader vuoti con glCreateShader!
2.  Fornire il codice sorgente (sotto forma di array di string)
con glShaderSource!
3.  Compilare gli shader con glCompileShader!
4.  Creare un oggetto program con glCreateProgram!
5.  Connettere gli shader al program con glAttachShader!
6.  Link-are il program con glLinkProgram!
7.  Impostare il programma nello stato corrente con
glUseProgram!
KAEMaRT – Michele Antolini!
GLSL – Application Code!
#include <GLEW/glew.h> //includere GL Extensions Wrapper
void setShaders() {
char *vs,*fs;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead(”myshader.vert");
fs = textFileRead(”myshader.frag");
const char * vv = vs;
const char * ff = fs;
glShaderSource(v, 1, &vv, NULL);
glShaderSource(f, 1, &ff, NULL);
free(vs);free(fs);
glCompileShader(v);
glCompileShader(f);
p = glCreateProgram();
glAttachShader(p,v);
glAttachShader(p,f);
glLinkProgram(p);
glUseProgram(p); // glUseProgram(0) per disattivare uno shader
}
KAEMaRT – Michele Antolini!
GLSL – Impostazione parametri!
•  Per impostare parametri uniform o attribute deve essere
prima richiesta la location (un identificatore) in base al
nome del parametro (formato stringa)!
•  Parametri uniform:!
Glint loc1 = glGetUniformLocation(program,
”CoolestTemp");
glUniform1f(loc1,myTemp);
•  esistono le varianti glUniform 2f, 3f, 4f, v !
KAEMaRT – Michele Antolini!
GLSL – Impostazione parametri!
•  Parametri attribute:!
•  Specificati tra glBegin() e glEnd()!
Glint loc2 = glGetAttribLocation(program, "height");
glBegin(GL_TRIANGLE_STRIP);
glVertexAttrib1f(loc2,2.0);
glVertex2f(-1,1);
...
glEnd();
•  esistono le varianti glVertexAttrib 2f, 3f, 4f, v !
KAEMaRT – Michele Antolini!
GLSL - Particles!
•  Gli shaders possono essere utilizzati anche per produrre
animazioni!
•  Primo tipo: modifica ad ogni frame delle caratteristiche
della superficie dell’oggetto su cui è applicato lo shader
(utilizzando il fragment shader)!
•  Secondo tipo: modifica ad ogni frame (in funzione del
tempo) della posizione di un particolare vertice (vertex
shader)!
•  Quest’ultima tecnica permette di sfruttare la potenza di
calcolo parallelo della GPU per ricalcolare la posizione di
una serie di punti!
KAEMaRT – Michele Antolini!
GLSL – Toon Shader Example!
KAEMaRT – Michele Antolini!
GLSL – Toon Shader Example!
Vertex shader:!
!
varying vec3 Normal;
void main(void)
{
//passo al fragment shader il vettore normale
Normal = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
KAEMaRT – Michele Antolini!
GLSL – Toon Shader Example!
Fragment shader:!
uniform
uniform
uniform
uniform
vec3 DiffuseColor; //default (0.0, 0.25, 1.0)
vec3 PhongColor; //default (0.75, 0.75, 1.0)
float Edge; //default 0.5
float Phong; //default 0.98
varying vec3 Normal;
void main (void) {
vec3 color = DiffuseColor;
float f = dot(vec3(0,0,1),Normal);
if (abs(f) < Edge)
color = vec3(0);
if (f > Phong)
color = PhongColor;
gl_FragColor = vec4(color, 1);
}
KAEMaRT – Michele Antolini!
GLSL – Effetti particellari!
KAEMaRT – Michele Antolini!
GLSL – Effetti particellari – Vertex Shader!
uniform float time; //il tempo viene incrementato per ogni frame
varying vec4 Color;
const float radius = 0.3;
void main(void) {
vec4 vertex = gl_Vertex; //coordinate non trasformate
float t1 = mod(time, 5.0);
vertex.x = radius * gl_Color.y * t1 * sin(gl_Color.x * 6.28);
vertex.z = radius * gl_Color.y * t1 * cos(gl_Color.x * 6.28);
float h = gl_Color.y * 1.25;
float t2 = mod(t1, h*2.0);
vertex.y = -(t2-h)*(t2-h)+h*h;
vertex.y -= 1.0;
gl_Position = gl_ModelViewProjectionMatrix * vertex;
Color.r = 1.0;
Color.g = 1.0 - gl_Color.y;
Color.b = 0.0;
Color.a = 1.0 - t1 / 5.0;
}
KAEMaRT – Michele Antolini!
GLSL – Effetti particellari – Fragment Shader !
varying vec4 Color;
void main (void)
{
gl_FragColor = Color;
}
KAEMaRT – Michele Antolini!
GLSL - Particles!
•  Animazioni: ridisegno ciclico della scena!
•  Due metodi per chiamare la glutPostRedisplay():!
•  al termine della funzione Display()!
•  all’interno della glutTimerFunc impostando un
framerate specifico!
•  Si aggiorna una variabile uniform per far ricalcolare agli
shaders il nuovo frame!
KAEMaRT – Michele Antolini!
GLSL – Utility function!
char *textFileRead(char *fn) {
FILE *fp;
char *content = NULL;
int count=0;
if (fn != NULL) {
fp = fopen(fn,"rt");
if (fp != NULL) {
fseek(fp, 0, SEEK_END);
count = ftell(fp);
rewind(fp);
if (count > 0) {
content = (char *)malloc(sizeof(char) * (count+1));
count = fread(content,sizeof(char),count,fp);
content[count] = '\0';
}
fclose(fp);
}
}
return content;
}
KAEMaRT – Michele Antolini!
GLSL – Utility function!
int printOglError()
{
//
// Returns 1 if an OpenGL error occurred, 0 otherwise.
//
GLenum glErr;
int
retCode = 0;
glErr = glGetError();
while (glErr != GL_NO_ERROR)
{
printf("glError: %s\n", gluErrorString(glErr));
fflush(stdout);
retCode = 1;
glErr = glGetError();
}
return retCode;
}
KAEMaRT – Michele Antolini!
GLSL – Tutorials - Libri!
Lighthouse 3D!
http://www.lighthouse3d.com/opengl/glsl/index.php?intro!
!
3D Shaders (R. Rost, OpenGL Shading Language Orange Book)!
http://www.3dshaders.com/home/!
!
!
KAEMaRT – Michele Antolini!