Behind The Scene of "WebGL でクリスマス"

Posted :

昨日公開した作例 Santa’s Boxes! の内容をざっくりまとめました。

Ground

去年のアドベントカレンダーに書いた内容をそのままで、ディフューズ マップを変更して雪原を作りました。three.js の機能でバンプ マップを適用したところ、IE 11 でレンダリングできなかったため、ディフューズ マップのみ適用しています。

単品 demo

Skybox

three.js で cube ジオメトリーを作成し、スカイボックス用のディフューズ マップを適用しているだけです。立方体の内側を表面として表示するためには materialside プロパティーに THREE.BackSide を指定します。

スカイボックス用に利用したテクスチャーは以下のような、シームレスな 6 面になっています。

単品 demo

Snowing

雪は THREE.ParticleSystem を用いて描画しています。1000 個のスノーフレークが常に舞っていますが、ParticleSystem のおかげで全体で 1 つのジオメトリーとして処理されており、一回の描画につき、ドローコールは一度しか発生しません。

単品 demo

Boxes

プレゼントボックスは、 Blender を経由して three.js 用の JSON ファイルに変換し利用しています。変換した JSON ファイルは、three.js の機能の jsonLoader で読み込みます。表示に必要な回数、読み込みを行うと、Ajax による HTTP リクエストが複数回発生してしまいます。そのため、一回のみ Ajax 読み込みを行い Mesh を生成した後、メッシュ.clone() でデュプリケイトしています。こうすることで、オブジェクト 1 つ分の HTTP 通信でいくつでもオブジェクトを増やすことができます。

単品 demo

Trees

木のオブジェクトは、プレゼントボックス同様に、Blender を経由して three.js 用の JSON ファイルに変換して利用しています。シーン内には 3 本の木が配置されています。コレを行うために、素直にシーンに木を 3 回配置 (add) してもいいのですが、これでは一回の描画につき、3回のドローコールが発生してしまいます。これを軽減するために、予め、3 本の木を、1 つのジオメトリーとしてマージしました。

複数のメッシュやジオメトリーを、ひとつのジオメトリーとしてマージするには、

THREE.GeometryUtils.merge( ジオメトリーA, ジオメトリーB );

を利用します。するとジオメトリーAジオメトリーBがマージされます。THREE.GeometryUtils.merge の引数は、mesh オブジェクトも有効です。

単品 demo

Santa

サンタさんは、MMD 用として公開されているモデルを使いました。このモデルに Blender 内でボーンとアイドル状態と走り状態のアニメーションを設定し、three.js 用の JSON ファイルとして出力しています。

scene に読み込んだ後、任意のイベントに合わせてアニメーションを再生すれば、アイドルや走りの表現を行えます。

単品 demo

Collisions

衝突判定には、Cannon.js を利用しました。物理空間の衝突用オブジェクトとして、サンタは球体、プレゼントボックスは立方体、木は円柱が割り当てられています。ですので、実は物理空間ではプリミティブな図形のみでの衝突が行われています。この結果の座標や回転状態を three.js で表示されたそれぞれのオブジェクトにコピーし、表示空間と物理空間のリンクさせています。

まとめ

実はあまり難しいことをしているわけではなく、ほとんどは Blender と three.js と Cannon.js の機能に頼って実現しています。11月が始まってから週末に少しずつ作ってきましたが、実質 1 週間位あればこれくらいのことはできてしまいます。とっても便利ですね!