with the flow

WEBプログラマを目指すWEBデザイナーが書き綴る開発日誌のようなもの

Canvasで雪っぽい表現を作る

Canvasの勉強をしたかったので、以下のコードを参考に、
雪が降ってるっぽい表現を作ってみました。
http://thecodeplayer.com/walkthrough/html5-canvas-experiment-a-cool-flame-fire-effect-using-particles

要するに、canvas
1:画面をすべて黒く塗り潰す
2:その上に、前回から位置等をずらした指定個数分の丸を描く

っていうのを猛烈な勢いでやってるだけです。

また、ctx.createRadialGradientを使って、
中心から「ランダムな透明度の白→透明」の円を描くことで、ぼかしと同じ効果を表現できています。

var gradient = ctx.createRadialGradient(p.location.x, p.location.y, 0, p.location.x, p.location.y, p.radius);
gradient.addColorStop(0, "rgba("+p.r+", "+p.g+", "+p.b+", "+p.opacity+")");
gradient.addColorStop(1, "rgba("+p.r+", "+p.g+", "+p.b+", 0)");
ctx.fillStyle = gradient;


ポイントはこの辺り。

function draw() {
  ctx.globalCompositeOperation = "source-over";//1
  ctx.fillStyle = "rgb(20,20,40)";
  ctx.fillRect(0, 0, W, H);//2
  ctx.globalCompositeOperation = "lighter";//3
  for(var i = 0; i < particles.length; i++){
  (… 雪を個数分描画する処理 …)//4,5
  }
}
setInterval(draw, 40);

上記を踏まえて、draw()処理の流れを詳細にすると

1:画面をsource-over(塗りつぶし)モードにする
2:すべて黒く塗り潰す
3:画面をlighter(Photoshop風に言うとオーバーレイ?)モードに切り替え
4:指定個数分の丸を描く
5:次の描画位置をセット

です。
globalCompositeOperation は「合成方法」です。
illustratorの「パスファインダ」にPhotoShopの「描画モード」の考え方を少し足したみたいなもんでしょうか。
別々にcanvas上へ描画した要素やイメージ同士が重なった時にどう表現するかを設定できます。
http://www.htmq.com/canvas/globalCompositeOperation.shtml


要するに、「画面をすべて黒く塗り潰す」時には、画面をsource-over(塗りつぶし)モードにし、雪同士が重なった時には、少し白っぽく見せたいので"lighter"の指定を使っているということですね。
今回は白でやったので"lighter"はわかりにくいかもしれませんが、赤とか、冒頭のサンプルにあるように7色入り乱れてやる場合は"lighter"の指定が生きてきます。

毎回塗りつぶすんじゃなくて
ctx.clearRect(0,0,W,H)って本当に消しても良さそうな気もしますが。
冒頭の参考コードは塗りつぶすやり方でした。
描いたのを消すのと黒く塗り潰すのとどちらが効率がいいんだろうか。。
と疑問に思ったので一応作ってみた。

単色で塗りつぶさないので、背景に雪国の写真とか、
今回みたくグラデーションとか、任意のものがcanvasに頼らずに使えるのがいいところですね。
こっちのほうが良いかもしれない。