神刀安全网

Manga Panel Animated with HTML5 Canvas

Continuing thecomic theme I’ve been building over the past few weeks and inspired by the news that Ghost In The Shell is finally in the process of becoming a live-action movie, I thought it might be interesting to take a panel from the manga series and animate it using web technologies: in this case, the <canvas> element .

Whitewashing Tech

Putting aside the horrible decision Dreamworks made in whitewashing the cast of the movie, which I am trying very hard not to be drawn into…

Manga Panel Animated with HTML5 Canvas
Manga Panel Animated with HTML5 Canvas
Manga Panel Animated with HTML5 Canvas

Nope, can’t think of an Asian actress to play Major Motoko Kusanagi. Not one.

…let’s look at the markup. The <canvas> element takes the same dimensions as the image that will be used to fill its background:

<canvas id="gits" width="500" height="707"></canvas>

Rather than writing the panel into the element with JavaScript, the simplest way is to apply it as abackground image:

canvas {   box-sizing: border-box;   background-image: url(gits.png);   background-size: cover;   border: 20px solid #111;   display: block;   margin: 0 auto;   width: 30%;   max-width: 500px; }

We’ll be animating the snow effect against of this background.

Snow

Creating the snow is created via a particle system . “Particles” are tiny visual elements controlled en masse with a few rules. Snow, fire and smoke are often particle systems in computer animation. It’s important to understand that these systems don’t allow control over individual particles: we don’t “choose” a path for a snowflake. Rather, the motion of a snowflake is a random emergent property of an underlying physical system that is described with math.

Our script starts by identifying some of these properties asvariables:

var canvas = document.getElementById("gits"), ctx = canvas.getContext("2d"), W = canvas.width, H = canvas.height, maxParticles = 25, maxParticleSize = 12, minParticleSize = 4, maxMove = 1, angle = 0, particles = [];

particles is anarray into which our particle elements arepushed. Each particle has a position in x y space together with a width and height ( wh ).

for (var i = 0; i < maxParticles; i++) {     particles.push({         x: Math.random() * W,          y: Math.random() * H,          wh: Math.random() * maxParticleSize + minParticleSize     }) }

Therandomness introduced into the calculations adds the first aspect of chaotic behaviour: the initial snowflakes will be randomly positioned within the <canvas> area and provided with a random size (between the limits imposed by maxParticleSize and minParticleSize ).

Fuzzy Snow

I wanted to introduce abokeh-like effect to the snowflakes, which created a challenge: how could I blur the particles while still keeping the code efficient? A few possibilities occurred to me:

  1. I could add a blur filter to the entire <canvas> : but that would blur the background image as well, while being computationally expensive and slow on mobile.
  2. I could create a shadow with a shadowBlur for each circle, although that would effectively double the draw for each element
  3. Alternatively, I could write a gaussian blur shader for the circles: but since I didn’t need every particle to appear blurred, and the blur amount per particle did not need to change (the snow is always falling parallel to the viewer, and not moving closer or further away) that seemed overkill.

In the end, I opted for a slightly counter-intuitive approach: the particles themselves would be square, with a blurry circle drawn inside each using a radial gradient. This is contained inside a draw function:

function draw() {     ctx.clearRect(0, 0, W, H);     ctx.beginPath();         for (var i = 0; i < maxParticles; i++) {             var p = particles[i];             ctx.moveTo(p.x, p.y);             ctx.rect(p.x, p.y, p.wh, p.wh);             var radgrad = ctx.createRadialGradient(p.x + p.wh/2,p.y + p.wh/2,0,p.x + p.wh/2,p.y + p.wh/2,p.wh/2);             radgrad.addColorStop(0, 'rgba(255, 255, 255, 1)');             radgrad.addColorStop(0.5, 'rgba(255, 255, 255, .8)');             radgrad.addColorStop(1, 'rgba(255,255,255,0)');             ctx.fillStyle = radgrad;             ctx.fill();         }     update(); }

For small snowflakes, this makes little difference – they still look “solid” – but larger snowflakes that are closer to the user will appear to have a blurry edge.

The function starts with clearing the entirety of the canvas (which doesn’t affect the background image, since that’s in CSS). A slightly strange requirement is the beginPath method added immediately after, even though we are not actually drawing a path: without it, the canvas will not completely clear.

Finally, there’s a call to the update function, which moves each particle.

Snowfall

function update() {     angle += 0.01;     for (var i = 0; i < maxParticles; i++) {         var p = particles[i];         p.y += Math.cos(angle) + p.wh/4;         p.x += Math.sin(angle) * 2;         if (p.x > W + maxMove || p.x < -maxMove || p.y > H) {             if (i%3 > 0) {                 particles[i] = {x: Math.random() * W, y: -(maxMove), wh: p.wh };             } else {                 if (Math.sin(angle) > 0) {                     particles[i] = {x: -maxMove, y: Math.random()*H, wh: p.wh };                 } else {                     particles[i] = {x: W+maxMove, y: Math.random()*H, wh: p.wh };     } } } } requestAnimationFrame(draw); } draw();

While I have addressed most of theoperators used in the script, this function has more math than I’ve covered inJavaScript so far, so I’ll leave in-depth discussion for future articles. However, this won’t be the last time I cover animating comics with canvas: there will be more articles to come.

I must acknowledge the help of this anonymous contribution at codeplayer , which helped inspire this code.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Manga Panel Animated with HTML5 Canvas

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址