さて、前回までの3つのエントリで、FLARToolKitのサンプルを改造してMetasequoiaファイルを表示出来ていると思うが、今までのサンプルは表示するモデルをハードコーディングしていて、モデルを動的に変更すると言う機能が無かった。そこでこの連載記事の最後として、サンプルを改造して外部で作成した任意のモデルを表示する機能を付けてみたいと思う。それが出来れば、自由度がかなり高まる。
で、そのために必要な変更は以下の2つ。
- モデルを外部から設定できるインタフェースを作成する
- サンプル自体ではなく、モデルを作って渡す側がメインクラスとなれるようにする
1つ目はすぐに分かると思うが、2つ目は意味が分からないかもしれないので少し説明する。
サンプルクラスは、ビルド時にメインクラスになる事を前提として作られている。そのため、メインクラスにしか存在しない変数を使ったり、サイズ(幅と高さ)が固定値で出来ている。が、メインクラスにしない場合、メインクラスにしか存在しない変数を使えば実行時エラーになるし、サイズは可変な方が便利に決まっている。その辺りを変えて行こうと言うわけだ。
ここまでやれば、誰かが、最近Papervisio3D(GreateWhite)に実装されたと言う「DAE Animation」をモデルとして使ってくれるだろう。間違いなく。
ちなみに、DAE Animationについてはこちらを参照して下され。
rev570でGreatWhiteにDAEアニメーションが実装されました。ASColladaの作者でPV3DのコミッターでもあるTim Knip氏がMLにポストしてくれたのでテスト。
[Papervision3D 2.0] DAE Animation (1) (TORIGOE DESIGN. doc)
Metasequoia以外のモデルも表示出来るように改造
さて、ある程度ActionScript3.0を知っている人であれば既にお分かりの通り、このサンプルをちょっと改造して、this._transGrp
に設定するモデルを外部から変更可能にすれば、どんなモデルでも簡単に表示できるようになる。俺の作ったモデル変更可能なAR系コンテンツは、そうやって作っている。
この変更の手順は以下の2つ。
- 前々回のエントリで解説した、赤い正方形の枠とピンクの立方体を登録する部分を削除して初期状態では何も表示されないようにする。
- 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);
↓
- this._transGrp = this._scene.addChild(new DisplayObject3D()) as DisplayObject3D;
- 外部インタフェースとなる、以下のような関数を追加する。
- public function set model(model:DisplayObject3D):void
- {
- try {
- this._transGrp.removeChildByName("model");
- } catch (e:Error) {
- trace("remove失敗");
- }
- this._transGrp.addChild(model, "model");
- }
removeChildByName
をtry節で囲っているのは、名前に該当する子が無い時に例外を出したような気がするので、念のためだ。必要なければ削除して問題ない。
メインクラス特有機能の排除
これで外部からモデルの変更が可能になったので、次はメインクラス特有の部分を削除する。
元々のサンプルはメインのクラス、つまりFlashDevelopで、「Always Compile」にするクラスにのみ使用できる変数を使用しているので、その部分を取り除いてやらないと外部から利用できない。
その変数はコンストラクタ中で使われている。
- public function FLARToolKitTest2() {
- this.stage.scaleMode = StageScaleMode.SHOW_ALL;
- this.stage.quality = StageQuality.LOW;
- this.addEventListener(Event.INIT, this._onInit);
- this.init(CAMERA_FILE, PATTERN_FILE, 320, 240);
- }
最初の2行にある「this.stage
」が、メインのクラス以外だとnull
になるので、削除しておく必要がある。この2行はFlashコンテンツがビルド時に設定した大きさ以外になった時の処理の方法(1行目)と、Flashコンテンツの画質(2行目)を設定してある。今回であれば、コンテンツサイズが変更されたら中身も一緒に拡大縮小するようにして、画質は「低」である。FLARToolKitではメインの処理(マーカー検出とモデル表示)が重いので、画質は「低」がいいのかもしれない。
サイズ変更可能にする
FLARToolKitでは、以下に示すような処理手順で、Webカメラの映像と3Dモデルを合成している。
- Webカメラからの入力をVideoオブジェクト(
_video
)で受け取る。 - Videoオブジェクトが解析用のBitmap領域(
_capture
)に現在の映像を書き込む。 - FLARToolKitが現在の映像からマーカーを検出する。
- マーカーの状態に合わせてPapervision3Dのモデルを移動・回転・拡大縮小する。
- 解析用のBitmap領域(
_capture
)をそのままコンテンツの出力として表示する。 - Papervision3Dの表示をコンテンツの出力に上書きする。
なので、サイズ変更を可能にする場合は、その辺を注意して「Videoの出力(ここでは_capture
に出力される画像)」とPapervision3Dの表示領域(_viewport
)」の大きさを合わせてやる必要がある。
では、サンプルではこの辺りはどうなっているのか?ちょっと見てみよう。
- サンプル「FLARToolKitTest2」のコンストラクタで、幅320×高さ240を指定して
ARAppBase#init
を呼び出す。- this.init(CAMERA_FILE, PATTERN_FILE, 320, 240);
- ARAppBase#initで、メンバ
_width
に320を、_height
に240を設定する。- protected function init(cameraFile:String, codeFile:String, canvasWidth:int = 320, canvasHeight:int = 240, codeWidth:int = 80):void {
- this._cameraFile = cameraFile;
- this._width = canvasWidth;
- this._height = canvasHeight;
- 必要なパラメータファイル(Data以下にある奴)の読み込み完了後、
ARAppBase#_onLoadCode
で幅320×高さ240を指定してVideo
を作成し、入力としてWebカメラを指定する。- this._video = new Video(this._width, this._height);
- this._video.attachCamera(this._webcam);
- 解析用のBitmap領域(
_capture
)を、幅320×高さ240を指定して新規に作成する。- this._capture = new Bitmap(new BitmapData(this._width, this._height, false, 0), PixelSnapping.AUTO, true);
FLARToolKitTest2#_onInit
で、解析用のBitmap領域(_capture
)の幅と高さを2倍の640×480に指定する。- this._capture.width = 640;
- this._capture.height = 480;
FLARToolKitTest2#_onInit
で、Papervision3Dの表示領域である_viewport
を幅320×高さ240を指定して新規に作成し、縦横のスケールを2倍に拡大する事で640×480にする。- this._viewport = this._base.addChild(new Viewport3D(320, 240, false, false, false, false)) as Viewport3D;
- this._viewport.scaleX = 640 / 320;
- this._viewport.scaleY = 480 / 240;
このようになっている。基本的には、320×240の表示領域を縦横2倍に広げて640×480っぽく見せかけていると言う状態だ。
さて、これを自由に変更できるようにするにはどうすればよいか?
- まず、コンストラクタで幅と高さを受け取るようにしてみる。受け取った幅と高さは
ARAppBase#init
にそのまま渡す。- public function FLARToolKitTest2(_width:int, _height:int) {
- this.addEventListener(Event.INIT, this._onInit);
- this.init(CAMERA_FILE, PATTERN_FILE, _width, _height);
- }
FLARToolKitTest2#_onInit
で_capture
の幅と高さを再指定するのを止め、_viewport
も2倍に広げずに元の_capture
と同じ大きさで新規作成する。- this._capture.width = 640;
- this._capture.height = 480;
- this._base.addChild(this._capture);
- this._viewport = this._base.addChild(new Viewport3D(320, 240, false, false, false, false)) as Viewport3D;
- this._viewport.scaleX = 640 / 320;
- this._viewport.scaleY = 480 / 240;
↓
- this._base.addChild(this._capture);
- this._viewport = this._base.addChild(new Viewport3D(this._capture.width, this._capture.height, false, false, false, false)) as Viewport3D;
こんな風に、拡大表示とかの気遣いを排除すればよい。で、元のサンプルのように320×240を2倍にして表示したいと言うのであれば、外部のクラスで
- var ar:FLARToolKitTest2 = new FLARToolKitTest2(320, 240);
- ar.scaleX = ar.scaleY = 2;
とかすればいいだけだし。
作ったサンプルを使う
と言う事で外部から操作可能にしたサンプルクラスを使う方法。
- まずは、作り方。
- var ar:FLARToolKitTest2 = new FLARToolKitTest2(320, 240);
- ar.addEventListener(Event.INIT, function(e:Event):void {
- this.addChild(ar);
- });
これでよし。FLARToolKitTest2の
Event.INITは
、パラメータファイルとかパターンファイルとかを全部詠んで準備が出来た時に出されるので、こうしておけば妙なnull参照とかで悩まされることも無くなる。
まぁ、本当はパラメータファイルやパターンファイルを指定可能にしたりとか、色々とすべき事があるんだろうが、そこはまた別の話ってことで。 - 次に、モデルの登録方法
- var mqo:Metasequoia = new Metasequoia();
- mqo.load(・・・);
- ar.model = mqo;
おまけ:fpsの棒グラフは要らないって人は・・・
FLARToolKitTest2#_onInit
の、以下のコードを削除すればよい。
- this.addChild(new FPSMeter());
今回はちょっと散文的になってしまった。まぁ、自分的メモとしての側面も強かったかなと言う感じ。
さて、これで一旦この記事は終了。俺も修行の旅に出る。帰ってきたら、またまとめ記事書きます。