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

BitmapDataで3D表現を試してみる。

BitmapDataの勉強をしたかったので、
沢山のサンプルがあるパーティクル表現を教材にしました。

BitmapDataでは、3Dに関する操作はできない
とのことだったので、
疑似的に3D表現を試みました。
深度の表現に関しては、alpha値、サイズの2要素を取り入れました。

深度については、ビームのサイズを大きくするとわかりますが、α値のグラデーションがx軸方向にリニアにかかっちゃっています。
また、サイズについてもrectangleを利用したものなので、形が四角形へと変形していきます。
どちらも、適応させる分だけBitmapDataを用意した方が奇麗ですが、
面倒なので一括で計算しています。

説明文や変数名でビームとかBeemを使っていますが、
最初につくった変数名を変えるのが面倒だったからです。
分かりにくくてごめんなさい(・´ω`・)b

任意の軸で回転させてみた↓
http://wonderfl.net/c/5VCy
Get Adobe Flash player
by code 28 Apr 2010
/**
 * Copyright code ( http://wonderfl.net/user/code )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ircB
 */

/*
	BitmapDataの勉強をしたかったので、
	沢山のサンプルがあるパーティクル表現を教材にしました。
	
	BitmapDataでは、3Dに関する操作はできない
	とのことだったので、
	疑似的に3D表現を試みました。
	深度の表現に関しては、alpha値、サイズの2要素を取り入れました。
	
	深度については、ビームのサイズを大きくするとわかりますが、α値のグラデーションがx軸方向にリニアにかかっちゃっています。
	また、サイズについてもrectangleを利用したものなので、形が四角形へと変形していきます。
	どちらも、適応させる分だけBitmapDataを用意した方が奇麗ですが、
	面倒なので一括で計算しています。
	
	説明文や変数名でビームとかBeemを使っていますが、
	最初につくった変数名を変えるのが面倒だったからです。
	分かりにくくてごめんなさい(・´ω`・)b
	
	任意の軸で回転させてみた↓
	http://wonderfl.net/c/5VCy
	
*/
package 
{

	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.text.TextField;
	
	//よくわからないけど、便利なものらしい
	[SWF(width="512",height="512", frameRate="30" )]
	
	public class main extends Sprite 
	{
		//変数
		private var fromPoint:Vector3D;	//出発地点
		private var canvas:BitmapData;	//ビットマップを描写するカンバス
		private var dammy:Sprite;		//ダミーの3D空間
		private const PI2:Number = Math.PI * 2;	//phi
		private var beemBMD:BitmapData;	//ビームのビットマップデータ
		private var alphaBMD:BitmapData;	//深度調整用のビットマップデータ
		private var Beems:Vector.<BeemManager>;	//ビームのインスタンスを格納する配列
		private var BeemPool:Vector.<BeemManager>;	//ビームのインスタンスをプールしておくための配列

		//ビーム初期設定用
		private const size:uint=2; //ビームの大きさ
		private const color:uint=0xffffff*((Math.random()*0.3)+0.7); //ビームの色 好きな色は16538071です!明るい色へオフセット
		private const SPEED:uint = 2; //ビームのスピード
		
		//球体作成用
		private const ADD_NUM:uint = 30; //1フレームで追加するビームの数
		private const RADIUS:uint = 200; //球体の半径
		private const BLUR:Number = 0.7; //モーションブラーフェード値
		private const fromOffset:uint = 160;	//発生地点のオフセット
		
		//デバッグ用のテキスト(必要なし)
		private var debugTxt:TextField;
		private var debugTxt2:TextField;
		
		//コンストラクタ
		public function main()
		{
			
			//初期化
			setInit();
			
			//空間情報を格納するスプライト登録
			setCanvas();
			
			//ビームbitmapData作成
			createBEEMBMD();
			
			//ループ処理
			addEventListener(Event.ENTER_FRAME, loopHandler);
			
			//debug要のテキスト
			setDebugTxt();
			
		}
		
		//色々初期化
		private function setInit():void
		{
			//ステージの情報
			stage.quality = StageQuality.MEDIUM;
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			
			//出発地点
			fromPoint = new Vector3D(0, 0, 0);
			
			//消失点設定
			this.transform.perspectiveProjection.projectionCenter = new Point(stage.stageWidth / 2, stage.stageHeight / 2);
			
			//ダミー用スプライト
			dammy = new Sprite();
			addChild(dammy);
			dammy.x = stage.stageWidth / 2;
			dammy.y = stage.stageHeight / 2;
			
			//BeemManagerインスタンスをプールさせておく配列の初期化
			BeemPool = new Vector.<BeemManager>();
			//実際に動いているBeemManagerインスタンスを格納しておく配列の初期化
			Beems = new Vector.<BeemManager>();
			
		}
		
		//bitmapデータを描くカンバス作成
		private function setCanvas():void
		{
			canvas = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
			addChild(new Bitmap(canvas));
		}
		
		//ビームのBitmapData作成
		private function createBEEMBMD():void
		{
			
			//ビームのデザインからビットマップデータを作る
			var beem:Shape = new Shape();
			var beemG:Graphics = beem.graphics;
			beemG.beginFill(color);
			beemG.drawCircle(size, size,size);
			beemG.endFill();
			//ビットマップデータ作成
			beemBMD = new BitmapData(beem.width, beem.height, true, 0);
			beemBMD.draw(beem);
			
			//BitmapDataで、深度によるα値を適用させるためのBitmapDataを作成
			beemG.clear();
			//GradientFillのための変数
			var gType:String = GradientType.LINEAR;
			var gColor:Array = [0x000000, 0x000000];
			var gAlpha:Array = [1, 0.1];
			var gRatio:Array = [150, 255];
			//α値をピックアップするためにgradiendFillを使います。
			beemG.beginGradientFill(gType, gColor, gAlpha, gRatio);
			beemG.drawRect(0,0,100,size*2);
			beemG.endFill();
			alphaBMD = new BitmapData(100,size*2, true,0xffffff);
			alphaBMD.draw(beem);
		
		}
			
		private function loopHandler(e:Event):void 
		{
			
			//描画ロック
			canvas.lock();
			
			//疑似モーションブラー
			var ct:ColorTransform = new ColorTransform (BLUR, BLUR, BLUR);
            canvas.colorTransform(canvas.rect, ct);
			
			//新しくビームを作成
			createBEEM();
			
			//ループ処理
			for (var i:uint = 0; i < Beems.length; i++) 
			{
				var beem:BeemManager = Beems[i];
				
				//3D座標を2Dへコンバート
				convert2D(beem);
				
				//中心からの規定値を超えたらプール
				if (beem.radius >= RADIUS){
					poolObject(i);
					continue;
				}
				
				//カンバスにコピー
				canvas.copyPixels(beemBMD, beem.rect, beem.toPoint2D, alphaBMD, new Point(beem.depth, 0), false);
				
			}
			
			//デバッグ用のテキスト
			debugTxt.text = "処理対象のBEEM : "+String(Beems.length);
			debugTxt2.text="プールしているBEEM : "+String(BeemPool.length)
			
			//描画ロック解除
			canvas.unlock();
			
		}
		
		//ビームインスタンスをプールする
		private function poolObject(i:uint):void
		{
				//プール配列へBeemManagerインスタンスを格納
				BeemPool.push(Beems[i]);
				//処理対象の配列から削除
				Beems.splice(i, 1);
		}
		
		//新しくビームを作成
		private function createBEEM():void 
		{
			//新しく追加するビームの初期化
			for (var i:uint = 0; i < ADD_NUM; i++)
			{
				//新しくビームを作成
				var newBeem:BeemManager;
				if ( BeemPool.length != 0){
				//プールしているBeemManagerインスタンスがあったら。そこから持ってくる。
					newBeem = BeemPool.pop();
				}else{
				//プールしているBeemManagerインスタンスが無かったら新しく作成。
					newBeem = new BeemManager();
				}
				
				//座標を決める要素の初期化
				newBeem.angleAlpha = Math.random() * Math.PI * 2;
				newBeem.angleBeta = Math.random() * Math.PI * 2;
				newBeem.radius = (RADIUS - fromOffset) * Math.random() + fromOffset;
				newBeem.depth = 0;
				
				//作ったビームインスタンスを処理対象の配列へ格納
				Beems.push(newBeem);
				
			}
		}		
			
		//3D座標を2D座標へコンバート
		private function convert2D(beem:BeemManager):void
		{	
			//移動
			beem.radius += SPEED;
			
			//3D座標を計算
			var posX:Number = beem.radius * Math.cos(beem.angleBeta) * Math.sin(beem.angleAlpha);
			var posY:Number = beem.radius* Math.sin(beem.angleBeta);
			var posZ:Number = beem.radius * Math.cos(beem.angleBeta) * Math.cos(beem.angleAlpha);	
			
			//2D座標へ変換するときにVector3Dクラスが必要なので、いったん格納
			beem.toPoint3D = new Vector3D(posX, posY, posZ);
			
			//2D座標へコンバート
			beem.toPoint2D = dammy.local3DToGlobal(beem.toPoint3D);
			
			//深度を計算 100分割
			var myDepth:Number = (posZ + RADIUS) / RADIUS*0.5;
			beem.depth = myDepth*100 | 0;
			
			//サイズ決定 sizeで分割 rectoangleによる疑似的なもの。
			var n:uint = myDepth * size * 2 | 0;
			var m:Number = n * 0.5;
			var l:Number = size * 2 - n+1;
			beem.rect = new Rectangle(m, m, l, l);
		}


		//デバッグ用のテキスト	
		private function setDebugTxt():void
		{
			debugTxt = new TextField();
			debugTxt.autoSize = "left";
			debugTxt.textColor = 0xffffff;
			addChild(debugTxt);
			
			debugTxt2=new TextField();
			debugTxt2.autoSize="left";
			debugTxt2.textColor=0xffffff;
			addChild(debugTxt2);
			debugTxt2.y=20;
			
		}
		
	}
	

}


//Beemに関する情報を格納しておくクラス
import flash.geom.*;	
class BeemManager
{
	public var toPoint3D:Vector3D;
	public var toPoint2D:Point;
	public var radius:Number;
	public var angleAlpha:Number;
	public var angleBeta:Number;
	public var depth:Number;
	public var rect:Rectangle;
	
	//コンストラクタ
	public function BeemManager()
	{
		toPoint3D = new Vector3D();
		toPoint2D = new Point();
		radius = 0;
		angleAlpha = 0;
		angleBeta = 0;
		depth = 0;
		rect = new Rectangle(0, 0, 0, 0);
	}
	
}