Spinning Images in WebGL
Join the DZone community and get the full member experience.
Join For Freehere are our demo and downloadable package:
live demo
download in package
ok, download the example files and lets start coding !
step 1. html
here are html sources of our demo. as you can see – just an empty page.
index.html
<!doctype html> <html lang="en" > <head> <link href="css/main.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="js/glmatrix-0.9.5.min.js"></script> <script type="text/javascript" src="js/webgl-utils.js"></script> <script type="text/javascript" src="js/script.js"></script> <title>creating a keyboard sensitive 3d twisted images in webgl | script tutorials</title> </head> <body onload="initwebgl();"> <div class="example"> <h3><a href="http://www.script-tutorials.com/twisting-images-webgl/">creating a keyboard sensitive 3d twisted images in webgl | script tutorials</a></h3> <h3>you can use your mouse + arrow keys + page up / down</h3> <canvas id="panel" width="500" height="333"></canvas> <div style="clear:both;"></div> </div> </body> </html>
step 2. css
here are used css styles.
css/main.css
body { background:#eee; font-family:verdana, helvetica, arial, sans-serif; margin:0; padding:0 } .example { background:#fff; width:500px; font-size:80%; border:1px #000 solid; margin:20px auto; padding:15px; position:relative; -moz-border-radius: 3px; -webkit-border-radius:3px } h3 { text-align:center; }
step 3. js
js/webgl-utils.js and js/glmatrix-0.9.5.min.js
these files we will use in project for working with webgl. both files will in our package.
js/script.js
var gl; // global webgl object var shaderprogram; var pics_names=['1.png', '2.png', '3.png', '4.png', '5.png', '6.png', '7.png']; var pics_num=pics_names.length; // diffirent initializations function initgl(canvas) { try { gl = canvas.getcontext('experimental-webgl'); gl.viewportwidth = canvas.width; gl.viewportheight = canvas.height; } catch (e) {} if (! gl) { alert('can`t initialise webgl, not supported'); } } function getshader(gl, type) { var str = ''; var shader; if (type == 'x-fragment') { str = "#ifdef gl_es\n"+ "precision highp float;\n"+ "#endif\n"+ "varying vec2 vtexturecoord;\n"+ "uniform sampler2d usampler;\n"+ "void main(void) {\n"+ " gl_fragcolor = texture2d(usampler, vec2(vtexturecoord.s, vtexturecoord.t));\n"+ "}\n"; shader = gl.createshader(gl.fragment_shader); } else if (type == 'x-vertex') { str = "attribute vec3 avertexposition;\n"+ "attribute vec2 atexturecoord;\n"+ "uniform mat4 umvmatrix;\n"+ "uniform mat4 upmatrix;\n"+ "varying vec2 vtexturecoord;\n"+ "void main(void) {\n"+ " gl_position = upmatrix * umvmatrix * vec4(avertexposition, 1.0);\n"+ " vtexturecoord = atexturecoord;\n"+ "}\n"; 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; } function initshaders() { var fragmentshader = getshader(gl, 'x-fragment'); var vertexshader = getshader(gl, 'x-vertex'); shaderprogram = gl.createprogram(); gl.attachshader(shaderprogram, vertexshader); gl.attachshader(shaderprogram, fragmentshader); gl.linkprogram(shaderprogram); if (!gl.getprogramparameter(shaderprogram, gl.link_status)) { alert('can`t initialise shaders'); } gl.useprogram(shaderprogram); shaderprogram.vertexpositionattribute = gl.getattriblocation(shaderprogram, 'avertexposition'); gl.enablevertexattribarray(shaderprogram.vertexpositionattribute); shaderprogram.texturecoordattribute = gl.getattriblocation(shaderprogram, 'atexturecoord'); gl.enablevertexattribarray(shaderprogram.texturecoordattribute); shaderprogram.pmatrixuniform = gl.getuniformlocation(shaderprogram, 'upmatrix'); shaderprogram.mvmatrixuniform = gl.getuniformlocation(shaderprogram, 'umvmatrix'); shaderprogram.sampleruniform = gl.getuniformlocation(shaderprogram, 'usampler'); } var objvertexpositionbuffer=new array(); var objvertextexturecoordbuffer=new array(); var objvertexindexbuffer=new array(); function initobjbuffers() { for (var i=0;i<pics_num;i=i+1) { objvertexpositionbuffer[i] = gl.createbuffer(); gl.bindbuffer(gl.array_buffer, objvertexpositionbuffer[i]); vertices = [ math.cos(i*((2*math.pi)/pics_num)), -0.5, math.sin(i*((2*math.pi)/pics_num)), math.cos(i*((2*math.pi)/pics_num)), 0.5, math.sin(i*((2*math.pi)/pics_num)), math.cos((i+1)*((2*math.pi)/pics_num)), 0.5, math.sin((i+1)*((2*math.pi)/pics_num)), math.cos((i+1)*((2*math.pi)/pics_num)), -0.5, math.sin((i+1)*((2*math.pi)/pics_num)), ]; gl.bufferdata(gl.array_buffer, new float32array(vertices), gl.static_draw); objvertexpositionbuffer[i].itemsize = 3; objvertexpositionbuffer[i].numitems = 4; objvertextexturecoordbuffer[i] = gl.createbuffer(); gl.bindbuffer(gl.array_buffer, objvertextexturecoordbuffer[i] ); var texturecoords = [ 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, ]; gl.bufferdata(gl.array_buffer, new float32array(texturecoords), gl.static_draw); objvertextexturecoordbuffer[i].itemsize = 2; objvertextexturecoordbuffer[i].numitems = 4; objvertexindexbuffer[i] = gl.createbuffer(); gl.bindbuffer(gl.element_array_buffer, objvertexindexbuffer[i]); var objvertexindices = [ 0, 1, 2, 0, 2, 3, ]; gl.bufferdata(gl.element_array_buffer, new uint16array(objvertexindices), gl.static_draw); objvertexindexbuffer[i].itemsize = 1; objvertexindexbuffer[i].numitems = 6; } } function handleloadedtexture(texture) { gl.bindtexture(gl.texture_2d, texture); gl.pixelstorei(gl.unpack_flip_y_webgl, true); gl.teximage2d(gl.texture_2d, 0, gl.rgba, gl.rgba, gl.unsigned_byte, texture.image); gl.texparameteri(gl.texture_2d, gl.texture_mag_filter, gl.linear); gl.texparameteri(gl.texture_2d, gl.texture_min_filter, gl.linear); gl.bindtexture(gl.texture_2d, null); } var cratetextures = array(); function inittexture(image) { var crateimage = new image(); var texture = gl.createtexture(); texture.image = crateimage; crateimage.src = image; crateimage.onload = function () { handleloadedtexture(texture) } return texture; } function inittextures() { for (var i=0; i < pics_num; i++) { cratetextures[i]=inittexture(pics_names[i]); } } var mvmatrix = mat4.create(); var mvmatrixstack = []; var pmatrix = mat4.create(); function setmatrixuniforms() { gl.uniformmatrix4fv(shaderprogram.pmatrixuniform, false, pmatrix); gl.uniformmatrix4fv(shaderprogram.mvmatrixuniform, false, mvmatrix); } function degtorad(degrees) { return degrees * math.pi / 180; } // mouse and keyboard handlers var xrot = 0; var xspeed = 0; var yrot = 0; var yspeed = 10; var z = -3.0; var currentlypressedkeys = {}; function handlekeydown(event) { currentlypressedkeys[event.keycode] = true; } function handlekeyup(event) { currentlypressedkeys[event.keycode] = false; } function handlekeys() { if (currentlypressedkeys[33]) { // page up z -= 0.05; } if (currentlypressedkeys[34]) { // page down z += 0.05; } if (currentlypressedkeys[37]) { // left cursor key yspeed -= 1; } if (currentlypressedkeys[39]) { // right cursor key yspeed += 1; } if (currentlypressedkeys[38]) { // up cursor key xspeed -= 1; } if (currentlypressedkeys[40]) { // down cursor key xspeed += 1; } } var mousedown = false; var lastmousex = null; var lastmousey = null; var rotationmatrix = mat4.create(); mat4.identity(rotationmatrix); 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 newrotationmatrix = mat4.create(); mat4.identity(newrotationmatrix); mat4.rotate(newrotationmatrix, degtorad(deltax / 5), [0, 1, 0]); var deltay = newy - lastmousey; mat4.rotate(newrotationmatrix, degtorad(deltay / 5), [1, 0, 0]); mat4.multiply(newrotationmatrix, rotationmatrix, rotationmatrix); lastmousex = newx lastmousey = newy; } // draw scene and initialization var movematrix = mat4.create(); mat4.identity(movematrix); 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); mat4.translate(mvmatrix, [0.0, 0.0, z]); mat4.rotate(mvmatrix, degtorad(xrot), [1, 0, 0]); mat4.rotate(mvmatrix, degtorad(yrot), [0, 1, 0]); mat4.multiply(mvmatrix, movematrix); mat4.multiply(mvmatrix, rotationmatrix); for (var i=0;i<pics_num;i=i+1) { gl.bindbuffer(gl.array_buffer, objvertexpositionbuffer[i]); gl.vertexattribpointer(shaderprogram.vertexpositionattribute, objvertexpositionbuffer[i].itemsize, gl.float, false, 0, 0); gl.bindbuffer(gl.array_buffer, objvertextexturecoordbuffer[i]); gl.vertexattribpointer(shaderprogram.texturecoordattribute, objvertextexturecoordbuffer[i].itemsize, gl.float, false, 0, 0); gl.activetexture(gl.texture0); gl.bindtexture(gl.texture_2d, cratetextures[i]); gl.uniform1i(shaderprogram.sampleruniform, 0); gl.bindbuffer(gl.element_array_buffer, objvertexindexbuffer[i]); setmatrixuniforms(); gl.drawelements(gl.triangles, objvertexindexbuffer[i].numitems, gl.unsigned_short, 0); } } var lasttime = 0; function animate() { var timenow = new date().gettime(); if (lasttime != 0) { var elapsed = timenow - lasttime; xrot += (xspeed * elapsed) / 1000.0; yrot += (yspeed * elapsed) / 1000.0; } lasttime = timenow; } function drawframe() { requestanimframe(drawframe); handlekeys(); drawscene(); animate(); } function initwebgl() { var canvas = document.getelementbyid('panel'); initgl(canvas); initshaders(); initobjbuffers(); inittextures(); gl.clearcolor(1.0, 1.0, 1.0, 1.0); gl.enable(gl.depth_test); document.onkeydown = handlekeydown; document.onkeyup = handlekeyup; canvas.onmousedown = handlemousedown; document.onmouseup = handlemouseup; document.onmousemove = handlemousemove; drawframe(); }
and again – long code, but most important. i separated all code to 3 sides: initializations, handlers and drawing of scene. hope that you already read our previos webgl lesson . in this case it will more easy to understand today`s code. just make attention that instead color buffer we will using texture buffer (objvertextexturecoordbuffer). also, this demo able to work with any amouht of used images (better – more than 3).
step 4. images
all these images we will using for twisting:
live demo
download in package
conclusion
i hope you enjoyed today's result. if you have any suggestions or ideas – share them welcome back, friends!Opinions expressed by DZone contributors are their own.
Comments