高速化?いいえ、ブラクラです:SWFアニメから画像輪郭抽出してPixel表示
1.外部SWFから輪郭を取得する。
* 2.Papervision3DのPixcel3Dで描画
*
* @author yooKo@serialField
* @graphic chibitami
* @version 2.0
* Let's Click!
* Click毎に3Dエフェクトが切り替わるお~~
*
* 2009/10/13 13:49
* swfアニメの素材を変更
* chibitami さんのswfアニメのモーションがかなり見栄えがよくサンプルに
* ちょうどよかったので許可を頂いてお借りしました。
* 画像元
* 【CHiBiTAMi.NET/WORKS/】
* http://chibitami.net/works/
* 【Twitter】
* http://twitter.com/chibitami
*
追記 by clockmaker
したこと
・stage.quality
・bitmapDataのlockとunclock
やったら効果あるんじゃないかと思うこと
・画像解析の結果を予め配列に格納
・Papervision3D(Pixels3D)を使わず、2DのBitmapDataに書き込んで、
それをFlash 10の3Dで回転させるとか
追記 by paq
したこと
・画像解析の結果を予め配列に格納
動き出すまで時間掛かるので気長に待っててください。
/**
* Copyright paq ( http://wonderfl.net/user/paq )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/x2ps
*/
// forked from yooKo's 外部SWFアニメから画像の輪郭抽出してPixel表示 feat.chibitami
// forked from yooKo's 外部SWFアニメから画像の輪郭抽出してPixel表示
/**
* 1.外部SWFから輪郭を取得する。
* 2.Papervision3DのPixcel3Dで描画
*
* @author yooKo@serialField
* @graphic chibitami
* @version 2.0
* Let's Click!
* Click毎に3Dエフェクトが切り替わるお~~
*
* 2009/10/13 13:49
* swfアニメの素材を変更
* chibitami さんのswfアニメのモーションがかなり見栄えがよくサンプルに
* ちょうどよかったので許可を頂いてお借りしました。
* 画像元
* 【CHiBiTAMi.NET/WORKS/】
* http://chibitami.net/works/
* 【Twitter】
* http://twitter.com/chibitami
*
**/
/*
追記 by clockmaker
したこと
・stage.quality
・bitmapDataのlockとunclock
やったら効果あるんじゃないかと思うこと
・画像解析の結果を予め配列に格納
・Papervision3D(Pixels3D)を使わず、2DのBitmapDataに書き込んで、
それをFlash 10の3Dで回転させるとか
*/
/*
追記 by paq
したこと
・画像解析の結果を予め配列に格納
動き出すまで時間掛かるので気長に待っててください。
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.StageQuality;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.filters.BitmapFilterQuality;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.system.LoaderContext;
//import flash.system.SecurityDomain;
import flash.system.Security;
import org.papervision3d.core.effects.BitmapLayerEffect;
import org.papervision3d.core.effects.BitmapColorEffect;
import org.papervision3d.core.effects.utils.BitmapClearMode;
import org.papervision3d.core.geom.Pixels;
import org.papervision3d.core.geom.renderables.Pixel3D;
import org.papervision3d.view.BasicView;
import org.papervision3d.view.layer.BitmapEffectLayer;
import net.hires.debug.Stats;
[SWF(width="465", height="465", backgroundColor="0x000000", frameRate="60")]
public class Pixcel3DAnime extends BasicView {
private const IMAGE_URL:String = "http://selflash.jp/wonderfl/dance_girl.swf";
//private const FILTER_BLUR:BlurFilter = new BlurFilter(8, 8, BitmapFilterQuality.LOW);
private const TRANSFORM_COLOR:ColorTransform = new ColorTransform(0, 0, 0, 0, 0, 0, 0, 0);
private const CAMERA_DISTANCE:int = -200;
private const FRAME_COUNT:uint = 180;
private var _loader:Loader;
private var _pixelsStorage:Vector.<Pixels> = new Vector.<Pixels>();
private var _pixels:Pixels;
private var _rotateX:Number = 0;
private var _rotateY:Number = 0;
private var _currentNum:int = 0;
private var _bmd:BitmapData;
private var _pre:Number;
private var _a:Number;
private var _y:Number;
private var _x:Number;
private var _c:uint;
private var _vx:Number = 0;
private var _xx:Number = 0;
private var _vy:Number = 0;
private var _yy:Number = 0;
private var _count:uint = 0;
private var _frame:uint = 0;
// ソース画像のどの部分を解析するか。画像をさしかえる時はここを任意の値に
//解析する開始位置
private const TRIMMING_LEFT:int = 0;
private const TRIMMING_TOP:int = 0;
//解析する終わりの位置
private const TRIMMING_RIGHT:int = 280;
private const TRIMMING_BOTTOM:int = 280;
//=====================================================
//除外したい色
//private var EXCLUSION_COLOR:int = 0xFFFFFF; //白で抜きたいよー
private var EXCLUSION_COLOR:int = 0x00; //アルファで抜きたいよー
// 中央に持ってくる為に使う
private const W:Number = (TRIMMING_RIGHT + TRIMMING_LEFT) * .5/*TRIMMING_LEFT + TRIMMING_RIGHT * .5*/;
private const H:Number = (TRIMMING_BOTTOM + TRIMMING_TOP) * .5/*TRIMMING_TOP + TRIMMING_BOTTOM * .5*/;
//========================================================================
// コンストラクタ
//========================================================================
public function Pixcel3DAnime() {
super(0, 0, true, true);
stage.quality = StageQuality.LOW;
/**
*crossdomainにやらSecurity.allowDomain()やらまだまだ理解が浅くてわかんなかった、、
* 読み込む事はできるがdraw()ができなくて悩んだ。
* 結局呼び出す子swfの1フレーム目にSecurity.allowDomain("*")と記述した事でおk。
* ※Security.allowDomain("http://www.selflash.jp/")ではダメだった・・この辺はなんでか分かんない
* http://cocoasaurus.com/blog/2009/09/as3allowdomain-1.html
* ↑のリンク先の情報によると読み込む方と読み込まれる方の両方に Security.allowDomain() を記述しないといけないらしいが
* ↓はコメントアウトしても draw() 出来てる。これもなぜだかわかんない、、、
*/
//Security.allowDomain("*");
if (!stage)
addEventListener(Event.ADDED_TO_STAGE, init);
else
init();
}
//========================================================================
// 画像の読み込み
//========================================================================
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
_loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
_loader.load(new URLRequest(IMAGE_URL), new LoaderContext(true));
}
//========================================================================
// ロード完了後の処理
//========================================================================
private function onCompleteHandler(e:Event):void {
e.target.removeEventListener(Event.COMPLETE, init);
//こいつから毎回色、座標を解析する
_bmd = new BitmapData(TRIMMING_RIGHT, TRIMMING_BOTTOM, true, 0xFFFFFF);
//左下に表示するためのやつね
var bmp:Bitmap = new Bitmap(_bmd, "auto", false);
bmp.scaleX = .4;
bmp.scaleY = .4;
bmp.y = stage.stageHeight - bmp.height;
addChild(bmp);
camera.z = CAMERA_DISTANCE;
var _layer:BitmapEffectLayer = new BitmapEffectLayer(viewport, stage.stageWidth, stage.stageHeight, true, 0, BitmapClearMode.CLEAR_PRE, false);
viewport.containerSprite.addLayer(_layer);
_layer.addEffect(new BitmapColorEffect(1.2, 1.2, 1.2, .5));
//_layer.drawCommand.blendMode = BlendMode.ADD;
//_layer.addEffect(new BitmapLayerEffect(new BlurFilter(8, 8, BitmapFilterQuality.MEDIUM), false));
_pixels = new Pixels(_layer);
//_pixelsStorage.push(new Pixels(_layer), new Pixels(_layer), new Pixels(_layer), new Pixels(_layer), new Pixels(_layer));
for (var i:uint = 0; i < FRAME_COUNT; i++ )
{
_pixelsStorage.push(new Pixels(_layer));
scene.addChild(_pixelsStorage[i]);
_pixelsStorage[i].visible = false;
}
addEventListener(Event.ENTER_FRAME, upDate);
addEventListener(MouseEvent.MOUSE_DOWN, onDownHandler);
startRendering();
addChild(new Stats());
}
//========================================================================
// 表示の切り替え
// ここ失敗作。。切り替えの仕組みがしょぼすぎる・・・なんか挙動が変、、スマートな方法あったら教えてください、、
//========================================================================
private function onDownHandler(e:MouseEvent = null):void {
//_currentNum++;
//if (_currentNum > 6) {
//_currentNum = 0;
//}
/*if(_currentNum > 6)_currentNum = 0;
_vx = (Math.random() - .5) * 200;
_vy = (Math.random() - .5) * 200;*/
}
//========================================================================
// 常に行う処理
//========================================================================
private function upDate(e:Event):void {
_rotateX += (- viewport.containerSprite.mouseX - _rotateX) * 0.1;
_rotateY += (- viewport.containerSprite.mouseY - 170 - _rotateY) * 0.1;
//_bmd.applyFilter(_bmd, _bmd.rect, new Point(), FILTER_BLUR);
//_bmdの中身を毎回消すには↓のどっちかだけどnew BitmapData()するとやっぱり重い、、
_bmd.colorTransform(_bmd.rect, TRANSFORM_COLOR);
//_bmd = new BitmapData(TRIMMING_RIGHT, TRIMMING_BOTTOM, true, 0x00);
//_pixels.removeAllpixels();
_bmd.draw(_loader);
/** エフェクトの切り替え
* =================================================================
* 基本的には createBody()で全体,createFrame()で枠組みのみを生成します。
* 引数の説明
* 1つ目はレイヤーのz座標。
* 2つ目はドットの細かさ。
* 3つ目の色を指定しないという事はBitmapDataから取得した色をそのまま使うという事です。
* 引数を調整したりcreateBody(),createFrame()を増やしたりして調整してください。
* ==================================================================
*/
switch (_currentNum) {
// ノーマル //////////////////////////////////////
case 0:
// swfから取得した色で全体を表示する1層のレイヤー画像を作成
//createBody(0, 2)
if (_count < FRAME_COUNT-1)
{
createBody(0, 2)
//_pixelsStorage.push(createBody(0, 2));
_count++;
}
else if (_frame < FRAME_COUNT)
{
//_pixels = _pixelsStorage[0];
_pixelsStorage[_frame].visible = true;
_pixelsStorage[_frame].rotationY = _rotateX;
_pixelsStorage[_frame].rotationX = _rotateY;
for (var i:uint = 0; i < FRAME_COUNT; i++ )
{
if (i != _frame)
{
//trace(i + ":" + _frame)
_pixelsStorage[i].visible = false;
}
}
//trace(_frame + ":" + _pixelsStorage[_frame].visible)
_frame++
if (_frame >= FRAME_COUNT)
{
_frame = 0;
}
}
break;
// 3D //////////////////////////////////////////
/*case 1:
// 指定した色で表示をする5層のレイヤーからなる厚みのある画像を作成。bodyでframeをサンドイッチ
createBody(-9, 4, 0xFFCCFF33);
createFrame(-6, 5, 0xFFCCFF33);
createFrame(-3, 5, 0xFFCCFF33);
createFrame(0, 5, 0xFFCCFF33);
createFrame(3, 5, 0xFFCCFF33);
createFrame(6, 5, 0xFFCCFF33);
createBody(9, 4, 0xFFCCFF33);
break;
// シルエット /////////////////////////////////////
case 2:
// 指定した色で全体を表示する1層のレイヤー画像を作成。
createBody(0, 3, 0xFFCCFF00);
break;
// フレーム //////////////////////////////////////
case 3:
// 指定した色で枠組みを表示する1層のレイヤー画像を作成。
createFrame(0, 2, 0xFFCCFF99);
break;
// 地震エフェクト? /////////////////////////////////
case 4:
// 指定した色で枠組みを表示する1層のレイヤー画像を作成。
createBody(0, 3, 0, ((Math.random() - .5) * 50));
break;
// ディスコエフェクト //////////////////////////////////
case 5:
// 指定した色で枠組みを表示する1層のレイヤー画像を作成。
createBody(0, 3, ((Math.random() - .7) * 5), ((Math.random() - .5) * 50));
break;
//ノイズエフェクト /////////////////////////////////////
case 6:
// 指定した色で枠組みを表示する1層のレイヤー画像を作成。
createBody(0, 3, 0xFF33CC00, 0, true);
break;*/
};
_xx += (_vx - _xx ) * .1;
_yy += (_vy - _yy ) * .1;
}
//========================================================================
// 中身を作成するメソッド
// 呼び出されたら白以外全部解析する
// ※ 引数に色の指定がなければ抽出した色を使う
//========================================================================
private function createBody(depth:Number = 0, distance:Number = 2, color:Number = NaN, disco:Number = 0, noise:Boolean = false):void {
_bmd.lock();
for ( _y = TRIMMING_TOP; _y < TRIMMING_BOTTOM; _y += distance ) {
for ( _x = TRIMMING_LEFT; _x < TRIMMING_RIGHT; _x += distance ) {
_c = _bmd.getPixel( _x, _y );
if (_c != EXCLUSION_COLOR) {
_c = (color)?color:rgb2argb(_c, 1);
if (noise) {
depth = depth + ((Math.random() - .5) * 2);
};
_pixelsStorage[_count].addPixel3D(new Pixel3D(_c, _x - W, _y - H, depth + disco));
}
}
}
_bmd.unlock();
}
//========================================================================
// 枠組みを作成するメソッド
// 呼び出されたらキャラクターの外枠だけ解析する
// ※ 引数に色の指定がなければ抽出した色を使う
//========================================================================
/*private function createFrame(depth:Number = -4, distance:Number = 2, color:Number = NaN, noise:Number = 0):void {
_bmd.lock();
for ( _y = TRIMMING_TOP; _y < TRIMMING_BOTTOM; _y += distance ) {
for ( _x = TRIMMING_LEFT; _x < TRIMMING_RIGHT; _x += distance ) {
_c = _bmd.getPixel( _x, _y );
if (_c != EXCLUSION_COLOR) {
_a = (_y == 0)?0:_x - W - _pre;
if (_a > distance || _a < - distance) {
_c = (color)?color:rgb2argb(_c, 1);
_pixels.addPixel3D(new Pixel3D(_c, _x - W, _y - H, depth));
}
_pre = _x - W;
}
}
}
for ( _x = TRIMMING_LEFT; _x < TRIMMING_RIGHT; _x += distance ) {
for ( _y = TRIMMING_TOP; _y < TRIMMING_BOTTOM; _y += distance ) {
_c = _bmd.getPixel( _x, _y );
if (_c != EXCLUSION_COLOR) {
_a = (_x == 0)?0:_y - H - _pre;
if(_a > distance || _a < - distance) {
_c = (color)?color:rgb2argb(_c, 1);
_pixels.addPixel3D(new Pixel3D(_c, _x - W, _y - H, depth));
}
_pre = _y - H;
}
}
}
for ( _y = TRIMMING_BOTTOM; _y > TRIMMING_TOP; _y -= distance ) {
for ( _x = TRIMMING_RIGHT; _x > TRIMMING_LEFT; _x -= distance ) {
_c = _bmd.getPixel( _x, _y );
if (_c != EXCLUSION_COLOR) {
_a = (_y == TRIMMING_TOP + TRIMMING_BOTTOM)?0:_x - W - _pre;
if(_a > distance || _a < - distance) {
_c = (color)?color:rgb2argb(_c, 1);
_pixels.addPixel3D(new Pixel3D(_c, _x - W, _y - H, depth));
}
_pre = _x - W;
}
}
}
for ( _x = TRIMMING_RIGHT; _x > TRIMMING_LEFT; _x -= distance ) {
for ( _y = TRIMMING_BOTTOM; _y > TRIMMING_TOP; _y -= distance ) {
_c = _bmd.getPixel( _x, _y );
if (_c != EXCLUSION_COLOR) {
_a = (_x == TRIMMING_LEFT + TRIMMING_RIGHT)?0:_y - H - _pre;
if(_a > distance || _a < - distance) {
_c = (color)?color:rgb2argb(_c, 1);
_pixels.addPixel3D(new Pixel3D(_c, _x - W, _y - H, depth));
}
_pre = _y - H;
}
}
}
_bmd.unlock();
}*/
//========================================================================
// RGBをARGBに変換する
//========================================================================
private function rgb2argb(rgb:uint, alpha:Number):uint {
return ((alpha * 0xff) << 24) + rgb;
}
}
}