Creating a 3D Animated Box HTML5 WebGL Photo Slideshow.
Step 1. HTML
Here are html sources of our demo. As you can see – just empty page.
index.html
| 04 |
<meta charset=”utf-8″ /> |
| 05 |
<title>WebGL Box photo slideshow | Script Tutorials</title> |
| 07 |
<link href=”css/main.css” rel=”stylesheet” type=”text/css” /> |
| 08 |
<script src=”js/glMatrix-0.9.5.min.js”></script> |
| 09 |
<script src=”js/webgl-utils.js”></script> |
| 10 |
<script src=”js/script.js”></script> |
| 12 |
<body onload=”initWebGl()”> |
| 13 |
<div class=”container”> |
| 14 |
<canvas id=”panel” width=”800″ height=”600″></canvas> |
| 17 |
<h2>WebGL Box photo slideshow</h2> |
Step 2. CSS
Here are used CSS styles.
css/main.css
| 06 |
background-repeat:no-repeat; |
| 07 |
background-color:#bababa; |
| 08 |
background-image: -webkit-radial-gradient(600px 200px, circle, #eee, #bababa 40%); |
| 09 |
background-image: -moz-radial-gradient(600px 200px, circle, #eee, #bababa 40%); |
| 10 |
background-image: -o-radial-gradient(600px 200px, circle, #eee, #bababa 40%); |
| 11 |
background-image: radial-gradient(600px 200px, circle, #eee, #bababa 40%); |
| 13 |
font:14px/1.3 Arial,sans-serif; |
| 17 |
background-color:#212121; |
| 19 |
box-shadow: 0 -1px 2px #111111; |
| 36 |
footer a.stuts,a.stuts:visited{ |
| 43 |
margin:23px 0 0 110px; |
| 53 |
border:3px #111 solid; |
| 60 |
-moz-border-radius:15px; |
| 61 |
-webkit-border-radius:15px; |
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
| 001 |
var gl; // global WebGL object |
| 016 |
var pics_num=pics_names.length; |
| 018 |
// diffirent initializations |
| 020 |
function initGL(canvas) { |
| 022 |
gl = canvas.getContext(’experimental-webgl’); |
| 023 |
gl.viewportWidth = canvas.width; |
| 024 |
gl.viewportHeight = canvas.height; |
| 027 |
alert(’Can`t initialise WebGL, not supported’); |
| 031 |
function getShader(gl, type) { |
| 035 |
if (type == ‘x-fragment’) { |
| 036 |
str = “#ifdef GL_ESn”+ |
| 037 |
“precision highp float;n”+ |
| 039 |
“varying vec2 vTextureCoord;n”+ |
| 040 |
“uniform sampler2D uSampler;n”+ |
| 041 |
“void main(void) {n”+ |
| 042 |
“ gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));n”+ |
| 044 |
shader = gl.createShader(gl.FRAGMENT_SHADER); |
| 045 |
} else if (type == ‘x-vertex’) { |
| 046 |
str = “attribute vec3 aVertexPosition;n”+ |
| 047 |
“attribute vec2 aTextureCoord;n”+ |
| 048 |
“uniform mat4 uMVMatrix;n”+ |
| 049 |
“uniform mat4 uPMatrix;n”+ |
| 050 |
“varying vec2 vTextureCoord;n”+ |
| 051 |
“void main(void) {n”+ |
| 052 |
“ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);n”+ |
| 053 |
“ vTextureCoord = aTextureCoord;n”+ |
| 055 |
shader = gl.createShader(gl.VERTEX_SHADER); |
| 060 |
gl.shaderSource(shader, str); |
| 061 |
gl.compileShader(shader); |
| 063 |
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { |
| 064 |
alert(gl.getShaderInfoLog(shader)); |
| 070 |
function initShaders() { |
| 071 |
var fragmentShader = getShader(gl, ‘x-fragment’); |
| 072 |
var vertexShader = getShader(gl, ‘x-vertex’); |
| 074 |
shaderProgram = gl.createProgram(); |
| 075 |
gl.attachShader(shaderProgram, vertexShader); |
| 076 |
gl.attachShader(shaderProgram, fragmentShader); |
| 077 |
gl.linkProgram(shaderProgram); |
| 079 |
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { |
| 080 |
alert(’Can`t initialise shaders’); |
| 083 |
gl.useProgram(shaderProgram); |
| 085 |
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, ‘aVertexPosition’); |
| 086 |
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); |
| 088 |
shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, ‘aTextureCoord’); |
| 089 |
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); |
| 091 |
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, ‘uPMatrix’); |
| 092 |
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, ‘uMVMatrix’); |
| 093 |
shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, ‘uSampler’); |
| 096 |
var objVertexPositionBuffer=new Array(); |
| 097 |
var objVertexTextureCoordBuffer=new Array(); |
| 098 |
var objVertexIndexBuffer=new Array(); |
| 100 |
function initObjBuffers() { |
| 101 |
for (var i=0;i<4;i=i+1) { |
| 102 |
objVertexPositionBuffer[i] = gl.createBuffer(); |
| 103 |
gl.bindBuffer(gl.ARRAY_BUFFER, objVertexPositionBuffer[i]); |
| 105 |
Math.cos(i*((2*Math.PI)/4)), -0.5, Math.sin(i*((2*Math.PI)/4)), |
| 106 |
Math.cos(i*((2*Math.PI)/4)), 0.5, Math.sin(i*((2*Math.PI)/4)), |
| 107 |
Math.cos((i+1)*((2*Math.PI)/4)), 0.5, Math.sin((i+1)*((2*Math.PI)/4)), |
| 108 |
Math.cos((i+1)*((2*Math.PI)/4)), -0.5, Math.sin((i+1)*((2*Math.PI)/4)), |
| 110 |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); |
| 111 |
objVertexPositionBuffer[i].itemSize = 3; |
| 112 |
objVertexPositionBuffer[i].numItems = 4; |
| 114 |
objVertexTextureCoordBuffer[i] = gl.createBuffer(); |
| 115 |
gl.bindBuffer(gl.ARRAY_BUFFER, objVertexTextureCoordBuffer[i] ); |
| 116 |
var textureCoords = [ |
| 122 |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW); |
| 123 |
objVertexTextureCoordBuffer[i].itemSize = 2; |
| 124 |
objVertexTextureCoordBuffer[i].numItems = 4; |
| 126 |
objVertexIndexBuffer[i] = gl.createBuffer(); |
| 127 |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, objVertexIndexBuffer[i]); |
| 128 |
var objVertexIndices = [ |
| 132 |
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(objVertexIndices), gl.STATIC_DRAW); |
| 133 |
objVertexIndexBuffer[i].itemSize = 1; |
| 134 |
objVertexIndexBuffer[i].numItems = 6; |
| 138 |
function handleLoadedTexture(texture) { |
| 139 |
gl.bindTexture(gl.TEXTURE_2D, texture); |
| 140 |
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); |
| 141 |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image); |
| 142 |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); |
| 143 |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); |
| 144 |
gl.bindTexture(gl.TEXTURE_2D, null); |
| 147 |
var crateTextures = Array(); |
| 148 |
var usedTextures = Array(); |
| 149 |
function initTexture(image) { |
| 150 |
var texture = gl.createTexture(); // allocate texture |
| 151 |
texture.image = new Image(); |
| 153 |
texture.image.onload = function () { |
| 154 |
handleLoadedTexture(texture); |
| 156 |
texture.image.src = image; |
| 160 |
function initTextures() { |
| 161 |
for (var i=0; i < pics_num; i++) { |
| 162 |
crateTextures[i]=initTexture(pics_names[i]); |
| 164 |
usedTextures = crateTextures.slice(0, 2); |
| 167 |
var mvMatrix = mat4.create(); |
| 168 |
var mvMatrixStack = []; |
| 169 |
var pMatrix = mat4.create(); |
| 171 |
function setMatrixUniforms() { |
| 172 |
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix); |
| 173 |
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix); |
| 176 |
function degToRad(degrees) { |
| 177 |
return degrees * Math.PI / 180; |
| 186 |
var RotationMatrix = mat4.create(); |
| 187 |
mat4.identity(RotationMatrix); |
| 189 |
// Draw scene and initialization |
| 191 |
var MoveMatrix = mat4.create(); |
| 192 |
mat4.identity(MoveMatrix); |
| 198 |
function drawScene() { |
| 199 |
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); |
| 200 |
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 202 |
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix); |
| 203 |
mat4.identity(mvMatrix); |
| 204 |
mat4.translate(mvMatrix, [0.0, 0.0, z]); |
| 205 |
mat4.rotate(mvMatrix, degToRad(yRot), [0, 1, 0]); |
| 206 |
mat4.multiply(mvMatrix, MoveMatrix); |
| 207 |
mat4.multiply(mvMatrix, RotationMatrix); |
| 209 |
iStep = (parseInt((yRot+45) / 90)) % pics_num; |
| 211 |
if (iCurStep != iStep) { |
| 214 |
var bChange = (iCurStep) % 2; |
| 215 |
var bChange2 = (iCurStep+1) % 2; |
| 217 |
if (iCurStep+2 > pics_num) { |
| 219 |
usedTextures[0] = crateTextures[0]; |
| 224 |
usedTextures[0] = crateTextures[iCurStep+1]; |
| 227 |
usedTextures[1] = crateTextures[iCurStep+1]; |
| 231 |
for (var i=0;i<4;i=i+1) { |
| 232 |
gl.bindBuffer(gl.ARRAY_BUFFER, objVertexPositionBuffer[i]); |
| 233 |
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, objVertexPositionBuffer[i].itemSize, gl.FLOAT, false, 0, 0); |
| 235 |
gl.bindBuffer(gl.ARRAY_BUFFER, objVertexTextureCoordBuffer[i]); |
| 236 |
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, objVertexTextureCoordBuffer[i].itemSize, gl.FLOAT, false, 0, 0); |
| 238 |
gl.activeTexture(gl.TEXTURE0); |
| 239 |
gl.bindTexture(gl.TEXTURE_2D, usedTextures[i % 2]); |
| 240 |
gl.uniform1i(shaderProgram.samplerUniform, 0); |
| 242 |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, objVertexIndexBuffer[i]); |
| 244 |
gl.drawElements(gl.TRIANGLES, objVertexIndexBuffer[i].numItems, gl.UNSIGNED_SHORT, 0); |
| 251 |
var timeNow = new Date().getTime(); |
| 252 |
if (lastTime != 0 && bPause == false) { |
| 253 |
var elapsed = timeNow – lastTime; |
| 254 |
yRot += (ySpeed * elapsed) / 1000.0; |
| 256 |
if (bPause == true) { |
| 257 |
var elapsed = timeNow – lastTime; |
| 259 |
if (iElapsed > iPause) { |
| 267 |
function drawFrame() { |
| 268 |
requestAnimFrame(drawFrame); |
| 273 |
function initWebGl() { |
| 274 |
var canvas = document.getElementById(’panel’); |
| 280 |
gl.clearColor(0.0, 0.0, 0.0, 1.0); |
| 281 |
gl.enable(gl.DEPTH_TEST); |
Hope that you already read similar tutorial – Creating a Photo Array in WebGL. In this case it will more easy to understand today`s code. I have made several changes in this code: I have removed all mouse/keyboard handlers, and have done most of changes in drawScene function.