Prossimo passo: Aggiungiamo attributi (per vertice!) Roadmap: 1. includiamoli nel buffer 2. facciamoli prendere dal vetex puller 3. usiamoli nel vertex shader 4. (verranno inteprolati autmaticamente nel rast.) 5. usiamo la loro interpolaz nel fragment shader ES: attributo COLORE Se abbiamo, per ogni vertice: X,Y,Z (geometria = attributo di indice 0) R,G,B (attributo colore = attributo di indice 1) Vari modi per formattare dati: in un buffer interleaved: X0,Y0,Z0,R0,G0,B0, X1,Y1,Z1,R1,G1,B1, in buffer separati: X0,Y0,Z0, X1,Y1,Z1, R0,G0,B0, R1,G1,B1, oppure anche: X0,X1, Y0,Y1, Z0,Z1, R0,R1, G0,G1 etc segliamo questo Grafica computazionale - Es 01 1
Attributo colore Un secondo indice, per un altro attributo const positionattribindex = 0; const rgbattributeindex = 1; (globali, costanti) Aggiungiamo i dati es: un vertice blu, uno verde, uno rosso: var positions = [ 0.0, 0.0, 0.0,0.0,1.0, // 1st vertex 1.0, 0.0, 0.0,1.0,0.0, // 2nd vertex 0.0, 1.0, 1.0,0.0,0.0, // 3rd vertex ]; X0 Y0 R0 G0 B0 X1 Y1 R1 G1 B1 X2 Spieghiamo il formato dei buffer al Vertex Puller Attributo Posizione: n. elem = 2 (float) Buffer: X0 Y0 R0 G0 B0 X1 Y1 R1 G1 B1 X2 stride = 5 x 4 bytes stride gl.vertexattribpointer( positionattributeindex, 2, gl.float, false, 5*4, 0); Grafica computazionale - Es 01 2
Spieghiamo il formato dei buffer al Vertex Puller Attributo Colore: n. elem = 3 (floats) Buffer: X0 Y0 R0 G0 B0 X1 Y1 R1 G1 B1 X2 offset = 2 x 4 bytes stride = 5 x 4 bytes stride gl.vertexattribpointer( colorattributeindex, 3, gl.float, false, 5*4, 2*4); Negli shaders: prima attribute vec2 aposition; void main(void) { gl_position = vec4( aposition, 0.0, 1.0 ); } VERTEX Shader void main(void) { gl_fragcolor = vec4(0.0, 0.0, 1.0, 1.0); } FRAG Shad. Grafica computazionale - Es 01 3
Negli shaders: dopo L I N K attribute vec2 position; attribute vec3 basecolor; varying vec3 color; void main(void) { gl_position = vec4( position, 0.0, 1.0 ); color = basecolor ; } precision highp float; varying vec3 color; void main(void) { gl_fragcolor = vec4( color, 1.0); } VERTEX Shader FRAGMENT Shader Linguaggio GLSL: classi di allocazione attribute vec3 basecolor; varying vec3 color; attribute valore definito su ogni vertice nel vertex shader: INPUT (sola lettura) nel fragment shader: non usato varying valore che varia dentro la primitiva nel vertex shader: OUTPUT (sola scrittura) interpolato dal rasterizzatore nel fragment shader: INPUT (sola lettura) Grafica computazionale - Es 01 4
Linking di vertex e fragment shader Vertex Shader: input: gli attributes output: i varyings gl_position (vec4) LINK Fragment Shader: input: i varyings output: gl_fragcolor (vec4) gl_depth (float) (opzionale) Linguaggio GLSL: (per completezza) altre classi di allocazione const vec3 PINK_COLOR = vec3( 1.0, 0.5, 0.5 ); niente vec3 tmp ; const valore costante, noto a compilazione definito quando dichiarato (obbligatoriamente) risolto direttamente dal compilatore temporanea valore usa e getta, di lavoro var locale o globale lettura / scrittura nota: non sopravvive mai allo shader! (neanche se globale) Grafica computazionale - Es 01 5
Prossimo passo: Usiamo struttura mesh indexed Due tipi di buffer, detti: ARRAY_BUFFER array di vertici geometria + attributi, per vertice ELEMENT_ARRAY_BUFFER array di indici indici di vertice, per primitiva (element) connettività della mesh (l unico che usavamo prima) Prima mesh indicizzata: Un quad con diagonal split (4 vertici, 2 tris) V2 V3 var indices = [ 0,1,2, // 1st triangle 1,3,2, // 2nd triangle ]; V0 V1 Grafica computazionale - Es 01 6
Prepariamo il buffer di indici Un buffer ulteriore per la connettività della mesh Similmente agli altri buffer: var elbufferid = gl.createbuffer(); gl.bindbuffer(gl.element_array_buffer, elbufferid ); var indices = [ 0,1,2, // 1st triangle 1,3,2, // 2nd triangle ]; var indexdata = new Uint16Array( indices ); gl.bufferdata( gl.element_array_buffer, indexdata, gl.static_draw ); Dopo la bind, tutte le op su Element Array Buffer (rendering compreso) si riferiranno a questo buffer Disegnamo la mesh indicizzata gl.drawarrays( gl.triangles, 0, 3 ); mesh non indicizzata, quanti vertici (ogni 3 = un tri) gl.drawelements( gl.triangles, 6, gl.unsigned_short, 0 ); mesh indicizzata quanti indici di vertice (ogni 3 = un tri) tipo di ogni indice (short = 16 bit = 64K vertici max) da quale indice partire Grafica computazionale - Es 01 7
Piccole domande Come fai ad eseguire l altro diagonal split? (a dividere il quadrilatero diversamente nei due triangoli)? Vengono prodotti più o meno frammenti? Il risultato a schermo è indentico o differente? (pensa agli attributi nel punto in mezzo alla diagonale) Per una visione d insieme del codice, vedere l implementazione sul sito: Esercitaz 01 Consiglio: invece che utilizzare l implementazione fornita, scrivere la propria implementando uno ad uno tutti i passi come descritto qui, a partire dall esercitaz 00 Grafica computazionale - Es 01 8
WebGL pipeline con attributi e indexed Mesh: vertex buffer index buffer GPU-RAM vertex puller Input Vertex: XYZ (object space) + input attributes vertex shader Transformed Vertex: XYZW (clip space) + computed varying primitive assembler (& setup) Primitive: point (1xV) line (2xV) triangle (3xV) r r WebGL pipeline : rasterizer punti rasterizer lines rasterizer triangles Fragments: buffer pos (fixed, XY) + interpolated varying fragment shader Pixels: RGBa output combiner RGBa buffer to screen GPU-RAM Grafica computazionale - Es 01 9