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 themOpinions expressed by DZone contributors are their own.
Comments