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