In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

[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);
    }
}