前回のエントリを全部読んだ猛者であれば、現時点でFlasDevelopを使い、FLARToolKit開発が出来るようになっているはずだ。今回は、サンプルを変更してピンクの立方体以外の物を出力出来るようになる方法を書いていく。一応今回辺りからPapervision3Dや3次元モデルの知識が要るかもしれないし、要らないかも知れない。何にしろ、新しい事に立ち向かう覚悟は要る。
さて、「俺はActionScript3.0もFlashDevelopもPapervision3Dも完璧だ!早くFLARToolKitを使わせろ!」と言う方に要点を2点だけ解説。これが分かった方は、すぐにブラウザを閉じてコード変更に臨むんだ!
this._transGrp
にaddChild
したDisplayObject3D
インスタンスが、マーカー上に出る!- マーカーはXY平面で、高さはZで表される!そしてマーカーのど真ん中が原点!
新しい3Dのための準備
FLARToolKitが提供しているサンプル「FLARToolKitTest2.as」は、はっきり言って非常によく出来ている。ほぼ完成されていると言っても過言ではない。俺が作っているFLARToolKit系のコンテンツだって、このサンプルを10?20行程度書き換えたクラス+皮という構成で出来ている。このサンプルが便利すぎて、逆に拡張現実の深い所を理解するという重要事項が疎かになっているのが俺だ!
と、言う事でまずはサンプルを、FlashDevelopのプロジェクト「flar_sample」(前回作成)のフォルダ「src」以下にコピーしよう。以後、このコピーした奴を編集していくので、FlashDevelopの右クリックメニューから「Always Compile」をこのコピーした方に設定しておくのも忘れずに。
サンプルのソースを見る
サンプルを実行すると、赤い正方形の枠とその上に乗っかったピンクの立方体が表示される。これはサンプルのソース内に「赤い正方形の枠とピンクの立方体を表示しなさい」と言う命令がある」からに他ならない。つまり、この部分の命令を書き換えれば、例えば「緑の球体を表示しなさい」とすれば、その通りに緑の球体を表示できると言うわけだ。
その命令が以下の部分だ。
- this._transGrp = this._scene.addChild(new DisplayObject3D()) as DisplayObject3D;
- var wmat:WireframeMaterial = new WireframeMaterial(0xff0000, 1, 2);
- wmat.doubleSided = true;
- this._basePlane = new Plane(wmat, 80, 80);
- this._transGrp.addChild(this._basePlane);
- var light:PointLight3D = new PointLight3D();
- light.x = 1000;
- light.y = 1000;
- light.z = -1000;
- var fmat:FlatShadeMaterial = new FlatShadeMaterial(light, 0xff22aa, 0x0);
- this._cube = new Cube(new MaterialsList({ all: fmat }), 40, 40, 40);
- this._cube.z += 20;
- this._transGrp.addChild(this._cube);
これは、関数_onInit
中盤にあるコードで、次のような意味を持つ。
- 「表示すべき3次元世界全体に、表示したいモデル全体を含む(予定の)「纏め役」を登録 (1行目)
- 赤い正方形の枠を作成し、纏め役に登録 (2?5行目)
- ピンクの立方体を作成し、纏め役に登録 (6行目?)
ちなみに、この部分のコードは全てPapervision3Dの話で、FLARToolKitは関係なくなっている。FLARToolKit関連コードは他の部分にあるのだが、さっきも書いたようにサンプルが凄すぎて全く意識する必要が無いのだ。恐るべしサンプル!
と言う事で、以下はPapervision3Dの解説を書く。
纏め役の登録
Papervision3Dでは、3次元世界の事を「シーン」と読んでいる(コード中にも「this._scene
」とある)。で、シーンは木構造になっていて、親に対する変換(移動とか、回転とか、拡大縮小とか)は、全て子にも影響を及ぼす。FLARToolKitでは、マーカーの位置に応じて3次元モデルを移動・回転・拡大縮小してやることによって、マーカーの真上にモデルが出てくるわけだが、纏め役を作り、その子として表示したいモデルを登録する事で、変換のための計算対象を1個に絞っているのだ。
ちなみに、その変換部分は、関数_onEnterFrame
内の以下のコードだ。
- this._detector.getTranslationMatrix(this._resultMat);
- var a:Array = this._resultMat.getArray();
- var mtx:Matrix3D = this._transGrp.transform;
- mtx.n11 = a[0][1]; mtx.n12 = a[0][0]; mtx.n13 = a[0][2]; mtx.n14 = a[0][3];
- mtx.n21 = -a[1][1]; mtx.n22 = -a[1][0]; mtx.n23 = -a[1][2]; mtx.n24 = -a[1][3];
- mtx.n31 = a[2][1]; mtx.n32 = a[2][0]; mtx.n33 = a[2][2]; mtx.n34 = a[2][3];
最初の2行はFLARToolKitの何か難しい処理で、今は知らなくても良い。知らない俺が言うんだから間違いない。3行目で纏め役の変換行列と言うのを取ってる。これは数学会の偉大なる先人たちが開発した、3次元世界の移動・回転・拡大縮小をまとめて表現できる優れた行列らしい。詳しい事はそっちら辺の文献を見て欲しい。取り敢えず、最後の3行でこの変換行列を、マーカーの位置から計算された値に書き換えている事と、それによって纏め役が移動・回転・拡大縮小され、その子達も全て移動・回転・拡大縮小されるということがぼんやり想像出来ればよい。
赤い正方形の枠
ここまでで難しい所・大事な所はほぼ終了で、後は見た目の話になる。まずは正方形の枠が出ている部分について説明。
- var wmat:WireframeMaterial = new WireframeMaterial(0xff0000, 1, 2);
- wmat.doubleSided = true;
- this._basePlane = new Plane(wmat, 80, 80);
- this._transGrp.addChild(this._basePlane);
このコードは赤い正方形の枠を作り、最後の行で纏め役に登録している。赤い正方形の枠を作る部分をさらに分解すると、以下のようになる。
- 最初の行で「マテリアル」を作成している。マテリアルとは3次元物体の見え方を定義する代物で、今回であれば、「赤い(
0xff0000
)、不透明な(不透明度1)、太さが2の線(WireframeMaterial
)で形を描くためのマテリアル」を作成している事になる。 - 2行目では、「マテリアルは両面ともに適用される」と言う設定をしている。3次元物体は基本的に、「ポリゴン」と呼ばれる三角形が集まって出来ている、中身の無いハリボテだ。なので閉じた物体(立方体とか)の場合は裏面は表示されなくても良いが、今回のように裏表のある正方形の場合、両面設定をしておかないと、裏から見たら何も表示されないとか、真っ白い板とか、まぁそんな感じになってしまう。
- 3行目で、マテリアル、幅、高さを指定して正方形を作っている。
ピンクの立方体
次にピンクの立方体を作って登録する部分だ。基本的には赤い正方形の枠と同じように、マテリアルを作り、立方体を作り、纏め役に登録している。
- var light:PointLight3D = new PointLight3D();
- light.x = 1000;
- light.y = 1000;
- light.z = -1000;
- var fmat:FlatShadeMaterial = new FlatShadeMaterial(light, 0xff22aa, 0x0);
- this._cube = new Cube(new MaterialsList({ all: fmat }), 40, 40, 40);
- this._cube.z += 20;
- this._transGrp.addChild(this._cube);
正方形の枠に比べてコードが長いのは立方体だからではなく、マテリアルが凝った物だからだ。
- 最初の4行は「光源」を作成している。今回は立方体なので、影があったほうが分かりやすいからだろう
- 5行目でマテリアルを作成している。
FlatShadeMaterial
は、平坦な影が出来るマテリアルだで、光に近い方が影が濃いとかの細かい表現は無いが、光が当たる面は明るく、当たらない面は暗いと言う程度の表現は行ってくれる。光源は先ほど作ったものを使う。 - 6行目で立方体を作っている。幅・高さ・奥行きはそれぞれ40となっている。
MaterialsList
は、マテリアルの辞書だ。立方体は6面あり、各面に違うマテリアルを割り当てる事も出来る。今回使っているall
は、全部の面に同じマテリアルを使う時の指定だが。 - 7行目で立方体を20上に動かしている。立方体は、出来た瞬間には中心に原点があり、下半分が地面にめり込む形になっている。なので、高さの半分である20だけ、上に動かす必要があるのだ。
- 最後に、纏め役に登録。
マーカーと地面について
さて、立方体の登録部分で少しおかしいな?と思ったかもしれない。何故、「上に動かす」がthis._cube.z += 20
か?と。
通常、3次元世界ではXZ平面が水平となり、高さはYとなると言うのが見慣れたパターンではないか?
だが、FLARToolKitでは、地面はXY平面となる。
これは結構間違いの元になりそうなので注意。厳密には地面ではなくマーカーがXY平面なのだが、普通マーカーは地面になると思うので一緒か。と言う事で、上に移動する際はZと言う事に気をつけて欲しい。これは次回に記載予定の、Metasequoiaモデルを出す方法あたりでかなりクリティカルな話題だ。
緑の球体を出す
さて、これでサンプルの、物体表示部分の意味は完全に理解できた筈なので、早速不要な部分を消して、ピンクの立方体の代わりに緑の球体を出そう。さっきのピンクの立方体を作成する部分の5行目以降を削って、以下のコードを放り込めば良い。
- //緑(0x00ff00)で影付きマテリアルを作成(立方体の時のコードを参考に)
- var fmat:FlatShadeMaterial = new FlatShadeMaterial(light, 0x00ff00, 0x0);
- var sphere:Sphere = new Sphere(fmat , 40);
- sphere.z += 40;
- this._transGrp.addChild(sphere);
ピンクの立方体_cube
はメンバになっていたが、別に後から取り出したりするわけではないのでローカル変数でも良いだろう。変更したら再生ボタンを押してビルド&実行。コピペだけしたモノグサさんのFlashDevelopが、「Sphereなんて型は知らん」みたいなエラーを出してくるだろう。そんな時は、Sphereの最後のeを削ってCtrl+スペースでコード補完を行い、自動でSphereをimportするか、package
とclass
の間のimport
が並んでる部分に、
- import org.papervision3d.objects.primitives.Sphere;
と書き足せばよい。えらいギラギラした緑色の球体が、マーカーと赤枠の上にふわりと浮かんでいる様子が出るはず。
さて次回は、Metasequoiaモデルを表示する方法について解説。