700 likes | 887 Views
HTML5 Animation. Dr Raymond Bond ( rb.bond@ulster.ac.uk ). This is the lecture for week 5 Remember week 6 is your class test You need to revise everything from week 1 Class test will have 25 questions It will last approximately 40 minutes You will need a calculator
E N D
HTML5 Animation Dr Raymond Bond (rb.bond@ulster.ac.uk)
This is the lecture for week 5 • Remember week 6 is your class test • You need to revise everything from week 1 • Class test will have 25 questions • It will last approximately 40 minutes • You will need a calculator • It is a closed book test in the lab on blackboard • This video contains elements of the class test
Manipulating Raw Pixels //returns an object var imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height); //arrayof bytes var pixels = imgData.data;
Manipulating Raw Pixels Matrix of pixels to a 1*n (or 1 dimensional) array Red, Green, Blue, Alpha, Red … [byte1, byte2, byte3, byte4, byte5…] Pixel 1
Manipulating Raw Pixels varimgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height); varpixels = imgData.data; while (curRow < maxRow) { varthisRowBytes = curRow* ctx.canvas.width * 4; for (var j = 0; j < ctx.canvas.width * 4; j += 4) { pixels[thisRowBytes + j] = 255 - pixels[thisRowBytes + j]; // red pixels[thisRowBytes + j + 1] = 255 - pixels[thisRowBytes + j + 1]; // green pixels[thisRowBytes + j + 2] = 255 - pixels[thisRowBytes + j + 2]; // blue} curRow++; } ctx.putImageData(imgData, 0, 0);
Manipulating Raw Pixels for (var j = 0; j < ctx.canvas.width * 4; j += 4) { pixels[thisRowBytes + j] = pixels[thisRowBytes + j] + 50; // red pixels[thisRowBytes + j + 1] = pixels[thisRowBytes + j + 1] + 50; // green pixels[thisRowBytes + j + 2] = pixels[thisRowBytes + j + 2] + 50; // blue } // What will happen here?
The animation loop • Some call it • The Tick or Ticker • The Rendering loop • The Game Loop (in the context of games)
JS Animation loops • setTimeOut() • setInterval() • requestAnimationFrame()
setTimeout setTimeout(function, milliseconds);
setTimeout setTimeout(animate, 3000); function animate (){ //animation code here setTimeout(animate, 3000); }
setInterval setInterval(function, milliseconds);
varmyLoop = setInterval(animate, 1000); function animate(){ //insert code to render frame } //What’s the estimated FPS?
varmyLoop = setInterval(tick, 40); function tick(){ //insert code to render frame } //What’s the estimated FPS?
clearInterval(myLoop); // What would this function do?
Problems with setInterval(); • JS currently runs on a single thread • Thus the specified intervals are not guaranteed • Out of page animation • Browser Tab out of focus scenario (hogs CPU) • A setInterval has no priority over other setIntervals • …
New HTML5 requestAnimationFrame(); • A dedicated animation loop • Browser optimizes and prioritizes this loop • i.e. the browser will draw your animation at the next available opportunity!!! Not a predefined interval
PolyFill requestAnimationFrame(); PolyFill https://gist.github.com/paulirish/1579671
<script src="https://gist.github.com/paulirish/1579671/raw/3d42a3a76ed09890434a07be2212f376959e616f/rAF.js"></script> <script> window.onload= function () { requestAnimationFrame(animate); } function animate() { //perform animations here console.log("frame generated"); requestAnimationFrame(animate); } </script>
FPS with requestAnimationFrame • The FPS will be variable • But it will try to execute approx. 60 fps (refresh freq = 60Hz) • So what if you want to control FPS?
var fps = 15; requestAnimationFrame(animate); function animate() { setTimeout(draw, 1000 / fps); } function draw () { // Drawing and animation code goes here requestAnimationFrame(animate); }
Delta Time Another popular approach for animating objects at a constant speed.
Delta Time Example varprevTime = new Date().getTime(); requestAnimationFrame(draw); functiondraw() { varnow = new Date().getTime(); vardeltaTime= (now – prevTime) * 0.001; //convert to seconds // Drawing code goes here... for example updating an 'x' position: someXvalue+= 60 * deltaTime; prevTime= new Date().getTime(); requestAnimationFrame(draw); }
Delta Time Example Explanation of Delta Time: Example 1: Last frame interval is 36ms or 0.036 sec someXvalue += 60 * deltaTime; e.g. someXvalue+= 60* 0.036; //move 2.16pixels Example 2: Last frame interval is 72ms or 0.072 sec someXvalue += 60 * deltaTime; e.g. someXvalue+= 60* 0.072; //move 4.32 pixels
Delta Time Example “If the frame interval takes twice as long then the variable value will be twice as big”
Code for estimating FPS now = new Date().getTime(); dt= (now - prevtime) * 0.001; sumframeIntervals+= dt; numFrames++; if(numFrames == 60){ var avgFrameInterval = numFrames / sumframeIntervals; var FPS = Math.floor(avgFrameInterval); console.log("FPS ="+FPS); sumframeIntervals= 0; numFrames= 0; } prevtime= new Date().getTime();
Articles to read on JS Animation loops: • http://creativejs.com/resources/requestanimationframe/ • http://www.youtube.com/watch?v=XAqIpGU8ZZk#t=2884s • http://www.w3.org/TR/animation-timing/ • https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/
Basic Canvas Animation • A simple example of canvas animation that has no Buffer.
Basic Canvas Animation var rectW=40; var rectH=40; var rectX = -rectW; var rectY=200; var myLoop; var canvas = null; var context = null;
Basic Canvas Animation window.onload = function () { canvas = document.getElementById('testCanvas'); context = canvas.getContext("2d"); drawBG(); context.fillStyle= "yellow"; context.fillRect(rectX,rectY,rectW,rectH); myLoop = setInterval(anim, 30); }
Basic Canvas Animation function drawBG() { context.fillStyle= "#00eeee"; context.fillRect(0,0,context.canvas.width, context.canvas.height); }
Basic Canvas Animation function anim() { drawBG(); if (rectX < context.canvas.width) { rectX+= 5; context.fillStyle= "red"; context.strokeStyle= "yellow"; context.lineWidth= 3; context.fillRect(rectX,rectY,rectW,rectW); context.strokeRect(rectX,rectY,rectW,rectW); }else { rectX= -rectW; } }
Basic Canvas Animation • No Animation Buffer? No Middleman! • Remember Canvas is an immediate mode graphics engine. • All pixels in each frame must be redrawn Although the demo animation was smooth, canvas based animations can create a flicker or unwanted artifacts with a large number of animations.
No Buffering Number Crunching Draws directly to Canvas
Double Buffering Draws to invisible Canvas Buffer Copy pixels from the buffer and render on screen Number Crunching The next frame of animation is computed to an off screen buffer at the same time when the current frame is transferred to the frame buffer.
Double Buffering • Creating a Buffer is easy! var bufferCanvas= document.createElement("canvas"); // we create an element but we do not append it //document.appendChild(bufferCanvas); var bufferCanvasCtx= bufferCanvas.getContext("2d");
Double Buffering • A walkthrough the Particle Demo.
Blitting “Bit blit (also written BITBLT, BIT BLT, BitBLT, Bit BLT, Bit Blt etc., which stands for bit-level block transfer) is a computer graphics operation in which several bitmaps are combined into one using a raster operator.” http://en.wikipedia.org/wiki/Bit_blit
Reasons for spritesheets • http://www.codeandweb.com/what-is-a-sprite-sheet • http://www.codeandweb.com/what-is-a-sprite-sheet-performance
vartheCanvas; varctx; varcount = 0; varx; vary; varimg = new Image(); img.src= "sprite_sheet.png" img.onload= init;
function init() { theCanvas = document.getElementById('canvas'); ctx= theCanvas.getContext("2d"); varfps = 25; setInterval(draw, 1000/fps); }
function draw() { ctx.clearRect(0, 0, 212, 201); x = (count % 9) * 212; y = Math.floor(count / 9) * 201; ctx.drawImage(img, x, y, 212, 201, 0, 0, 212, 201); //ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); if(count == 149){ count = 0; } else{ count++; } }