SQLの窓

2012年05月21日

2009年末に作った Flex3 + FLARToolkit のソースを Flex4 に書き直しました

2009年バージョンはこちらです。zipfile ボタンで、.mqo と テクスチャの入ったファイルを読み込んで表示させる事ができます。当時作りっぱなしで放置していて、ソースを公開するのを忘れてたので再構築しました。

2009年バージョン + はちゅね



けっこういろんな人がかかわったソースが同梱されています。基本は FLARToolkit ですが、これのライセンスは GPL です。あと、メタセコイアをロードする為のソースとかもろもろ。

FLARToolkit のソースは当時の一番古いものです。今はもうちょっと新しいのがありますが( 二つ対象表示できる? )、3D 表示の元となるのが Papervision3D で、これは 2010 年に開発が止まってしまったソフトウェアで、忘れられてしまった感があります。しかし、PC もよくなったし、AIR で動かしていると結構なレスポンスなので、再び引っ張り出していろいろテストしています。ブラウザで動かす WebGL よりもレスポンスいいし、AIR ならアンドロイドで動くかもしれないので、おもしろいかもしれません。

Flex4バージョン



AR では、マーカーが必要なので、簡単にテストできるように画面上に画像貼っているので、そこへカメラを向ければ 3D モデル等を表示できます。画面上でドラッグすると字が書けますし、透過の画像をうまく配置すると吹き出しにセリフいれたり、その画像を 3D としてロードしてもいいです。ただ、3D 平面と 3D 球は位置固定なので使い勝手は悪いです。3D モデルは、データの座標を移動すれば位置は変えれますけど。



モデルは複数ロードできるので、座標を調整すると並んで表示できますが、なにもしないとこんな事になりますwww



※ 書いた文字は、色を白に変えて書くとリセットされます。


<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
	xmlns:mx="library://ns.adobe.com/flex/mx"
	xmlns:s="library://ns.adobe.com/flex/spark"
	applicationComplete="initOk();"
	usePreloader="true"
>

<fx:Script>
<![CDATA[

	import mx.controls.*;
	import mx.events.*; 
	import mx.formatters.*;
	import mx.graphics.codec.PNGEncoder;
	import flash.external.*;
	import flash.media.Camera;
	import org.libspark.pv3d.Metasequoia_v;

	private var camera:Camera;
	private var fRef:FileReference;
	private var loader:Loader;
	private var actType:int = 0;

	private var sc:SimpleCube;

	private var m_status:Boolean = false;
	private var cvs_thickness:Number = 4;
	private var cmd_cnt:Number = 0;
	private var bmp:BitmapData = null;
	private var mqo_v:Metasequoia_v = null;

	// *********************************************************
	// ログ表示
	// *********************************************************
	public function firebug(data:Object):void {
	
		var fmt:DateFormatter = new DateFormatter();
	
		fmt.formatString = "YYYY/MM/DD HH:NN:SS";
		var logdt:String = fmt.format( new Date );
	
		ExternalInterface.call(
			"console.log", logdt,
			data+""
		);
	
	}

	// *********************************************************
	// 初期処理
	// *********************************************************
	public function initOk():void {

		// NumericStepper のイベント処理
		ns.addEventListener( flash.events.Event.CHANGE,
			function(e:flash.events.Event):void {
				if ( mqo_v != null ) {
					mqo_v.scale = ns.value;
				}
			}
		);
		ns2.addEventListener( flash.events.Event.CHANGE,
			function(e:flash.events.Event):void {
				if ( mqo_v != null ) {
					mqo_v.rotationX = ns2.value;
				}
			}
		);

		camera = Camera.getCamera();
		if ( camera ) {
			sc = new SimpleCube();
			myImage.rawChildren.addChild(sc);
			firebug("FLARToolKit を追加しました");
		}


		// ファイルリファレンスの準備
		fRef = new FileReference();
		// ファイル保存用ダイアログを表示して保存する
		// ビルドに -target-player=10.0.12 オプションが必要
		// 以下の例では、エラー以外のイベントには空の無名関数が関係づけられています
		fRef.addEventListener(Event.OPEN, function(e:Event):void {} );
		fRef.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent):void {} );
		fRef.addEventListener(Event.COMPLETE, function(e:Event):void {

			firebug( actType );
			// 処理完了後の処理

			// 読み出す
			if ( actType == 0 ) {
				loader = new Loader();
				loader.loadBytes(FileReference(e.target).data);
				loader.contentLoaderInfo.addEventListener(Event.INIT,function(e:Event):void{

					firebug( "追加しました1" );
					myImage.rawChildren.addChild(e.target.content);
					firebug( "追加しました2" );
					firebug( e.target.content );
				});
				firebug( "ロードが完了しました" );
			}
			if ( actType == 2 ) {
				loader = new Loader();
				loader.loadBytes(FileReference(e.target).data);
				loader.contentLoaderInfo.addEventListener(Event.INIT,function(e:Event):void{

					firebug( "追加しました1" );
					if ( camera ) {
						sc.loadImageNormal(e.target.content);
					}
					firebug( "追加しました2" );
					firebug( e.target.content );
				});
				firebug( "ロードが完了しました" );
			}

			if ( actType == 3 ) {
				loader = new Loader();
				loader.loadBytes(FileReference(e.target).data);
				loader.contentLoaderInfo.addEventListener(Event.INIT,function(e:Event):void{

					firebug( "追加しました1" );
					if ( camera ) {
						sc.loadImageBall(e.target.content);
					}
					firebug( "追加しました2" );
					firebug( e.target.content );
				});
				firebug( "ロードが完了しました" );
			}

			// 保存が完了
			if ( actType == 1 ) {
				firebug( "保存が完了しました" );
			}
		} );
		fRef.addEventListener(Event.CANCEL, function(e:Event):void {} );
		fRef.addEventListener(Event.SELECT, function(e:Event):void {
			// ファイル選択後の処理
			if ( actType == 0 ) {
				firebug( "ロードします" );
				FileReference(e.target).load();
				firebug( "ロードを開始しました" );
			}
			if ( actType == 2 ) {
				firebug( "3D平面ロードします" );
				FileReference(e.target).load();
				firebug( "3D平面ロードを開始しました" );
			}
			if ( actType == 3 ) {
				firebug( "3D球面ロードします" );
				FileReference(e.target).load();
				firebug( "3D球面ロードを開始しました" );
			}
			if ( actType == 1 ) {
				firebug( "保存します" );
			}
		} );
		fRef.addEventListener(IOErrorEvent.IO_ERROR, fRefError );


		// *************************************************
		// メタセコイア拡張のロード完了
		// *************************************************
		mqo_v = new Metasequoia_v();
		mqo_v.addEventListener(Event.COMPLETE, function(e:Event):void {

			sc.loadMqo(mqo_v);
			mqo_v.rotationX = -90;
			mqo_v.scale = 1;
			ns.value = 1;
			ns2.value = mqo_v.rotationX;

		});

	}

	// *********************************************************
	// 撮影と保存( Flash 全体 )
	// *********************************************************
	public function shot():void {

		myPanel.title = comment.text;

		var bitmap:Bitmap = new Bitmap();
		var bitmapData:BitmapData = new BitmapData(shotarea.width, shotarea.height);
		bitmap.bitmapData = bitmapData;
		bitmapData.draw(shotarea);

		var pngEnc:PNGEncoder = new PNGEncoder();
		var png:ByteArray = pngEnc.encode(bitmap.bitmapData);

		firebug( "撮影しました" );

		actType = 1;
		fRef.save( png, "shot.png" );

	}

	// *********************************************************
	// IOエラー
	// *********************************************************
	public function fRefError( e:IOErrorEvent ):void {
		Alert.show(e.text);
	}

	// *********************************************************
	// マウスダウン
	// *********************************************************
	public function Mouse_Down(e:flash.events.MouseEvent):void {

		m_status = true;
		cvs.graphics.moveTo(
			e.localX,
			e.localY
		);

	}

	// *********************************************************
	// マウスアップ
	// *********************************************************
	public function Mouse_Up(e:flash.events.MouseEvent):void {

		m_status = false;

	}

	// *********************************************************
	// マウス移動
	// *********************************************************
	public function Mouse_Move(e:flash.events.MouseEvent):void {

		if ( m_status ) {

			cvs_thickness = 4;
			if ( cp.selectedColor == 0xffffff ) {
				bmp = new BitmapData(640,480,true,0x00000000);
				cvs.graphics.clear();
				cvs.graphics.beginBitmapFill(bmp); 
				cvs.graphics.drawRect(0, 0, bmp.width, bmp.height); 
				cvs.graphics.endFill(); 
				cp.selectedColor = 0x000000;
				cvs.graphics.moveTo(
					e.localX,
					e.localY
				);
				return;
			}
			cvs.graphics.lineStyle(
				cvs_thickness,
				cp.selectedColor,
				1
			);
			cvs.graphics.lineTo(
				e.localX,
				e.localY
			);
			cmd_cnt++;
			if ( cmd_cnt > 20 ) {
				cmd_cnt = 0;
				Convert_bmp();
			}
			cvs.graphics.moveTo(
				e.localX,
				e.localY
			);
		}
	}

	// *********************************************************
	// 変換
	// *********************************************************
	public function Convert_bmp():void {

		if ( bmp == null ) {
			bmp = new BitmapData(640,480,true,0x00000000);
		}

		bmp.draw(cvs);
		cvs.graphics.clear();
		cvs.graphics.beginBitmapFill(bmp); 
		cvs.graphics.drawRect(0, 0, bmp.width, bmp.height); 
		cvs.graphics.endFill(); 

	}


]]>
</fx:Script>

<s:Panel
	id="myPanel"
	title="{comment.text}"
	top="10"
	left="10"
	right="10"
	bottom="10"
	mouseDown="Mouse_Down(event)"
	mouseUp="Mouse_Up(event)"
	mouseMove="Mouse_Move(event)"
	mouseOut="Mouse_Move(event)"
>
<s:BorderContainer id="shotarea" left="10" top="10">
	<mx:Canvas
		id="myImage"
		width="640"
		height="480"
	>
	</mx:Canvas>
	<s:SpriteVisualElement
		id="cvs"
		width="640" height="480"
	>
	</s:SpriteVisualElement>
</s:BorderContainer>

<s:VGroup left="10" y="500">
	<s:HGroup paddingTop="10">
		<mx:ColorPicker id="cp" showTextField="true" />
		<s:Button
			styleName="blackButton"
			id="shotButton"
			label="シャッターを押す"
			click="shot();"
			toolTip="撮影"
		/>
		<s:Button
			styleName="blackButton"
			id="loadButton"
			label="ローカル画像のロード"
			click="actType=0;fRef.browse();"
		/>
		<s:TextInput
			id="comment"
			width="250"
			text="メタセコイアとその他のロード"
		/>
	</s:HGroup>
	<s:HGroup paddingTop="10">
		<s:Button
			styleName="blackButton"
			id="load3DButton1"
			label="3D平面ロード"
			click="actType=2;fRef.browse();"
		/>
		<s:Button
			styleName="blackButton"
			id="load3DButton2"
			label="3D球面ロード"
			click="actType=3;fRef.browse();"
		/>
		<s:Button
			styleName="blackButton"
			id="load3DButton6"
			label="メタセコイアとテクスチャの入った ZIP 書庫"
			click="mqo_v.browse('zip');"
		/>
	
		<s:NumericStepper
			id="ns" 
			minimum="0.1"
			 maximum="5" 
			stepSize="0.1" 
			value="1.0" 
			width="60"
		/>
	
		<s:NumericStepper
			id="ns2" 
			minimum="-180"
			 maximum="180" 
			stepSize="10" 
			value="-90" 
			width="60"
		/>
	
	</s:HGroup>
</s:VGroup>


</s:Panel>


</s:Application>

Flex3 から Flex4 の移行にあたって、FLARToolkit のベースとなる Canvas はそのままにしていますが、他は Flex4 仕様です。ColorPicker は、mx しか無いようなのでそのままですが、Flex4 になって結構面倒な仕様変更が多かったですね。やっぱこれじゃあ、日本じゃまだはやんないと思います・・・・はあ。





著作者情報

FLARToolkit
saqoosha
[GPL License]

Metasequoia.as
Copyright (c) 2007-2008 rch850
Metasequoia_v.as
改造 : lightbox

TGADecoder.as
 Copyright (c) 2008 rch850

BMPDecoder.as
Copyright (c) 2007 munegon

Papervision3D
MIT ライセンス

モンスター 3D モデル
光陰像型(3Dキャラ)
初音ミクのライセンス
■ 権利者 : クリプトン・フューチャー・メディア株式会社
■ ライセンス名 : ピアプロ・キャラクター・ライセンス
( ※ キャラクター利用のガイドライン )



しかし、Google Chrome に埋め込まれてる Flash は、Flex でテキスト入力しようとすると、日本語が入力されないというバグがあります。標準の Flash に変更すれば正常になりますが、一般の人には無理でしょうから、作り手は HTML 上で入力させて取り込むという作業が必要ですね。やっぱはやんないなぁ・・・・

▼ 以下はその手順です。



chrome:plugins で表示したページの右上から詳細表示にしてすべての Flash プラグインを表示して、Windows なら gcswf32.dll を無効にする。


ひとりごと

マーカーを 3D 表示させて、そこに カメラ向けるとどうなるんだろ。


タグ:AIR flex FLARToolKit
【AIR Flex( WEB Flex )の最新記事】
posted by at 2012-05-21 11:50 | AIR Flex( WEB Flex ) | このブログの読者になる | 更新情報をチェックする


Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX