[FLARToolkit] マーカーに「蝶」がとまる (Butterfly Animation)
-------------------------------------------------
*
* FLARToolkit Butterfly Animation
*
* マーカーを認識すると、「蝶」がマーカーによってきて、とまります。
* 非認識だと、飛び立ちます。
* 認識中マーカーを極端に動かすと、飛び立ち、また、マーカー位置にとまります。
*
* 認識中はマーカー位置に花とか表示するとよい?かも
*
* [marker pdf] マーカーをプリントしてください
* www.romatica.com/dev/resource/flarlogo-marker.pdf
*
*-------------------------------------------------
/**
* Copyright romatica ( http://wonderfl.net/user/romatica )
* GNU General Public License, v3 ( http://www.gnu.org/licenses/quick-guide-gplv3.html )
* Downloaded from: http://wonderfl.net/c/yUB8
*/
// forked from romatica's FLARToolkitマーカー位置にイージング移動 (easing motion)
// forked from rokubou's FLARToolKit_Sample_Simple_PV3D
/**
*-------------------------------------------------
*
* FLARToolkit Butterfly Animation
* @auther itoz ( http://www.romatica.com/ )
*
* マーカーを認識すると、「蝶」がマーカーに寄って来て、留まります。
* 非認識だと、飛び立ちます。
* 認識中マーカーを極端に動かすと、飛び立ち、また、マーカー位置に留まります。
*
* [marker pdf] マーカーをプリントして下さい。
* http://www.romatica.com/dev/resource/flarlogo-marker.pdf
*
*-------------------------------------------------
*/
package
{
import org.libspark.flartoolkit.core.FLARCode;
import org.libspark.flartoolkit.core.param.FLARParam;
import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData;
import org.libspark.flartoolkit.core.transmat.FLARTransMatResult;
import org.libspark.flartoolkit.detector.FLARSingleMarkerDetector;
import org.libspark.flartoolkit.support.pv3d.FLARBaseNode;
import org.libspark.flartoolkit.support.pv3d.FLARCamera3D;
import org.papervision3d.core.math.Matrix3D;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.render.LazyRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.PixelSnapping;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.media.Camera;
import flash.media.Video;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.utils.Dictionary;
[SWF(width=465, height=465, backgroundColor=0x808080, frameRate=30)]
public class FLARToolkit_Butterfly extends Sprite
{
/**FLAR*/
protected var cameraParamFile : String;
private var _canvasWidth : int;
private var _canvasHeight : int;
private var _captureWidth : int;
private var _captureHeight : int;
private var _codeWidth : int;
private var _markerPatternFile : String;
private var _cameraParam : FLARParam;
private var _markerPatternCode : FLARCode;
private var _webCamera : Camera;
private var _video : Video;
private var _capture : Bitmap;
private var _raster : FLARRgbRaster_BitmapData;
private var _detector : FLARSingleMarkerDetector;
private var _urlLoader : URLLoader;
private var _scene : Scene3D;
private var _viewport : Viewport3D;
private var _camera3D : FLARCamera3D;
private var _renderer : LazyRenderEngine;
private var _markerNode : FLARBaseNode;
private var _container : DisplayObject3D;
private var _modelWRAP : DisplayObject3D;
private var _hane1BM : Bitmap;
private var _hane2BM : Bitmap;
private var _lastRot : Number3D = new Number3D();
private var _loaderList : Dictionary;
private var _loadCount : int = 0;
private const LOAD_URL_ARRAY : Array = ["http://www.romatica.com/dev/wonderfl/butterfly1.png",
"http://www.romatica.com/dev/wonderfl/butterfly2.png"];
private var _butt : DisplayObject3D;
private var _hane1 : Plane ;
private var _hane2 : Plane;
private var _recognizer : TextField ; //認識/非認識 表示
private const STAY_LIMIT : int = 20; //蝶が飛び立つきっかけとなる目標点までの距離
/**
* Constructor
*/
public function FLARToolkit_Butterfly()
{
Wonderfl.capture_delay(16);
// 各種サイズの初期化
_captureWidth = 320;
_captureHeight = 240;
_canvasWidth = 640;
_canvasHeight = 480;
_codeWidth = 80;
// パラメータファイルの読込み 今回は省略して初期値を用いる
_cameraParam = new FLARParam();
_cameraParam.changeScreenSize(_captureWidth, _captureHeight);
// マーカーパターンファイルの読込み
_markerPatternFile = 'http://assets.wonderfl.net/static/flar/flarlogo.pat';
_urlLoader = new URLLoader();
_urlLoader.dataFormat = URLLoaderDataFormat.TEXT;
_urlLoader.addEventListener(Event.COMPLETE, this.onLoadCode);
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_urlLoader.load(new URLRequest(_markerPatternFile));
}
// ======================================================================
/**
* マーカーパターンを読み込む
*/
protected function onLoadCode(e : Event) : void
{
_urlLoader.removeEventListener(Event.COMPLETE, this.onLoadCode);
// 分割数(縦・横)、黒枠の幅(縦・横)
_markerPatternCode = new FLARCode(16, 16, 50, 50);
_markerPatternCode.loadARPatt(this._urlLoader.data);
_urlLoader = null;
laodImages(); //画像読み込み
}
// ======================================================================
/**
* imege load start
*/
private function laodImages() : void {
_loaderList = new Dictionary();
for (var i : int = 0;i < LOAD_URL_ARRAY.length ;i++) {
var loader : Loader = new Loader();
_loaderList[loader] = i;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.load(new URLRequest(LOAD_URL_ARRAY[i]), new LoaderContext(true));
}
}
// ======================================================================
/**
* 画像ロードカウント
*/
private function completeHandler(event : Event) : void
{
var loader : Loader = event.target.content.parent as Loader;
switch(_loaderList[loader]) {
case 0:
_hane1BM = event.target.content as Bitmap;
break;
case 1:
_hane2BM = event.target.content as Bitmap;
break;
default:
}
_loadCount++;
if(_loadCount >= LOAD_URL_ARRAY.length) {
_allLoadComplete();
}
}
// ======================================================================
/**
* 画像ロード完了
*/
private function _allLoadComplete() : void
{
onInit();// 初期化
}
// ======================================================================
/**
* Webカメラの設定と、ARToolKitの準備
*/
protected function onInit() : void {
// setup webcam
this._webCamera = Camera.getCamera();
if (!this._webCamera) {
throw new Error('No webcamera!');
}
this._webCamera.setMode(this._captureWidth, this._captureHeight, 30);
this._video = new Video(this._captureWidth, this._captureHeight);
this._video.attachCamera(this._webCamera);
// setup ARToolKit
this._capture = new Bitmap(new BitmapData(this._captureWidth, this._captureHeight, false, 0), PixelSnapping.AUTO, true);
// ウェブカメラの解像度と表示サイズが異なる場合は拡大する
this._capture.width = this._canvasWidth;
this._capture.height = this._canvasHeight;
this.addChild(this._capture);
this._raster = new FLARRgbRaster_BitmapData(this._capture.bitmapData);
// setup Single marker detector
this._detector = new FLARSingleMarkerDetector(this._cameraParam, this._markerPatternCode, this._codeWidth);
this._detector.setContinueMode(true);
// PV3D
_viewport = this.addChild(new Viewport3D(this._captureWidth, this._captureHeight)) as Viewport3D;
_viewport.scaleX = this._canvasWidth / this._captureWidth;
_viewport.scaleY = this._canvasHeight / this._captureHeight;
_viewport.x = -4; // なぜかずれるので補正
_scene = new Scene3D();
_markerNode = this._scene.addChild(new FLARBaseNode(FLARBaseNode.AXIS_MODE_PV3D)) as FLARBaseNode;
_camera3D = new FLARCamera3D(this._cameraParam);
_renderer = new LazyRenderEngine(this._scene, this._camera3D, this._viewport);
_container = new DisplayObject3D();
// モデルデータ
setModelData();
// モデルデータを登録
_markerNode.addChild(this._container);
//認識非認識チェッカー
createRecognizer();
// start
start();
}
// ======================================================================
/**
* 認識チェッカー作成
*/
private function createRecognizer():void
{
_recognizer =addChild( new TextField()) as TextField;
_recognizer.autoSize = TextFieldAutoSize.LEFT;
_recognizer.background = true;
_recognizer.backgroundColor = 0xcc0000;
_recognizer.x = _recognizer.y = 5;
}
// ======================================================================
/**
* 蝶作成
*/
protected function setModelData() : void
{
_modelWRAP = new DisplayObject3D();
_butt = new DisplayObject3D();
var h1BMM : BitmapMaterial = new BitmapMaterial(_hane1BM.bitmapData);
var h2BMM : BitmapMaterial = new BitmapMaterial(_hane2BM.bitmapData);
h1BMM.oneSide = false;
h2BMM.oneSide = false;
_hane1 = new Plane(h1BMM, 43, 61, 4, 6);
_hane2 = new Plane(h2BMM, 43, 61, 4, 6);
_butt.addChild(_hane1);
_butt.addChild(_hane2);
_hane1.transformVertices(Matrix3D.translationMatrix(21.5, 0, 0));
_hane2.transformVertices(Matrix3D.translationMatrix(-21.5, 0, 0));
_modelWRAP.addChild(_butt);
_scene.addChild(_modelWRAP);
}
// ======================================================================
/**
* マーカーの認識と3次元モデルの描写を開始する
*/
public function start() : void
{
// マーカー認識・非認識時用のイベントを登録
this.addEventListener(MarkerEvent.MARKER_ADDED, this.onMarkerAdded);
this.addEventListener(MarkerEvent.MARKER_UPDATED, this.onMarkerUpdated);
this.addEventListener(MarkerEvent.MARKER_REMOVED, this.onMarkerRemoved);
// 処理開始
this.addEventListener(Event.ENTER_FRAME, this.run);
}
// ======================================================================
/**
* 認識したマーカーの情報を格納
*/
protected var resultMat : FLARTransMatResult = new FLARTransMatResult();
public function onMarkerAdded(e : Event = null) : void
{
_recognizer.text = "マーカー認識しています";
_recognizer.backgroundColor = 0xffffff;
}
public function onMarkerUpdated(e : Event = null) : void {
}
public function onMarkerRemoved(e : Event = null) : void {
_recognizer.text = "マーカー認識していません";
_recognizer.backgroundColor = 0xcc0000;
}
// ======================================================================
/**
* 蝶の動き。ここで処理振り分けを行っている
*/
private var _ang : Number = 0;
private var _r : Number = 60;
private var _spd : Number = 60;
public function run(e : Event) : void {
this._capture.bitmapData.draw(this._video);
var rad : Number = _ang / 180 * Math.PI;
var rot : Number = Math.sin(rad);
// Marker detect
var detected : Boolean = false;
try {
detected = this._detector.detectMarkerLite(this._raster, 80) && this._detector.getConfidence() > 0.5;
} catch (e : Error) {
}
if (detected) {
// 認識時
_detector.getTransformMatrix(this.resultMat);
_markerNode.setTransformMatrix(this.resultMat);
var transform : Matrix3D = _markerNode.transform;
_lastRot = Matrix3D.matrix2euler(transform);
this.dispatchEvent(new MarkerEvent(MarkerEvent.MARKER_ADDED));
} else {
// 非認識時
this.dispatchEvent(new MarkerEvent(MarkerEvent.MARKER_REMOVED));
_markerNode.x += (rot * (Math.random() * 30 + 25));
_markerNode.y += (rot * Math.random() * 10 + 3);
_markerNode.z += (rot * (Math.random() * 10 + 10));
if(_markerNode.y>100) _markerNode.y-(Math.random()*10);
}
//距離の絶対値
var _xAbs : Number = (_markerNode.x - _modelWRAP.x);
_xAbs = (_xAbs > 0) ? _xAbs : -_xAbs;
var _yAbs : Number = (_markerNode.y - _modelWRAP.y);
_yAbs = (_yAbs > 0) ? _yAbs : -_yAbs;
var _zAbs : Number = (_markerNode.z - _modelWRAP.z);
_zAbs = (_zAbs > 0) ? _zAbs : -_zAbs;
if(_xAbs > STAY_LIMIT ||
_yAbs > STAY_LIMIT ||
_zAbs > STAY_LIMIT) {
_r = 60;
_ang += _spd;
if(_butt.rotationX < 90)_butt.rotationX += 20;
_butt.x += (rot * (Math.random() * 20));
if(_butt.x > 10 )_butt.x = 10;
if(_butt.x < -10 )_butt.x = -10;
_butt.y += (rot * Math.random() * 25 + 20);
if(_butt.y > 90 )_butt.y = 90;
if(_butt.y < 0 )_butt.y = 0;
_butt.z += (rot * ( Math.random() * 5 + 5));
if(_butt.z > 20 )_butt.z = 20;
if(_butt.z < -20 )_butt.z = -20;
} else {
_r = 30;
_ang += _spd / 11;
}
//羽の動き
_hane1.rotationY = rot * _r;
_hane2.rotationY = -(rot * _r);
//イージング移動
_modelWRAP.x += (_markerNode.x - _modelWRAP.x) * 0.15;
_modelWRAP.y += (_markerNode.y - _modelWRAP.y) * 0.15;
_modelWRAP.z += (_markerNode.z - _modelWRAP.z) * 0.15;
_modelWRAP.rotationX += (_lastRot.x - _modelWRAP.rotationX) * 0.1;
_modelWRAP.rotationY += (_lastRot.y - _modelWRAP.rotationY) * 0.1;
_modelWRAP.rotationZ += (_lastRot.z - _modelWRAP.rotationZ) * 0.1;
//
_butt.rotationX += (0 - _butt.rotationX) * 0.3;
_butt.x += (0 - _butt.x) * 0.2;
_butt.y += (0 - _butt.y) * 0.2;
_butt.z += (0 - _butt.z) * 0.2;
this._renderer.render();
}
}
}
import flash.events.Event;
/**
* イベント制御用の簡易クラス
*/
class MarkerEvent extends Event
{
/** Markerを認識した時*/
public static const MARKER_ADDED : String = "markerAdded";
/**Marker更新時*/
public static const MARKER_UPDATED : String = "markerUpdated";
/**Markerが認識しなくなった時 */
public static const MARKER_REMOVED : String = "markerRemoved";
public function MarkerEvent(type : String, bubbles : Boolean = false, cancelable : Boolean = false) {
super(type, bubbles, cancelable);
}
}