Salve a tutti!


Ora Analizzeremo l’ultima della funzioni di Inizializzazione:


Function: InitBuffer


I compiti della funzione:
1. Creare i Buffer
2. Riempire essi con i valori di partenza


Qua riportiamo il codice della funzione nel nostro esempio:


var triangleVertexPositionBuffer;
function initBuffers() {
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0,  1.0,  0.0,
-1.0, -1.0,  0.0,
1.0, -1.0,  0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
}

Notiamo innanzitutto la variabile global che rappresenta il buffer dove salveremo la posizione dei nostri vertici ,triangleVertexPositionBuffer.
Il primo step è la creazione del buffer, con la funzione gl.createBuffer(); terminata l’operazione, viene utilizzata la function bindbuffer(): essa ha il compito di imporre che ogni operazione eseguita successivamente riguarda solo il buffer  triangleVertexPositionBuffer, il quale  diventa perciò  il buffer corrente. Dopo viene creato una matrice 3X3, che corrisponde alle posizioni X,Y e Z dei tre vertici del triangolo.
Successivamente utilizziamo BufferData per creare un Array particolare usando come input la Matrice 3X3 descritta sopra .Infine vengono impostate due proprietà del buffer, salvandoci l’informazione su quanti vertici abbiamo e da quante “componenti” è composta una posizione.Non si tratta di qualcosa che sia integrato in WebGL, ma sarà molto utile in seguito.
Terminate le funzioni di Inizializzazione, non rimane che descrivere l’ultima delle funzioni, cioè quella che effettivamente DISEGNA la scena:


Function: Drawscene


Vista la complessità della funzione, riportiamo i singoli compiti della funzione:
1.inizializzare la viewport e pulisce la scena
2. Definire la prospettiva
3.posizionare gli oggetti da disegnare
6.Convertire array JAVASCRIPT ad array WEBGL
7.disegnare i vertici


Riportiamo ora il codice della funzione che useremo nel nostro esempio:


function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
loadIdentity();
mvTranslate([-1.5, 0.0, -7.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
}
La prima operazione eseguita serve per settare wieport. La viewport non è nient altro che la finestra 2d dove noi proiettiamo e disegniamo la scena 3d che abbiamo calcolato. La funzione gl.clear non fa altro che pulire la scena prima che ci venga disegnato sopra qualcosa. La funzione perspective(..) è piuttosto complessa, essa ha il compito di definire la prospettiva, cioè quell’insieme di proporzioni e altri strumenti matematici che ci permettono di costruire il nostro mondo sulla viewport.Al momento tale funzione( con gli attuali parametri) fa si che verranno rappresentati solo gli oggetti che distano più di 0.1 e meno di 100.0 , con la regola che gli oggetti più lontani sono più piccoli di quelli vicini ( sorvogliamo su questo argomento, lo prenderemo in esame un’altra volta).
Loadidentity viene utilizzato per centralizzare la scena ( nel senso che ci posizioniamo al centro di tutto il nostro mondo 3d: per disegnare un oggetto infatti dobbiamo partire dal centro, spostarci nella locazione desiderata e li far partire il disegno. Questa configurazione corrisponde alla posizione x=0;y=0;z=0 ).
La funzione MvTranslate serve per spostare il centro del nostro elemento da disegnare in certe coordinate 3d ( ricordiamo che essendo in un mondo 3d, per spostarsi bisogna definire una matrice).
Infine notiamo la funzione DrawArrays: come dice il nome, il suo compito è ciclare e disegnare tutti i vertici della scena. Per questione di efficienza, in webgl è meglio disegnare una figura 3d come il l’insieme di tanti triangoli ( per esempio un quadrato può essere visto che due triangoli, un cubo come 12,etc…). La funzione non farà altro che disegnare i vertici a gruppi di tre partenza dall’indice 0 fino a tutta la lunghezza dell’array, definito dal triangleVertexPositionBuffer.numItems.



CONFIGURATION AND STARTED


Al momento quasi tutto è pronto, manca solo il file js con le matrix utility functions: essa non sono nient’altro che alcune funzioni javascript che abbiamo utilizzato la cui definizione al momento non rientra nei precedenti file.Essa riguardando la definizione della LoadIdentity, della MvTranslate ed altro, tutte riguardanti le matrici.
Perciò creiamo un nuovo file chiamato MatriUtilityFunc.js e copia&incolliamo il codice javascript sopra riportato oppure andate su link e scaricatevi l’omonimo file che troverete.
var mvMatrix;
function loadIdentity()
{
mvMatrix = Matrix.I(4);
}
function multMatrix(m)
{ mvMatrix = mvMatrix.x(m); }
function mvTranslate(v)
{
var m = Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4(); multMatrix(m);
}
var pMatrix;
function perspective(fovy, aspect, znear, zfar)
{
pMatrix = makePerspective(fovy, aspect, znear, zfar); }
function setMatrixUniforms() { gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, new Float32Array(pMatrix.flatten()));
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, new Float32Array(mvMatrix.flatten()));
}

Ora si tratta solo di fondere il tutto assieme e testare se la nostra applicazione parte.Riassumendo abbiamo 3 file Javascript ( glUtils,Sylvester.js e  MatriUtilityFunc.js) ed un file html chiamato index.html nel nostro esempio, il cui codice finale è questo:

<html>
<head>
<script id=”shader-fs” type=”x-shader/x-fragment”>
#ifdef GL_ES
precision highp float;
#endif
void main(void) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>
<script id=”shader-vs” type=”x-shader/x-vertex”>
attribute vec3 aVertexPosition;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
}
</script>
<script type=”text/javascript” src=”Sylvester.js”></script>
<script type=”text/javascript” src=”glUtils.js”></script>
<script type=”text/javascript” src=”MatriUtilityFunc.js”></script>
<script type=”text/javascript”>
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext(“experimental-webgl”);
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch(e) {
}
if (!gl) {
alert(“Impossibile Inizializzare WebGL”);
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = “”;
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == “x-shader/x-fragment”) {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == “x-shader/x-vertex”) {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, “shader-fs”);
var vertexShader = getShader(gl, “shader-vs”);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert(“Non posso inizializzare gli shader”);
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, “aVertexPosition”);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, “uPMatrix”);
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, “uMVMatrix”);
}
var triangleVertexPositionBuffer;
function initBuffers() {
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0,  1.0,  0.0,
-1.0, -1.0,  0.0,
1.0, -1.0,  0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
}
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
loadIdentity();
mvTranslate([-1.5, 0.0, -7.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,  triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
}
function Start() {
var canvas = document.getElementById(“Mycanvas”);
initGL(canvas);
initShaders();
initBuffers();
setInterval(tick, 15);
}
function tick()
{
drawScene();
}
</script>
</head>
<body onload=”Start();”>
<canvas id=”Mycanvas” width=”320″ height=”240″></canvas>
</body>
</html>
Vi consiglio di non copia & incollare il codice soprastante, ma di utilizzare direttamente quello presente sul solito link lab.pralevis.com e scaricarvi il file zippato Esempio01.zip. Per testare la nostra applicazione, è importante che i tre file js siano nella stessa cartella o percorso del file .html ( se invece vogliamo spostarli per fare più ordine, dobbiamo modificare i le tre righe che includono i file js , per esempio <script type=”text/javascript” src=”Sylvester.js”></script>, con l’indirizzo src che più ci aggrada).
Terminato ciò, non basta altro che aprire la pagina con il nostro web browser e vedere se il tutto va a buon fine:

esempio01
Se questo è il nostro risultato su Chromium, abbiamo completato il nostro primo Esempio, complimenti :).
Il prossimo articolo riguarderà l’uso dei colori e d’ora in poi verranno anche proposti degli esercizi per aiutarvi a comprendere meglio la materia.

Grazie per l’Attenzione, buone vacanze

Andrea