超簡単に3DCGできるJavaScriptライブラリ作った

ブラウザでWebGLが使えるようになって3DCGプログラミングはずいぶん身近なものになりました。と書いてるそばから違和感を感じるくらい生のWebGLをJavaScriptで書くのは敷居が高かったりします。できなくはないけど前提となる知識がかなり必要な感じ。
 
three.jsが登場したときは、これで普通に3DCGができるということで一気にひろまりました。とはいえ、それでもまだやることは多く、画面に四角い箱を表示する場合以下のようなプログラムを書くことになります。
 ・シーンを作成
 ・ライトを作成、位置と向きを設定、シーンに追加
 ・カメラを作成、位置と向きを設定、シーンに追加
 ・マテリアルを作成、色を指定
 ・BoxGeometryを作成、サイズを指定
 ・メッシュを作成、位置と向きを設定、シーンに追加
 ・レンダラーを作成
 ・レンダリングループ処理
これらのひとつでも間違えたりパラメーターが適切でないと箱は表示されません。
 
そんなわけで、超簡単に3DCGが描けるthree.jsのラッパーライブラリを作成しました。
http://aikelab.net/threepiece/
https://github.com/aike/ThreePiece.js
 
■ボックスを表示

var t = new ThreePiece();
t.eval({obj:"box"});


このライブラリの基本的な方針としては、ライトもカメラもデフォルト値を持っていて、何も指定しないとデフォルト値が使われるというものです。オブジェクトを生成すると画面の見やすい位置に見やすい色、見やすい大きさで表示されます。DOMツリー上の位置も、divのIDを指定したらdivの下に生成し、省略するとbodyの直下に生成します。
 
■複数オブジェクトの表示
オブジェクトを追加したり、グリッドを描いたりはこんな感じ。

var t = new ThreePiece();
t.eval([
  {obj:"grid"},
  {obj:"box", x:-1, col:0xffff00},
  {obj:"sphere", x:1, col:0x0000ff}
]);


 
■視点の回転
3DCGは、一方向から見ただけでは、各オブジェクトの位置関係がわかりづらく、またカメラの後ろ側にオブジェクトが生成されていたりということがあったりします。そういうときのパラメーター調整に便利な、視点を回転するrotate()命令を用意しました。

var t = new ThreePiece();
t.eval([
  {obj:"ground"},
  {obj:"box", x:-2, scale:2},
  {obj:"cylinder", x:2, scale:2, col:0x0000FF},
]);
t.rotate();


 
■モデルに名前をつけて操作
モデルに名前をつけて、後から名前で検索して操作することもできます。
また、addHook()を使うことで、レンダリングループに独自の処理を追加できます。

var t = new ThreePiece();
t.eval([
  {obj:"grid"},
  {obj:"box", name:"myobj"}
]);
t.addHook(function(msec) {
  t.obj("myobj").position.x = Math.sin(msec / 1000) * 4;
});


 
■グループ化
モデルが複雑になってくると、複数のモデルをグループ化したり、オブジェクトに変化があったときのみ再描画したり(いわゆるダーティーフラグ)といった機能がほしくなります。

var t = new ThreePiece();
t.define("face", {obj:"group", z:2, data:[
  {obj:"box", col:0xEEEEEE},
  {obj:"circle", w:0.1, z:0.51, x:-0.2, y:0.2, col:0x222222},
  {obj:"circle", w:0.1, z:0.51, x: 0.2, y:0.2, col:0x222222},
  {obj:"plane", w:0.6, h:0.2, z:0.51, y:-0.2, col:0xAA2222}
]});
var data = [
  {obj:"grid"},
  {obj:"face", x:-3, y:0},
  {obj:"face", x: 0, y:0, name:"centerface"},
  {obj:"face", x: 3, y:0}
];
t.useDirtyFlag();
t.eval(data);
var pos = 1;
setInterval(function() {
  pos = 1 - pos;
  t.obj("centerface").position.y = pos;
  t.setDirty();
}, 500);


 
■応用例
がんばればこんなこともできます。

http://aikelab.net/websynthv2/
 
Enjoy!