Introdução ao WebGL Pedro Costa 2014
Brevíssima Introdução ao Javascript
Variáveis Tipificação solta var a; // para tudo Princípio de incerteza c = 2; c já existia? Who cares!
Objectos Podem ser criados do nada var a = { ; Ou a partir de uma função function Fruta() { var b = new Fruta();
Propriedades de Objectos Podem-se declarar assim var a = { propname1: 2, propname2: str ; function Fruta() { this.propname1 = 2; this.propname2 = str ; Ou assim a.propname1 = 2; a[ propname1 ] = 2; Podem-se aceder como em C++ b = a.propname1; b = a[ propname1 ];
Funções = Objectos function mastigacomida() { var a = mastigacomida; a(); // mastigada
Arrays Podem ser criados assim var a = [ ]; var b = [ batata, tomate ]; E acedidos como em C var b = array[1];
Operações e Propriedades de Arrays Propriedade length a.length Operações úteis a.sort() a.push(b) a.pop() a.slice(1,3) a.concat(array2, array3) a.reverse()
Herança Em C++ -> Classes Em JavaScript -> Protótipos de Objectos Baseado na clonagem de objectos individuais Declaração Fruit.prototype = { grow: function() {, shrink: function() { Utilização Banana.prototype = new Fruit(); var b = new Banana(); b.grow();
Consultar w3schools www.w3schools.com/js/default.asp Code academy www.codecademy.com/en/tracks/javascript
Transição de OpenGL para WebGL
Corre no browser <html> <head> </html> <meta http-equiv="content-type" content="text/html; charset=iso- 8859-1"> </head> <title></title> <script type="text/javascript"> </script> <body onload="webglstart();"> </body>
Inicialização <script type= text/javascript > var gl; function webglstart() { var canvas = document.createelement( canvas ); canvas.id = mycanvas ; canvas.width = 0.99*window.innerWidth; canvas.height = 0.98*window.innerHeight; document.body.appendchild(canvas);...
Inicialização try { gl = canvas.getcontext( experimental-webgl ); gl.viewportwidth = canvas.width; gl.viewportheight = canvas.height; catch (e) { if (!gl) { alert( Could not initialise WebGL, sorry :-( );...
Inicialização... initshaders(); initbuffers(); gl.clearcolor(0.0, 0.0, 0.0, 1.0); gl.enable(gl.depth_test); </script> drawscene();
Os shaders <head> <meta http-equiv="content-type" content="text/html; charset=iso- 8859-1"> </head> <title></title> <script id="shader-vs" type="x-shader/x-vertex"> </script> <script id="shader-fs" type="x-shader/x-fragment"> </script> <script type="text/javascript"> </script>
Recolher os shaders 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;...
Recolher os shaders 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);...
Recolher os shaders... if (!gl.getshaderparameter(shader, gl.compile_status)) { alert(gl.getshaderinfolog(shader)); return null; return shader;
Inicializar os shaders 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("could not initialise shaders");
Inicializar os shaders gl.useprogram(shaderprogram); shaderprogram.vertexpositionattribute = gl.getattriblocation(shaderprogram, "position"); shaderprogram.normalattribute = gl.getattriblocation(shaderprogram, "normal"); shaderprogram.texattribute = gl.getattriblocation(shaderprogram, "texcoord"); gl.enablevertexattribarray(shaderprogram.vertexpositionattribute); gl.enablevertexattribarray(shaderprogram.normalattribute); gl.enablevertexattribarray(shaderprogram.texattribute); shaderprogram.pmatrixuniform = gl.getuniformlocation(shaderprogram, "upmatrix"); shaderprogram.mvmatrixuniform = gl.getuniformlocation(shaderprogram, "umvmatrix");
Inicializar os buffers var vertices = [0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0]; var texcoords = [0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]; var normals = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0]; var vertexstride = 4; var faceindex = [0, 1, 2, 2, 3, 0]; var normalsstride = 3; var texstride = 2; var faceindexstride = 1;
Inicializar os buffers function initbuffers() { quadvertexpositionbuffer = gl.createbuffer(); gl.bindbuffer(gl.array_buffer, quadvertexpositionbuffer); gl.bufferdata(gl.array_buffer, new Float32Array(vertices), gl.static_draw); quadvertexpositionbuffer.itemsize = vertexstride; quadvertexpositionbuffer.numitems = vertices.length/vertexstride; // igual para buffers de normais e texturas, ajustando itemsize & numitems
Inicializar os buffers faceindexbuffer = gl.createbuffer(); gl.bindbuffer(gl.element_array_buffer, faceindexbuffer); gl.bufferdata(gl.element_array_buffer, new Uint16Array(faceIndex), gl. STATIC_DRAW); faceindexbuffer.itemsize = faceindexstride; faceindexbuffer.numitems = faceindex.length/faceindexstride;
Desenhar function drawscene() { gl.viewport(0, 0, gl.viewportwidth, gl.viewportheight); gl.clear(gl.color_buffer_bit gl.depth_buffer_bit); mat4.perspective(45, gl.viewportwidth / gl.viewportheight, 0.1, 100.0, pmatrix); mat4.identity(mvmatrix); gl.bindbuffer(gl.array_buffer, quadvertexpositionbuffer); gl.vertexattribpointer(shaderprogram.vertexpositionattribute, quadvertexpositionbuffer.itemsize, gl.float, false, 0, 0);
Desenhar gl.bindbuffer(gl.array_buffer, normalbuffer); gl.vertexattribpointer(shaderprogram.normalattribute, normalbuffer.itemsize, gl. FLOAT, false, 0, 0); gl.bindbuffer(gl.array_buffer, texbuffer); gl.vertexattribpointer(shaderprogram.texattribute, texbuffer.itemsize, gl.float, false, 0, 0); gl.bindbuffer(gl.element_array_buffer, faceindexbuffer); setmatrixuniforms(); gl.drawelements(gl.triangles, faceindexbuffer.numitems, gl.unsigned_short, 0); // VAOs??
E as matrizes? var pmatrix; var mvmatrix; function setmatrixuniforms() { gl.uniformmatrix4fv(shaderprogram.pmatrixuniform, false, pmatrix); gl.uniformmatrix4fv(shaderprogram.mvmatrixuniform, false, mvmatrix);
Adicionar texturas function inittextures() { text = gl.createtexture(); text.image = new Image(); text.image.onload = function () { handleloadedtexture(text); text.image.src = "nehe.gif";
Adicionar texturas function handleloadedtexture(text) { gl.bindtexture(gl.texture_2d, text); gl.pixelstorei(gl.unpack_flip_y_webgl, true); gl.teximage2d(gl.texture_2d, 0, gl.rgba, gl.rgba, gl.unsigned_byte, text.image); gl.texparameteri(gl.texture_2d, gl.texture_mag_filter, gl.nearest); gl.texparameteri(gl.texture_2d, gl.texture_min_filter, gl.nearest); gl.bindtexture(gl.texture_2d, null);
Adicionar texturas function webglstart() { initshaders(); initbuffers(); inittextures(); gl.clearcolor(0.0, 0.0, 0.0, 1.0); gl.enable(gl.depth_test); drawscene();
Adicionar texturas function initshaders() { // get uniform for textures shaderprogram.sampleruniform = gl.getuniformlocation(shaderprogram, "usampler");
Desenhar texturas function drawscene() { gl.activetexture(gl.texture0); gl.bindtexture(gl.texture_2d,text); gl.uniform1i(shaderprogram.sampleruniform, 0); gl.bindbuffer(gl.array_buffer, quadvertexpositionbuffer); gl.vertexattribpointer(shaderprogram.vertexpositionattribute, quadvertexpositionbuffer.itemsize, gl.float, false, 0, 0);
glmatrix Biblioteca de cálculo matricial e vectorial para WebGL Criado por Brandon Jones Operações para 4x4, 3x3 e vectores tri-dimensionais
glmatrix - operadores básicos // nova matrix var A = mat4.create(); // A = A.B mat4.multiply(a, B); // A = I 4x4 mat4.identity(a); // C = A.B mat4.multiply(a, B, C);
glmatrix - operadores básicos // copiar matrix A para a matrix B mat4.set(a, B); // returnar uma string que representa a matrix A mat4.str(a);
glmatrix - transformações // init um vector var b = vec3.create([1 1 0]); // init outro vector var c = vec3.create([2 2 1]); // A = T(b).A mat4.translate(a, b); // A = S(c).A mat4.scale(a, c); // B = T(b).A mat4.translate(a, b, B); // B = S(c).A mat4.scale(a, c, B);
glmatrix - transformações // init um vector var b = vec3.create([0 0 1]); // A = R(90º,b).A mat4.rotate(a, Math.PI / 2, b); // A = R x (90º).A mat4.rotatex(a, Math.PI / 2); // B = R(90º,b).A mat4.rotate(a, Math.PI / 2, b, B); // B = R y (90º).A mat4.rotatey(a, Math.PI / 2, B);
glmatrix - matriz normal // init var nmatrix = mat3.create(); // nmatrix = [modelview] 3x3-1 mat4.toinversemat3(modelview, nmatrix); // nmatrix = [ [modelview] 3x3-1 ] T mat3.transpose(nmatrix);
glmatrix - projecções e lookat // projecção ortogonal var orth = mat4.ortho(left, right, bottom, top, near, far); // projecção perspectiva var pers = mat4.perspective(fov, aspect, near, far); // eye, center e up são vec3s var lookatmat = mat3.lookat(eye, center, up);
Voltando à aplicação - o game loop function webglstart() { initshaders(); initbuffers(); inittextures(); gl.clearcolor(0.0, 0.0, 0.0, 1.0); gl.enable(gl.depth_test); drawscene();
O game loop function webglstart() { initshaders(); initbuffers(); inittextures(); gl.clearcolor(0.0, 0.0, 0.0, 1.0); gl.enable(gl.depth_test); loop();
O game loop function loop() { requestanimframe(loop); drawscene(); update(); Biblioteca WebGL Fundamentals API comum providenciada pelos developers dos browsers Controlar e optimizar o refrescamento
Teclado function webglstart() { inittextures(); gl.clearcolor(0.0, 0.0, 0.0, 1.0); gl.enable(gl.depth_test); document.onkeydown = handlekeydown; document.onkeyup = handlekeyup; loop();
Teclado var currentlypressedkeys = {; function handlekeydown(event) { currentlypressedkeys[event.keycode] = true; if (String.fromCharCode(event.keyCode) == "F") { function handlekeyup(event) { currentlypressedkeys[event.keycode] = false;
Teclado function loop() { requestanimframe(loop); handlekeys(); drawscene(); update(); function handlekeys() { if (currentlypressedkeys[33]) { // Page Up z -= 0.05; JavaScript key codes http://www.javascripter.net/faq/keycodes.htm
Rato function webglstart() { document.onkeydown = handlekeydown; document.onkeyup = handlekeyup; canvas.onmousedown = handlemousedown; document.onmouseup = handlemouseup; // capturar fora do canvas document.onmousemove = handlemousemove; loop();
Rato var mousedown = false; var lastmousex = null; var lastmousey = null; function handlemousedown(event) { mousedown = true; lastmousex = event.clientx; lastmousey = event.clienty; function handlemouseup(event) { mousedown = false; function handlemousemove(event) { if (!mousedown) return; var newx = event.clientx; var newy = event.clienty; var deltax = newx - lastmousex; var deltay = newy - lastmousey; lastmousex = newx lastmousey = newy;
Mais informações Restante API é semelhante ao que já vimos no OpenGL Learning WebGL http://learningwebgl.com/ WebGL reference https://www.khronos.org/opengles/sdk/docs/man/ WebGL cheat sheet https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf
Sugestões de Estruturação da Aplicação
Estrutura Modular <html> <head> <script type="text/javascript" src="log.js"></script> <script type="text/javascript" src="frog.js"></script> <script type="text/javascript" src="game.js"></script> </head> <body onload="webglstart();"> </body> </html>
Mantém-se o Resto Game.prototype.draw = function() { Game.prototype.update = function (dt) { Game.prototype.reset = function() { Frog.prototype.draw = function() { Frog.prototype.collides = function(other) { // etc etc etc
Inicializar a aplicação <script type= text/javascript > var game = new Game(); function webglstart() { var canvas = document.createelement( canvas ); canvas.id = mycanvas ; canvas.width = 0.99*window.innerWidth; canvas.height = 0.98*window.innerHeight; document.body.appendchild(canvas); game.init(canvas); </script>
Inicializar a aplicação Game.prototype.init = function(canvas) { initgl(canvas); initshaders(); initbuffers(); inittextures(); gl.clearcolor(0.0, 0.0, 0.0, 1.0); gl.enable(gl.depth_test); loop();
Fim