反応拡散系をBitmapで
反応拡散系をBitmapDataとFilterで実現してみた。
特にインタラクションの要素はなく、ただ変形していくのを眺めるだけ。
/**
* Copyright o_healer ( http://wonderfl.net/user/o_healer )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/y8zU
*/
/*
「反応拡散系をBitmapで」
以下のサイトを参考に、BitmapDataとFilterで反応拡散系を実現してみた
・http://www.bio.nagoya-u.ac.jp/~z3/research/rdsoft.htm
放っておくとだんだん形が変わる
・インタラクション要素はなし
ランダムな値からでもちゃんと動作するものの、四角から始まるやつが格好良かったのでここではそれを採用
*/
package {
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
import flash.media.*;
[SWF(width="465", height="465", frameRate="60", backgroundColor="0x000000")]
public class GameMain extends Sprite {
//==Const==
//サイズ
static public const SCL:int = 2;//4;//大きくすると荒くなる(高速化される)
static public const BMD_W:int = 465/SCL;//100;
//Utility
static public const BMD_RECT:Rectangle = new Rectangle(0,0,BMD_W,BMD_W);
static public const POS_ZERO:Point = new Point(0,0);
//Debug
static public const DEBUG:Boolean = false;
//==Var==
//表示用
public var m_BitmapData_View:BitmapData;
public var PALLETE_MAP:Array;
//Debug
public var m_BitmapData_View_U:BitmapData;
public var m_BitmapData_View_V:BitmapData;
//拡散反応用
public var m_BitmapData_Src_U:BitmapData;
public var m_BitmapData_Src_V:BitmapData;
public var m_BitmapData_Dst_U:BitmapData;
public var m_BitmapData_Dst_V:BitmapData;
//作業用
public var dd:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
public var AddU:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
public var SubU:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
public var AddV:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
public var SubV:BitmapData = new BitmapData(BMD_W, BMD_W, false, 0x000000);
//==Function==
//Init
public function GameMain():void {
//表示用
{
//画像
{
m_BitmapData_View = new BitmapData(BMD_W, BMD_W, false, 0x000000);
var bmp_view:Bitmap = new Bitmap(m_BitmapData_View);
bmp_view.scaleX = SCL;
bmp_view.scaleY = SCL;
addChild(bmp_view);
}
//Palette
{
const COLOR_00:uint = 0x111111;
const COLOR_FF:uint = 0xCCCC33;
const COLOR_00_R:uint = (COLOR_00 >> 16) & 0xFF;
const COLOR_00_G:uint = (COLOR_00 >> 8) & 0xFF;
const COLOR_00_B:uint = (COLOR_00 >> 0) & 0xFF;
const COLOR_FF_R:uint = (COLOR_FF >> 16) & 0xFF;
const COLOR_FF_G:uint = (COLOR_FF >> 8) & 0xFF;
const COLOR_FF_B:uint = (COLOR_FF >> 0) & 0xFF;
const Lerp:Function = function(in_Src:uint, in_Dst:uint, in_Ratio:Number):uint{
return (in_Src * (1-in_Ratio)) + (in_Dst * in_Ratio);
};
PALLETE_MAP = new Array(256);
for(var i:int = 0; i < 256; i++){
var ratio:Number = i / (255.0);
ratio = 0.5 - 0.5*Math.cos(Math.PI*ratio);
var r:uint = Lerp(COLOR_00_R, COLOR_FF_R, ratio);
var g:uint = Lerp(COLOR_00_G, COLOR_FF_G, ratio);
var b:uint = Lerp(COLOR_00_B, COLOR_FF_B, ratio);
PALLETE_MAP[i] = (r << 16) | (g << 8) | (b << 0);
}
}
}
//Debug
if(DEBUG)
{
var bmp:Bitmap;
m_BitmapData_View_U = new BitmapData(BMD_W, BMD_W, false, 0x000000);
bmp = new Bitmap(m_BitmapData_View_U);
addChild(bmp);
m_BitmapData_View_V = new BitmapData(BMD_W, BMD_W, false, 0x000000);
bmp = new Bitmap(m_BitmapData_View_V);
bmp.x = BMD_W;
addChild(bmp);
}
//拡散反応用
{
//生成
{
m_BitmapData_Src_U = new BitmapData(BMD_W, BMD_W, false, 0x000000);
m_BitmapData_Src_V = new BitmapData(BMD_W, BMD_W, false, 0x000000);
m_BitmapData_Dst_U = new BitmapData(BMD_W, BMD_W, false, 0x000000);
m_BitmapData_Dst_V = new BitmapData(BMD_W, BMD_W, false, 0x000000);
}
//初期値設定
{
/*
//パーリンノイズ(あまり美しくない)
m_BitmapData_Src_U.perlinNoise(BMD_W, BMD_W, 6, Math.random()*100, false, true, BitmapDataChannel.BLUE);
m_BitmapData_Src_V.perlinNoise(BMD_W, BMD_W, 6, Math.random()*100, false, true, BitmapDataChannel.BLUE);
//*/
/*
//完全ランダム(わりと高速に安定化する)
m_BitmapData_Src_U.noise(Math.random()*100, 0x00,0xFF, BitmapDataChannel.BLUE);
m_BitmapData_Src_V.noise(Math.random()*100, 0x00,0xFF, BitmapDataChannel.BLUE);
//*/
//*
//中央に四角(なんか魔法陣的な感じになる)
m_BitmapData_Src_U.fillRect(new Rectangle(BMD_W*3/8, BMD_W*3/8, BMD_W/4, BMD_W/4), 0x0000FF);
m_BitmapData_Src_V.fillRect(new Rectangle(BMD_W*3/8, BMD_W*3/8, BMD_W/4, BMD_W/4), 0x0000FF);
//*/
}
}
//Update
{
addEventListener(Event.ENTER_FRAME, Update);
}
}
//Update
public function Update(e:Event=null):void{
//var DeltaTime:Number = 1.0 / stage.frameRate;
//拡散反応処理
Update_ReactionDiffusion();
//結果を可視化
Redraw();
}
//Update:拡散反応
public function Update_ReactionDiffusion():void{
//Calc
//拡散
{
//大きくすると最終的な模様も大雑把になる
const POW:Number = 6;//10;
//U
{
const BlurU:Number = Math.pow(1.01, POW);//1.01;
const filter_blur_u:BlurFilter = new BlurFilter(BlurU, BlurU);
m_BitmapData_Dst_U.applyFilter(m_BitmapData_Src_U, BMD_RECT, POS_ZERO, filter_blur_u);
}
//V
{
const BlurV:Number = Math.pow(1.25, POW);//1.25;
const filter_blur_v:BlurFilter = new BlurFilter(BlurV, BlurV);
m_BitmapData_Dst_V.applyFilter(m_BitmapData_Src_V, BMD_RECT, POS_ZERO, filter_blur_v);
}
}
//反応
{
//U
{
//増える量
{
//a*u + b*v + c
const A:Number = 0.08;
const B:Number = -0.072;
const C:Number = 0.04;
const ct_add_u_ac:ColorTransform = new ColorTransform(0,0,A,1, 0,0,C*0xFF,0);
const ct_add_u_b:ColorTransform = new ColorTransform(0,0,Math.abs(B));
AddU.draw(m_BitmapData_Dst_U, null, ct_add_u_ac);
AddU.draw(m_BitmapData_Dst_V, null, ct_add_u_b, (B > 0)? BlendMode.ADD: BlendMode.SUBTRACT);
//制限
const SymUMax:Number = 0.1;
const ThrU:uint = uint(0xFF * SymUMax);
AddU.threshold(AddU, BMD_RECT, POS_ZERO, ">=", ThrU, ThrU, 0x0000FF);
}
//減る量
{
//-d*u
const D:Number = 0.05;
const ct_sub_u:ColorTransform = new ColorTransform(0,0,D);
SubU.draw(m_BitmapData_Dst_U, null, ct_sub_u);
}
//実際の反映はあとで実行する(V側の計算に影響を与えないように)
}
//V
{
//増える量
{
//e*u+f
const E:Number = 0.06;
const F:Number = -0.0015;
const ct_add_v_ef:ColorTransform = new ColorTransform(0,0,E,1, 0,0,F*0xFF,0);
AddV.draw(m_BitmapData_Dst_U, null, ct_add_v_ef);
//制限
const SymVMax:Number = 0.25;
const ThrV:uint = uint(0xFF * SymVMax);
AddV.threshold(AddV, BMD_RECT, POS_ZERO, ">=", ThrV, ThrV, 0x0000FF);
}
//減る量
{
//-g*v
const G:Number = 0.03;
const ct_sub_v:ColorTransform = new ColorTransform(0,0,G);
SubV.draw(m_BitmapData_Dst_V, null, ct_sub_v);
}
}
//反映
{
m_BitmapData_Dst_U.draw(AddU, null, null, BlendMode.ADD);
m_BitmapData_Dst_U.draw(SubU, null, null, BlendMode.SUBTRACT);
m_BitmapData_Dst_V.draw(AddV, null, null, BlendMode.ADD);
m_BitmapData_Dst_V.draw(SubV, null, null, BlendMode.SUBTRACT);
}
}
//For Next
{
m_BitmapData_Src_U.copyPixels(m_BitmapData_Dst_U, BMD_RECT, POS_ZERO);
m_BitmapData_Src_V.copyPixels(m_BitmapData_Dst_V, BMD_RECT, POS_ZERO);
m_BitmapData_Dst_U.fillRect(m_BitmapData_Dst_U.rect, 0x000000);
m_BitmapData_Dst_V.fillRect(m_BitmapData_Dst_V.rect, 0x000000);
}
}
//Redraw
public function Redraw():void{
//可視化
{
//m_BitmapData_Src_Uの可視化(Src側に今回の結果がフィードバックされているものとする)
m_BitmapData_View.paletteMap(m_BitmapData_Src_U, BMD_RECT, POS_ZERO, null, null, PALLETE_MAP);
}
//Debug
if(DEBUG){
m_BitmapData_View_U.copyPixels(m_BitmapData_Src_U, BMD_RECT, POS_ZERO);
m_BitmapData_View_V.copyPixels(m_BitmapData_Src_V, BMD_RECT, POS_ZERO);
}
}
}
}