FLARToolKit

FLARManger version 1.0

Section 14 Augmented Reality with Collada models

本家チュートリアルの初っ端には、「とあるキャラクターが可愛いんで欲しいぜ」なんて一文からスタートしているので、 なんていうか……まぁ、脱力気味ですが、チュートリアルを翻訳していきますよ。

さて、ここでは前々回のチュートリアルをベースに、Colladaモデルを表示するようにして見ましょう。
Colladaは何か?リンク先を見てください。後は調べてください。 今回は3Dデータの作成とかの説明はしませんので、予めご了承くださいませ。

前準備

詳しい説明は前々回を見てもらうとして、 今回はその辺りを全てスキップして処理を全て消したテンプレート状態からはじめます。

srcフォルダに、新しいファイルを作成します。
srcフォルダを選択して右クリック->[Add]->[New Class]

FlashDevelop

“Name:“にColladaSampleと入力して[OK]。
他にも変えるべきところがあるのですがファイルだけ作っておきます。

FlashDevelop

作成されたファイルを選択して、右クリック->[Always Compile]をクリックします。

続いて作成されたファイルの内容を削除して下記のコードを貼り付けます。

ColladaSample.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 
{
	/**
	 * @see flash.display.Sprite
	 * @see flash.events.Event
	 */
	import flash.display.Sprite;
	import flash.events.Event;

	/**
	 * FLARManager library
	 * @see com.transmote.flar.FLARManager
	 * @see	com.transmote.flar.marker.FLARMarker
	 * @see	com.transmote.flar.marker.FLARMarkerEvent
	 * @see com.transmote.flar.utils.geom.FLARPVGeomUtils
	 */
	import com.transmote.flar.FLARManager;
	import com.transmote.flar.marker.FLARMarker;
	import com.transmote.flar.marker.FLARMarkerEvent;
	import com.transmote.flar.utils.geom.FLARPVGeomUtils;

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

	/**
	 * Papervision3D library
	 * @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.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 Collada sample 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 ColladaSample extends Sprite 
	{
		/**
		 * FLARManagerの本体とMarker情報を管理するクラス
		 */
		private var flarManager:FLARManager;
		private var activeMarker:FLARMarker;

		/**
		 * FLARToolKit
		 * PV3Dのカメラ位置を管理するクラス
		 */
		private var camera3D:FLARCamera3D;

		/**
		 * Papervision3D関連
		 */
		private var scene3D:Scene3D;
		private var viewport3D:Viewport3D;
		private var renderEngine:LazyRenderEngine;
		private var pointLight3D:PointLight3D;
		private var modelContainer:DisplayObject3D;

		/**
		 * メインメソッド
		 */
		public function ColladaSample():void 
		{
			// FLARManagerの設定ファイルを引数に、インスタンスを生成
			this.flarManager = new FLARManager("./data/config.xml");

			// 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 {
		}

		/**
		 * マーカー認識時のイベントハンドラ
		 * @param	evt FLARMarkerEvent
		 */
		private function onMarkerAdded (evt:FLARMarkerEvent) :void {
		}

		/**
		 * マーカー更新時のイベントハンドラ
		 * @param	evt FLARMarkerEvent
		 */
		private function onMarkerUpdated (evt:FLARMarkerEvent) :void {
		}

		/**
		 * マーカー非認識時のイベントハンドラ
		 * @param	evt FLARMarkerEvent
		 */
		private function onMarkerRemoved (evt:FLARMarkerEvent) :void {
		}

		/**
		 * フレームごとの再描画イベントハンドラ
		 * @param	evt
		 */
		private function onEnterFrame (evt:Event) :void {
		}
	}
}

最後にlibフォルダ内のASCollada.swcを右クリック->“Add To Library”をクリックします。

結果的に下図の様になります。

FlashDevelop

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

importライブラリ

基本的なものは入っているのですが、これはPV3D用の物のみなので、 Collada用のライブラリをインポートするように修正します。

Main.as
/**
 * PaperVision 3D library
 * @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.objects.parsers.DAE // (追加)
 * @see org.papervision3d.render.LazyRenderEngine
 * @see org.papervision3d.scenes.Scene3D
 * @see org.papervision3d.view.Viewport3D
 */
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.objects.parsers.DAE; // (追加)
import org.papervision3d.render.LazyRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;

クラス変数などの定義、Main関数

ここは変更する箇所はありませんので、次に進みます。

Papervision3Dを設定する

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

Main.as
/**
 * 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();

	// 解析済みのカメラパラメータを使って FLARCamera3D を初期化します。
	this.camera3D = new FLARCamera3D(this.flarManager.cameraParams);

	this.viewport3D = new Viewport3D(this.stage.stageWidth, this.stage.stageHeight);
	this.addChild(this.viewport3D);

	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;

// 追加
	// Modelデータのロード
	// (このモデル用に回転、サイズを設定しています。この調整はモデル毎に異なるので注意してください)
	var model:DAE = new DAE(true, "model", true);
	// ファイルコピーの説明が面倒になったのでサンプルのまま。
	// swfのある位置からの相対パス設定になります。
	model.load("../resources/assets/scout.dae");
	model.rotationX = 90;
	model.rotationZ = 90;
	model.scale = 0.5;
// ここまで

	// 3Dモデルのためにコンテナを作成します。それは座標変換行列を引数にします
	this.modelContainer = new DisplayObject3D();
	this.modelContainer.addChild(model);
	this.modelContainer.visible = false;
	this.scene3D.addChild(this.modelContainer);

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

PV3Dのキューブを表示したときと異なるのは赤字にしている部分です。 手抜きしたために、データの位置があれですが、実際にやる場合にはちゃんと修正してください。

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 = FLARPVGeomUtils.convertFLARMatrixToPVMatrix(this.activeMarker.transformMatrix);
	}

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

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

ソースコード

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

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 
{
	/**
	 * @see flash.display.Sprite
	 * @see flash.events.Event
	 */
	import flash.display.Sprite;
	import flash.events.Event;

	/**
	 * FLARManager library
	 * @see com.transmote.flar.FLARManager
	 * @see	com.transmote.flar.marker.FLARMarker
	 * @see	com.transmote.flar.marker.FLARMarkerEvent
	 * @see com.transmote.flar.utils.geom.FLARPVGeomUtils
	 */
	import com.transmote.flar.FLARManager;
	import com.transmote.flar.marker.FLARMarker;
	import com.transmote.flar.marker.FLARMarkerEvent;
	import com.transmote.flar.utils.geom.FLARPVGeomUtils;

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

	/**
	 * Papervision3D library
	 * @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.parsers.DAE
	 * @see org.papervision3d.render.LazyRenderEngine
	 * @see org.papervision3d.scenes.Scene3D
	 * @see org.papervision3d.view.Viewport3D
	 */
	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.parsers.DAE;
	import org.papervision3d.render.LazyRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;

	/**
	 * FLARManager Collada sample 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 ColladaSample extends Sprite 
	{
		/**
		 * FLARManagerの本体とMarker情報を管理するクラス
		 */
		private var flarManager:FLARManager;
		private var activeMarker:FLARMarker;

		/**
		 * FLARToolKit
		 * PV3Dのカメラ位置を管理するクラス
		 */
		private var camera3D:FLARCamera3D;

		/**
		 * Papervision3D関連
		 */
		private var scene3D:Scene3D;
		private var viewport3D:Viewport3D;
		private var renderEngine:LazyRenderEngine;
		private var pointLight3D:PointLight3D;
		private var modelContainer:DisplayObject3D;

		/**
		 * メインメソッド
		 */
		public function ColladaSample():void 
		{
			// FLARManagerの設定ファイルを引数に、インスタンスを生成
			this.flarManager = new FLARManager("./data/config.xml");

			// 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();

			// 解析済みのカメラパラメータを使って FLARCamera3D を初期化します。
			this.camera3D = new FLARCamera3D(this.flarManager.cameraParams);

			this.viewport3D = new Viewport3D(this.stage.stageWidth, this.stage.stageHeight);
			this.addChild(this.viewport3D);

			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;

			// Modelデータのロード
			// (このモデル用に回転、サイズを設定しています。この調整はモデル毎に異なるので注意してください)
			var model:DAE = new DAE(true, "model", true);
			// ファイルコピーの説明が面倒になったのでサンプルのまま。
			// swfのある位置からの相対パス設定になります。
			model.load("../resources/assets/scout.dae");
			model.rotationX = 90;
			model.rotationZ = 90;
			model.scale = 0.5;

			// 3Dモデルのためにコンテナを作成します。それは座標変換行列を引数にします
			this.modelContainer = new DisplayObject3D();
			this.modelContainer.addChild(model);
			this.modelContainer.visible = false;
			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 = FLARPVGeomUtils.convertFLARMatrixToPVMatrix(this.activeMarker.transformMatrix);
			}

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

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