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!
© Copyright 2024 ExpyDoc