nyakuroのブログ

音楽ユニット"sugarmosaic"のコンポーザーの@nyakuroのブログ。作詞・作編曲 / Web Engineering / 写真・映像などについて書きます。

canvasで粉雪アニメーションを作ってみた(CreateJS / WebGL)

こんにちは。nyakuroです。
今月に入って急激に寒くなってきました。
自分はめっぽう冬に弱いので、毎朝布団から出るのが辛くてたまりません。
早く春よ来い!

音楽とプログラミング

自分は、sugarmosaicというユニットで音楽活動をしているのですが、
ここでは、音楽とデザイン、プログラミングを用いて一体感のあるコンテンツを提供することを目標としています。
この度、そちらで12月に2回のサイト更新やページ追加を行いました。

◯公式サイトをリニューアル
sugarmosaic.com

◯2ndアルバム『透明化症候群』の特設サイトを公開
sugarmosaic.com


このサイト、どちらもHTML5canvasを使ったパーティクル表現がなされているのがわかると思います。
このプログラムの実装を担当したので、今回はこれについて話してみたいと思います。

主な仕様

項目仕様備考
PC版

  • 背景画像をロード完了後、canvasを表示
  • 音楽が終了後、別のcanvasヴィジュアライザに切り替え(雪 -> 雨 -> 雪 -> 雨 …)
  • マウスポインタから粉雪を発生させたり、マウスポインタで粉雪を弾くなどのユーザーアクションを反映する機能

SP版

  • 背景画像をロード完了後、canvasを表示
  • アクセスするたびに切り替え。3分の2の確率で粉雪のヴィジュアライザ、3分の1の確率で雨のヴィジュアライザ。

  • Web GL対応ブラウザであればスマホでもスラスラ動きます!

CreateJSでの実装

CreateJSについて

createjs.com

canvasを扱えるJSフレームワーク
FLASHっぽい動きが簡単に実装できる。

4つのライブラリから成り立つ。
WebGLにも対応。モダンブラウザ、Androidブラウザ、iOS8以上のSafariで高速描画できます。


パーティクルをアニメーションさせる

キラキラと一つ一つの粒子を点滅させるために、pngのスプライト画像を用意してアニメーションを作ってます。
▼サンプル
http://sugarmosaic.com/outside/createJs/practice/particle.php

▼スプライト画像
f:id:cat_b:20151226124416p:plain

▼設定
スプライト画像を読み込んだ後、javascript側で以下のようにアニメーション設定をしています。

Snow Particles(CreateJS / canvas / javascript)

WebGL対応。Context 2Dとの比較

Context 2Dでの描画だと重すぎるので、WebGLに対応してみました。

比較用にパーティクルをたくさん出してみました。
WebGL版はiOS8でも割と表示できました。

▼Context 2D版
http://sugarmosaic.com/outside/createJs/practice/particle100.php

WebGL
http://sugarmosaic.com/outside/createJs/practice/particleWebGL100.php

canvasの切り替え

PC版でアクセスして、長いこと放置しておくと曲が終わり、次のcanvasアニメーションに切り替わります。
この機能を実装している時にとある問題が発生…

一度WebGL用に初期化してしまったcanvasでContext 2Dを動かすとエラーがでて動かない。。
Context 2Dで作ったヴィジュアライザと、WebGL対応ヴィジュアライザで使用するcanvasを完全に分けてしまうことで、仮対応しています。

雪の表現研究

まずYoutubeを見る


Diamond dust ★ ダイヤモンド・ダスト

  • キラキラときらめく表現
  • 風向きの表現
  • 近いものはカメラのピンぼけ効果で大きく見え、移動速度も早い
  • 時間による変化

などの表現ができれば、それっぽく見えそうだという事がわかりました。


パーティクルに持たせている情報

一粒一粒の雪には、固有の情報を持たせています。
パーティクルを新規作成する時にある程度の範囲内でランダムで生成されます。

  • 位置(x, y)
  • 奥行き z ≒ scale (拡大率)
  • 速度(vx, vy)

キラキラときらめく表現

先に述べたパーティクルのアニメーションで実現しています

風向きの表現

以下の図のように、画面全体を5x5に区切り、それぞれのマスに風向きベクトルを定義しました。

f:id:cat_b:20151226125020j:plain

風向きベクトルは加速度と同じ次元になるので、パーティクルの現在の速度を(vx, vy)、次のフレームの速度を(vx', vy')、風向きベクトルを(wx, wy),とすると、

vx' = vx + wx
vy' = vy + wy

みたいな処理を毎フレームでやっています。
ただ、これだと、粒子が加速し続けて現実味の無い動きになってしまうので、
vx' = vx * 0.98 + wx
のように、空気抵抗的な係数をかけてます。0.98はいろいろ試していてこの数値になりました。FPSによっても変わってくると思います。

奥行き感の表現

実際は2Dスプライトを重ねることしかしてないんですが、ちょっと工夫して擬似3Dを実現しています。
大きく表示されている(手前)のものは早く、小さく表示されているものは遅く。
を表現するために、scale(拡大率)の値を使って、速度反映率weightみたいなものを各粒子に持たせています。

weight = 係数 * scale * scale
のような式で出しています。そして、それを使って、次のフレームでの雪の位置を

x = x' + vx * weight
のように出しています。

時間変化の表現

以下のようにフレームごとに風向きの適応率の変化を定義しています。

Snow Particles TimeLine Animation Setting(CreateJS ...

次のフレームでの速度を算出する際に、風向きベクトルに対してこちらの倍率をかけることで、風の強さの時間変化を作っています。


最後に

だいぶ端折ってしまいましたが、
雪の表現はこんな感じで実現しています。
もっと実装よりの事を知りたい方はソースコードを覗いてみてくださればと思います
(グローバル汚染の酷い意識低い感じのソースですが…w)

最後に、12月31日に冬コミにて、自分がディレクション、作詞・作曲・編曲したCDの新譜が出ます!
手間暇かけて作ったので、是非是非興味を持っていただいた方は冬コミまでお越しください!

以下がジャケットです!
f:id:cat_b:20151226125903p:plain

特設サイトはこちらです!
sugarmosaic.com