FLARToolKit

FLARManger version 1.0

Section 12 SimpleCube

FLARManagerのサイトにあるチュートリアルInside FLARManager: Basic Augmented Realityを参考に作成しています。 どうやって新しいプロジェクトを作り、コンテンツを作成すればよいのかに特化しています。 まず、FLARManagerでコンテンツを作る場合にどのようにすればよいか、何をしているのかの一助になればと思います。

前準備

前回の環境から更にサンプルコードや不要なものを削除します。
その状態からFLARManagerTutorial_3D.asと同じものを作成します。

まず、examplesappsパッケージを削除します。 更に、APIリファレンスが含まれている、html_docsも削除します。 最後にLauncherファイル、FLARManager_AppLauncher.asFLARManagerExampleLauncher.asも削除すれば前準備が完了します。
結果的に下図の様になればかまいません。

Flash - Flash Builder

この状態からはじめます。

各種サンプルについて

真面目に読むとFLARManagerをさらに理解できると思います。
examplesに含まれるものやappsに含まれるものをそのまま商用利用するのは問題があるので避けるとして、作成するコンテンツの実装の参考にしてみると良いかもしれません。

設定ファイルの準備

FLARManagerは、Managerとあるだけに管理系の処理が詰まったライブラリになります。 そのため、マーカーのパターン情報や挙動を管理するための設定を行うための外部ファイルがあります。 この設定ファイルと、FLARToolKitで必要となるパラメータファイルなどについて簡単に説明します。

FLARManagerで必要になる外部ファイルは、resourcesフォルダ内の flarflarToolkitにあります。 この中で使用するのは、flarConfig.xmlと、FLARCameraParams.datpatternsフォルダ内のマーカーのパターンファイルになります。

flarConfig.xml
メインとなる設定ファイル。XML形式で挙動、マーカーパターン情報などを管理しています。詳細は次章にて説明します。
FLARCameraParams.dat
FLARToolKitで言うところの、カメラパラーメーターファイルになります。
patternsフォルダ
FLARManagerで標準的に使われているマーカーのパターンファイルが含まれています。

今回は標準的に使われているものをそのまま使います。

Main.asの新規作成

[ファイル]->[新規作成]->[ActionScript クラス]で、srcにMain.asファイルを作成します。

新規 ActionScript クラス

作成したらMain.asを[デフォルトのアプリケーションに設定]します。

Flash - Flash Builder

ここまでできたら、コードを書いていきます。

ヘッダ

テンプレートとして幾つか書かれているのでそれを修正しつつ、加筆します。

まずはヘッダーコメントから見ていきます。 アプリケーション名とライセンス表記(簡易版)を追記します。さらに最初から書かれているものにコメントを追加します。 書き方のフォーマットはASDocに対応していますが、まれにJavaDoc形式のものも混ざっていますが気にしないでください。

Main.as
/**
 * FLARManager Example
 * 
 *  license
 *   This source file is subject to The GPL License or The MIT License.
 *   It is also available through the world-wide-web at this URL:
 *    http://sixwish.jp/Licenses/artk/
 * 
 * @copyright (C) 2010 The Sixwish project
 * @license http://sixwish.jp/licenses/artk The GPL License or The MIT License
 */
package jp.sixwish
{

importライブラリ

必要なライブラリをインポートします。

    /**
     * @see flash.display.Sprite
     * @see flash.events.Event
     * @see flash.geom.Rectangle
     */
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Rectangle;

    /**
     * FLARManager library
     * @see com.transmote.flar.FLARManager
     * @see com.transmote.flar.camera.FLARCamera_PV3D
     * @see com.transmote.flar.marker.FLARMarker
     * @see com.transmote.flar.marker.FLARMarkerEvent
     * @see com.transmote.flar.tracker.FLARToolkitManager
     * @see com.transmote.flar.utils.geom.PVGeomUtils
     */
    import com.transmote.flar.FLARManager;
    import com.transmote.flar.camera.FLARCamera_PV3D;
    import com.transmote.flar.marker.FLARMarker;
    import com.transmote.flar.marker.FLARMarkerEvent;
    import com.transmote.flar.tracker.FLARToolkitManager;
    import com.transmote.flar.utils.geom.PVGeomUtils;

    /**
     * FLARToolKit Support library
     * @see org.libspark.flartoolkit.support.pv3d.FLARCamera3D
     */
    import org.libspark.flartoolkit.support.pv3d.FLARCamera3D;

    /**
     * PaperVision 3D library
     * @see org.papervision3d.cameras.Camera3D
     * @see org.papervision3d.lights.PointLight3D
     * @see org.papervision3d.materials.shadematerials.FlatShadeMaterial
     * @see org.papervision3d.materials.utils.MaterialsList
     * @see    org.papervision3d.objects.DisplayObject3D
     * @see org.papervision3d.objects.primitives.Cube
     * @see org.papervision3d.render.LazyRenderEngine
     * @see org.papervision3d.scenes.Scene3D
     * @see org.papervision3d.view.Viewport3D
     */
    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.render.LazyRenderEngine;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.view.Viewport3D;

クラス変数などの定義

使用する変数の定義。変数の内容はコメントを参照。

/**
 * FLARManager Example main class
 *  
 *  see the accompanying tutorial writeup here:
 *  http://words.transmote.com/wp/flarmanager/inside-flarmanager/basic-augmented-reality/
 * 
 * @author Eric Socolofsky
 * @author F.Rokubou
 */
[SWF(width="640", height="480", frameRate="30", backgroundColor="#EEEEEE")]
public class Main extends Sprite 
{
    /**
     * FLARManagerの本体とMarker情報を管理するクラス
     */
    private var flarManager:FLARManager;
    private var activeMarker:FLARMarker;

    /**
     * PaperVision3D関連
     */
    private var scene3D:Scene3D;
    private var camera3D:Camera3D;
    private var viewport3D:Viewport3D;
    private var pointLight3D:PointLight3D;

    /**
     * LazyRenderEngine を用いていますが、他にもレンダラーがあります。PV3Dのリファレンスを調べてみてください。
     */
    private var renderEngine:LazyRenderEngine;

    /**
     * 表示する3Dモデルデータを管理するコンテナ
     */
    private var modelContainer:DisplayObject3D;

Main関数

コメントにも説明じみたことを書いているので、そちらから。

public function Main():void 
{
    // FLARManagerの設定ファイル、使用するトラッキングエンジンなどを引数に、インスタンスを生成
    this.flarManager = new FLARManager("../resources/flar/flarConfig.xml", new FLARToolkitManager(), this.stage);

    // Webカメラからの映像入力(FLARManager.flarSource)を追加します
    this.addChild(Sprite(this.flarManager.flarSource));

    // FLARMarkerEvents のイベントリスナーを登録
    // 追加しているのは、マーカーを認識した場合、認識後の移動、認識から外れた場合となっています
    this.flarManager.addEventListener(FLARMarkerEvent.MARKER_ADDED, this.onMarkerAdded);
    this.flarManager.addEventListener(FLARMarkerEvent.MARKER_UPDATED, this.onMarkerUpdated);
    this.flarManager.addEventListener(FLARMarkerEvent.MARKER_REMOVED, this.onMarkerRemoved);

    // FLARManagerのイベントの登録を待ってから、Papervision3Dの初期化イベントリスナーを登録する
    this.flarManager.addEventListener(Event.INIT, this.onFlarManagerInited);
}

一行ずつ見ていきます。

// FLARManagerの設定ファイル、使用するトラッキングエンジンなどを引数に、インスタンスを生成
this.flarManager = new FLARManager("../resources/flar/flarConfig.xml", new FLARToolkitManager(), this.stage);

上記処理で、config.xmlに書かれた内容と、FLARToolKitのトラッキングエンジンに従ってFLARToolKitを初期化していきます。

次に、Webカメラからの映像入力を取得しなければならないので、それに対応する処理を書いています。

// Webカメラからの映像入力(FLARManager.flarSource)を追加します
this.addChild(Sprite(this.flarManager.flarSource));

FLARManagerは、デフォルトのWebカメラからの映像入力を作成する事ができます。 このWebカメラからの映像入力については、config.xmlで設定する事ができます。

続いての処理は、イベントリスナーの登録です。 マーカーを認識した場合にどういう処理を行うか、時系列的に更新された時(継続的に認識した場合)、 マーカーが認識できなかった場合の処理を、それぞれどのメソッドで行うかを規定しています。

// FLARMarkerEvents のイベントリスナーを登録
// 追加しているのは、マーカーを認識した場合、認識後の移動、認識から外れた場合となっています
this.flarManager.addEventListener(FLARMarkerEvent.MARKER_ADDED, this.onMarkerAdded);
this.flarManager.addEventListener(FLARMarkerEvent.MARKER_UPDATED, this.onMarkerUpdated);
this.flarManager.addEventListener(FLARMarkerEvent.MARKER_REMOVED, this.onMarkerRemoved);

最後にPapervison 3Dの環境設定を初期化するイベントハンドラを追加します。

// FLARManagerのイベントの登録を待ってから、Papervision3Dの初期化イベントリスナーを登録する
this.flarManager.addEventListener(Event.INIT, this.onFlarManagerInited);

ここまでが主要な処理です。 ここからは一つ一つのイベントリスナー(ハンドラ)の内容を追記していきます。

Papervision3Dを設定する

PV3Dの説明ではないのでソースコード中のコメントを参考にしてください。

/**
 * Papervision3Dを設定する
 * @param evt Event.INIT
 */
private function onFlarManagerInited (evt:Event) :void
{
    // 一回しか行わないので早速リスナーから削除
    this.flarManager.removeEventListener(Event.INIT, this.onFlarManagerInited);

    // org.papervision3d.scenes.Scene3D の初期化
    this.scene3D = new Scene3D();
    this.viewport3D = new Viewport3D(this.stage.stageWidth, this.stage.stageHeight);
    this.addChild(this.viewport3D);

    // 解析済みのカメラパラメータを使って FLARCamera3D を初期化します。
    // このクラスは、FLARToolKitで使われているものとは別物なので注意してください。
    this.camera3D = new FLARCamera_PV3D(this.flarManager, new Rectangle(0, 0, this.stage.stageWidth, this.stage.stageHeight));

    this.renderEngine = new LazyRenderEngine(this.scene3D, this.camera3D, this.viewport3D);

    this.pointLight3D = new PointLight3D();
    this.pointLight3D.x = 1000;
    this.pointLight3D.y = 1000;
    this.pointLight3D.z = -1000;

    // 検出されたマーカーの上に表示するために立方体を作成
    var cubeMaterial:FlatShadeMaterial = new FlatShadeMaterial(this.pointLight3D, 0xFF1919, 0x730000);
    var materialsList:MaterialsList = new MaterialsList({all: cubeMaterial});
    var cube:Cube = new Cube(materialsList, 40, 40, 40);
    // キューブの初期位置からz軸方向に20px足している。コメントアウトすれば中心位置
    cube.z += 20;

    // 立方体のためにコンテナを作成します。
    this.modelContainer = new DisplayObject3D();
    this.modelContainer.addChild(cube);
    this.scene3D.addChild(this.modelContainer);

    // フレーム毎のイベントリスナーを追加
    this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
}

FLARMarkerEventsのハンドラ

ここからのイベントハンドらは、マーカーが認識したとき、更新されたとき、認識できなくなったときに、それぞれ、イベントがキャッチされて、FLARMarkerEventで通知されます。
FLARMarkerEventに含まれる情報、FLARMarkerは多くの情報を含んでいます。 たとえば、2次元、3次元の位置やベクター情報、回転角、パターンIDなどです。

このサンプルでは、onMarkerAddedで、3Dキューブを可視化、onMarkerUpdatedも同じように可視化、onMarkerRemovedで不可視に変更しています。

/**
 * マーカー認識時のイベントハンドラ
 * @param    evt FLARMarkerEvent
 */
private function onMarkerAdded (evt:FLARMarkerEvent) :void {
    trace("["+evt.marker.patternId+"] added");
    this.modelContainer.visible = true;
    this.activeMarker = evt.marker;
}

/**
 * マーカー更新時のイベントハンドラ
 * @param    evt FLARMarkerEvent
 */
private function onMarkerUpdated (evt:FLARMarkerEvent) :void {
    //trace("["+evt.marker.patternId+"] updated");
    this.modelContainer.visible = true;
    this.activeMarker = evt.marker;
}

/**
 * マーカー非認識時のイベントハンドラ
 * @param    evt FLARMarkerEvent
 */
private function onMarkerRemoved (evt:FLARMarkerEvent) :void {
    trace("["+evt.marker.patternId+"] removed");
    this.modelContainer.visible = false;
    this.activeMarker = null;
}

コンテナを作って、可視化と非可視化……表示・非表示を繰り返しているのには、認識が甘く、ちょくちょくonMarkerRemovedが呼ばれてしまうからです。 トラッキングモードが実装されれば、Addedでコンテナ追加、Removedでコンテナ削除という事もやりやすくなるかもしれませんが……

3Dキューブの更新

PaperVsion3Dはあらゆるフレームで再描画する必要があります。
そのため、onFlarManagerInited内で、onEnterFrameのイベントリスナーを追加しています。 ここではそれの実装を行います。

/**
 * フレームごとの再描画イベントハンドラ
 * @param    evt
 */
private function onEnterFrame (evt:Event) :void {
    // FLARToolkitの変換行列をCubeに適用
    if (this.activeMarker) {
        this.modelContainer.transform = PVGeomUtils.convertMatrixToPVMatrix(this.activeMarker.transformMatrix, this.flarManager.flarSource.mirrored);
    }

    // Papervision3Dの描画更新
    this.renderEngine.render();
}

activeMarker(FLARMarker)は、ここまでのFLARMarkerEventsハンドラで、更新された情報です。 それを用いて、描画しています。

ソースコード

細切れは評判が悪く、ダウンロードする好意は個人的に好まないので、ここまで追加した内容を含めたコードを一括表示します。

/**
 * FLARManager Example
 * 
 *  license
 *   This source file is subject to The GPL License or The MIT License.
 *   It is also available through the world-wide-web at this URL:
 *    http://sixwish.jp/Licenses/artk/
 * 
 * @copyright (C) 2010 The Sixwish project
 * @license http://sixwish.jp/licenses/artk The GPL License or The MIT License
 */
package jp.sixwish
{
    /**
     * @see flash.display.Sprite
     * @see flash.events.Event
     * @see flash.geom.Rectangle
     */
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Rectangle;

    /**
     * FLARManager library
     * @see com.transmote.flar.FLARManager
     * @see com.transmote.flar.camera.FLARCamera_PV3D
     * @see com.transmote.flar.marker.FLARMarker
     * @see com.transmote.flar.marker.FLARMarkerEvent
     * @see com.transmote.flar.tracker.FLARToolkitManager
     * @see com.transmote.flar.utils.geom.PVGeomUtils
     */
    import com.transmote.flar.FLARManager;
    import com.transmote.flar.camera.FLARCamera_PV3D;
    import com.transmote.flar.marker.FLARMarker;
    import com.transmote.flar.marker.FLARMarkerEvent;
    import com.transmote.flar.tracker.FLARToolkitManager;
    import com.transmote.flar.utils.geom.PVGeomUtils;

    /**
     * FLARToolKit Support library
     * @see org.libspark.flartoolkit.support.pv3d.FLARCamera3D
     */
    import org.libspark.flartoolkit.support.pv3d.FLARCamera3D;

    /**
     * PaperVision 3D library
     * @see org.papervision3d.cameras.Camera3D
     * @see org.papervision3d.lights.PointLight3D
     * @see org.papervision3d.materials.shadematerials.FlatShadeMaterial
     * @see org.papervision3d.materials.utils.MaterialsList
     * @see    org.papervision3d.objects.DisplayObject3D
     * @see org.papervision3d.objects.primitives.Cube
     * @see org.papervision3d.render.LazyRenderEngine
     * @see org.papervision3d.scenes.Scene3D
     * @see org.papervision3d.view.Viewport3D
     */
    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.render.LazyRenderEngine;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.view.Viewport3D;

    /**
     * FLARManager Example main class
     *  
     *  see the accompanying tutorial writeup here:
     *  http://words.transmote.com/wp/flarmanager/inside-flarmanager/basic-augmented-reality/
     * 
     * @author Eric Socolofsky
     * @author F.Rokubou
     */
    [SWF(width="640", height="480", frameRate="30", backgroundColor="#EEEEEE")]
    public class Main extends Sprite
    {
        /**
         * FLARManagerの本体とMarker情報を管理するクラス
         */
        private var flarManager:FLARManager;
        private var activeMarker:FLARMarker;

        /**
         * PaperVision3D関連
         */
        private var scene3D:Scene3D;
        private var camera3D:Camera3D;
        private var viewport3D:Viewport3D;
        private var pointLight3D:PointLight3D;

        /**
         * LazyRenderEngine を用いていますが、他にもレンダラーがあります。PV3Dのリファレンスを調べてみてください。
         */
        private var renderEngine:LazyRenderEngine;

        /**
         * 表示する3Dモデルデータを管理するコンテナ
         */
        private var modelContainer:DisplayObject3D;

        public function Main()
        {
            // FLARManagerの設定ファイル、使用するトラッキングエンジンなどを引数に、インスタンスを生成
            this.flarManager = new FLARManager("../resources/flar/flarConfig.xml", new FLARToolkitManager(), this.stage);

            // Webカメラからの映像入力(FLARManager.flarSource)を追加します
            this.addChild(Sprite(this.flarManager.flarSource));

            // FLARMarkerEvents のイベントリスナーを登録
            // 追加しているのは、マーカーを認識した場合、認識後の移動、認識から外れた場合となっています
            this.flarManager.addEventListener(FLARMarkerEvent.MARKER_ADDED, this.onMarkerAdded);
            this.flarManager.addEventListener(FLARMarkerEvent.MARKER_UPDATED, this.onMarkerUpdated);
            this.flarManager.addEventListener(FLARMarkerEvent.MARKER_REMOVED, this.onMarkerRemoved);

            // FLARManagerのイベントの登録を待ってから、Papervision3Dの初期化イベントリスナーを登録する
            this.flarManager.addEventListener(Event.INIT, this.onFlarManagerInited);
        }

        /**
         * Papervision3Dを設定する
         * @param evt Event.INIT
         */
        private function onFlarManagerInited (evt:Event) :void
        {
            // 一回しか行わないので早速リスナーから削除
            this.flarManager.removeEventListener(Event.INIT, this.onFlarManagerInited);

            // org.papervision3d.scenes.Scene3D の初期化
            this.scene3D = new Scene3D();
            this.viewport3D = new Viewport3D(this.stage.stageWidth, this.stage.stageHeight);
            this.addChild(this.viewport3D);

            // 解析済みのカメラパラメータを使って FLARCamera3D を初期化します。
            // このクラスは、FLARToolKitで使われているものとは別物なので注意してください。
            this.camera3D = new FLARCamera_PV3D(this.flarManager, new Rectangle(0, 0, this.stage.stageWidth, this.stage.stageHeight));

            this.renderEngine = new LazyRenderEngine(this.scene3D, this.camera3D, this.viewport3D);

            this.pointLight3D = new PointLight3D();
            this.pointLight3D.x = 1000;
            this.pointLight3D.y = 1000;
            this.pointLight3D.z = -1000;

            // 検出されたマーカーの上に表示するために立方体を作成
            var cubeMaterial:FlatShadeMaterial = new FlatShadeMaterial(this.pointLight3D, 0xFF1919, 0x730000);
            var materialsList:MaterialsList = new MaterialsList({all: cubeMaterial});
            var cube:Cube = new Cube(materialsList, 40, 40, 40);
            // キューブの初期位置からz軸方向に20px足している。コメントアウトすれば中心位置
            cube.z += 20;

            // 立方体のためにコンテナを作成します。
            this.modelContainer = new DisplayObject3D();
            this.modelContainer.addChild(cube);
            this.scene3D.addChild(this.modelContainer);

            // フレーム毎のイベントリスナーを追加
            this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
        }

        /**
         * マーカー認識時のイベントハンドラ
         * @param    evt FLARMarkerEvent
         */
        private function onMarkerAdded (evt:FLARMarkerEvent) :void {
            trace("["+evt.marker.patternId+"] added");
            this.modelContainer.visible = true;
            this.activeMarker = evt.marker;
        }

        /**
         * マーカー更新時のイベントハンドラ
         * @param    evt FLARMarkerEvent
         */
        private function onMarkerUpdated (evt:FLARMarkerEvent) :void {
            //trace("["+evt.marker.patternId+"] updated");
            this.modelContainer.visible = true;
            this.activeMarker = evt.marker;
        }

        /**
         * マーカー非認識時のイベントハンドラ
         * @param    evt FLARMarkerEvent
         */
        private function onMarkerRemoved (evt:FLARMarkerEvent) :void {
            trace("["+evt.marker.patternId+"] removed");
            this.modelContainer.visible = false;
            this.activeMarker = null;
        }

        /**
         * フレームごとの再描画イベントハンドラ
         * @param    evt
         */
        private function onEnterFrame (evt:Event) :void {
            // FLARToolkitの変換行列をCubeに適用
            if (this.activeMarker) {
                this.modelContainer.transform = PVGeomUtils.convertMatrixToPVMatrix(this.activeMarker.transformMatrix, this.flarManager.flarSource.mirrored);
            }

            // Papervision3Dの描画更新
            this.renderEngine.render();
        }

    }
}

さて、あとは実行です。FLARToolKitのサンプルを実行したときのようにしてください。