動きのある部分にパーティクル作成
動きのある部分にパーティクルを作成してみました。
こんな感じ
http://moeten.info/flex/20081004_OpenCanpasDemo2/bin-release/main.html
ほんとはお台場のソニーのメディアージュ(だったかな?)にあるビデオのエフェクトみたいなのを作りたいんだけど、やっぱまだまだ技術が足りない(@_@;)
作り方の簡単な説明。
手順
1.画像をマイフレームキャプチャ
nowbd.draw( myFlv , mat );
2.キャプチャ画像のエッジを取り出す
//エッジの抽出 var Con:ConvolutionFilter = new ConvolutionFilter(3,3); Con.matrix = new Array( 0, -1, 0, -1, 4, -1, 0, -1, 0 ); //Con.bias = 255; nowbd.applyFilter( nowbd , nowbd.rect , new Point() , Con );
3.古い画像との差分を求める
bdArr[j-dnum].draw( bdArr[j] , null , null , "difference" ); bdArr[j-dnum].threshold( bdArr[j-dnum] , bdArr[j-dnum].rect , new Point() , ">" , 0xff333333 , 0xffffffff , 0xffffffff );
4.変化量の大きい部分にパーティクルを設置
for( var x:int = 0 ; x < myImage.width ; x +=step ){ for( var y:int = 0 ; y < myImage.height ; y +=step ){ if( bdArr[j-dnum].getPixel(x,y)==0xffffff ){ if( Math.random() > 0.9 ){ makeParticle(x,y); } } } }
パーティクルは桜パーティクルを使ってます。
すべてのソースコードはこちら
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="left" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5" backgroundAlpha="1" backgroundColor="0xffccff" creationComplete="init()" viewSourceURL="srcview/index.html"> <mx:Script> <![CDATA[ private function init():void{ setCamera(); // カメラを反転させておく // myFlv.scaleX = -1; // myFlv.x = - myFlv.width; // myFlv.source = "01.flv"; } //カメラ private var timer:Timer = new Timer( 24 ); private function setCamera():void{ var camera:Camera = Camera.getCamera(); if( camera != null ){ myFlv.attachCamera( camera ); }else{ myFlv.source = "01.flv"; } timer.addEventListener( TimerEvent.TIMER , myTick ); timer.start(); } //差分をゲット private var nowbd:BitmapData = new BitmapData( 320 , 240 ); private var bdArr:Array = new Array(); private var j:int = 0; private var dnum:int = 5; private function myTick( e:TimerEvent ):void{ var mat:Matrix = new Matrix(); // mat.scale(-1,1); // mat.tx = 320; nowbd.draw( myFlv , mat ); // nowbd.applyFilter( nowbd , nowbd.rect , new Point() , myBlur ); //エッジの抽出 var Con:ConvolutionFilter = new ConvolutionFilter(3,3); Con.matrix = new Array( 0, -1, 0, -1, 4, -1, 0, -1, 0 ); // Con.bias = 255; nowbd.applyFilter( nowbd , nowbd.rect , new Point() , Con ); //コピー。こうするとちらつきがなくなる bdArr[j] = nowbd.clone(); //画像の差分を取得する if( bdArr.length > dnum ){ bdArr[j-dnum].draw( bdArr[j] , null , null , "difference" ); bdArr[j-dnum].threshold( bdArr[j-dnum] , bdArr[j-dnum].rect , new Point() , ">" , 0xff333333 , 0xffffffff , 0xffffffff ); //myImage.source = new Bitmap( bdArr[j] ); //変化のあった部分のみパーティクル作成 setSakura(); bdArr[j-dnum].dispose(); } j++; } //変化のあった部分のみパーティクル作成 [Embed(source='sakura.png')]private var flower:Class; [Embed(source='star.png')] private var star:Class; [Embed(source='heart.png')] private var heart:Class; private var step:int = 20; private function setSakura():void{ for( var x:int = 0 ; x < myImage.width ; x +=step ){ for( var y:int = 0 ; y < myImage.height ; y +=step ){ if( bdArr[j-dnum].getPixel(x,y)==0xffffff ){ if( Math.random() > 0.9 ){ makeParticle(x,y); } } } } } private var _vol:Number; private var _drag:Number; private var _shrink:Number; private var _gravity:Number; private var _fade:Number; private var _wind:Number; private var xVelArr:Array = new Array(); private var yVelArr:Array = new Array(); private var rotArr:Array = new Array(); private var cnt:int = 0; private function makeParticle(x:Number,y:Number):void{ _vol = p_vol.value; _drag = p_drag.value; _shrink = p_shrink.value; _gravity = p_gravity.value; _fade = p_fade.value; _wind = p_wind.value; for (var i:uint = 0; i < 2; i++){ var pt:Point = getNearPoint( new Point( x , y ) ); var mc:Bitmap; if( typeBox.selectedIndex == 0 ){ mc = new flower(); }else if( typeBox.selectedIndex == 1 ){ mc = new star(); }else if( typeBox.selectedIndex == 2 ){ mc = new heart(); } mc.x = pt.x; mc.y = pt.y; mc.alpha = Math.random()*1; mc.name = "" + cnt; xVelArr[cnt] = getRandRange( -5, 5); yVelArr[cnt] = getRandRange( -5, 5); rotArr[cnt] = getRandRange( -20, 20); mc.addEventListener(Event.ENTER_FRAME, function(e:Event):void{ var m:Bitmap = e.target as Bitmap; m.filters = [gf]; if ( m.alpha > 0){ var c:int = int( m.name ); m.x += xVelArr[c] + _wind * 10; m.y += yVelArr[c]; xVelArr[c] *= _drag; yVelArr[c] *= _drag; m.scaleX *= _shrink; m.scaleY *= _shrink; yVelArr[cnt] += _gravity; m.alpha -= _fade; m.rotation += rotArr[c]; }else{ m.removeEventListener(Event.ENTER_FRAME, arguments.callee); myCover.removeChild(m); m = null; } }); cnt ++; myCover.addChild( mc ); } } private function getRandRange(min:Number, max:Number):Number{ var randomNum:Number = (Math.random() * (max - min )) + min; return randomNum; } private function getNearPoint(pt1:Point):Point{ var len:uint = Math.round(Math.random() * 10); var angle:uint = Math.round(Math.random() * 2 * Math.PI); var pt2:Point = Point.polar(len, angle); pt2.offset( pt1.x, pt1.y ); return pt2; } [Bindable] private var typeArr:Array = new Array( {"label":"桜", "type":"sakura", "vol":3,"drag":0.9,"shrink":0.95,"gravity":-0.2,"fade":0.02,"wind":-0.2}, {"label":"星", "type":"star", "vol":3,"drag":0, "shrink":0.95,"gravity":0, "fade":0.02,"wind":0}, {"label":"ハート","type":"heart", "vol":3,"drag":0, "shrink":1.05,"gravity":-2, "fade":0.06,"wind":0} ); private function setType():void{ var n:int = typeBox.selectedIndex; p_vol.value = typeArr[n].vol; p_drag.value = typeArr[n].drag; p_shrink.value = typeArr[n].shrink; p_gravity.value = typeArr[n].gravity; p_fade.value = typeArr[n].fade; p_wind.value = typeArr[n].wind; } ]]> </mx:Script> <mx:GlowFilter id="gf" blurX="16" blurY="16" color="0xffccff" /> <mx:BlurFilter id="myBlur" blurX="8" blurY="8" /> <mx:Canvas width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off"> <mx:Image id="myImage" width="320" height="240" visible="false" y="240"/> <mx:VideoDisplay id="myFlv" width="320" height="240" scaleX="{this.width/320}" scaleY="{this.height/240}" visible="true"/> <mx:Image id="myCover" width="320" height="240" scaleX="{this.width/320}" scaleY="{this.height/240}"/> <mx:VBox backgroundAlpha="0.5" backgroundColor="0xffffff" horizontalAlign="left" cornerRadius="5" borderColor="0xcccccc" borderStyle="solid" borderThickness="3" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5" left="5" top="5" > <mx:ToggleButtonBar id="typeBox" labelField="label" itemClick="setType()" selectedIndex="0" width="100%" dataProvider="{typeArr}"/> <mx:HSlider id="p_vol" labels="{['vol '+p_vol.value]}" minimum="0" maximum="10" value="3" snapInterval="1"/> <mx:HSlider id="p_drag" labels="{['drag'+p_drag.value]}" minimum="0" maximum="2" value="0.9" snapInterval="0.01"/> <mx:HSlider id="p_shrink" labels="{['shrink'+p_shrink.value]}" minimum="0" maximum="2" value="0.95" snapInterval="0.01"/> <mx:HSlider id="p_gravity" labels="{['gravity'+p_gravity.value]}" minimum="-2" maximum="2" value="-0.2" snapInterval="0.01"/> <mx:HSlider id="p_fade" labels="{['fade'+p_fade.value]}" minimum="0" maximum="2" value="0.02" snapInterval="0.01"/> <mx:HSlider id="p_wind" labels="{['wind'+p_wind.value]}" minimum="-2" maximum="2" value="-0.2" snapInterval="0.01"/> </mx:VBox> </mx:Canvas> </mx:Application>