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

forked from: PerlinNoise生成

ブラウンノイズからPerlinNoiseを生成
2次元のブラウンノイズってどうやって作ればいいんだろう・・・・?
Get Adobe Flash player
by Nao_u 23 Apr 2009
// forked from Nao_u's PerlinNoise生成
// 
// ブラウンノイズからPerlinNoiseを生成
// 
//    2次元のブラウンノイズってどうやって作ればいいんだろう・・・・?
//
package {     
    import flash.display.Sprite;     
    import flash.events.*;     
    [SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="30")]      
        
    public class FlashTest extends Sprite {     
        public function FlashTest() {     
            Main = this;     
            initialize();     
            stage.addEventListener(Event.ENTER_FRAME,update);      
        }     
    }     
}             
    
import flash.display.Bitmap; 
import flash.display.BitmapData; 
import flash.display.Sprite;      
import flash.events.*
import flash.text.TextField;     
import flash.geom.*;
import flash.utils.getTimer;
var Main:Sprite;     
var SCREEN_W:Number = 465;
var SCREEN_H:Number = 465;
var Text:TextField    
var View: Bitmap; 
var BmpData: BitmapData; 

var BITMAP_W:int = SCREEN_W/2;
var BITMAP_H:int = SCREEN_H/2;

function initialize():void{     
    BmpData = new BitmapData(BITMAP_W, BITMAP_H, false, 0xffffff); 
    View = new Bitmap(BmpData); 
    View.scaleX = 2.0;
    View.scaleY = 2.0;
    Main.addChild(View);      

    Text = new TextField();     
    Text.text = "PerlinNoise生成中...";   
    Text.autoSize = "left";
    Main.addChild(Text);      

    makeRndTbl(); 
    makeBrownRndTbl(); 
}

var Cnt:int;
function update(e :Event):void{     
    Cnt++;
    if( Cnt == 2 ){
        var time:int = getTimer(); 
        var cont:Number = 64;
        var mul:Number = 128 + cont;
        BmpData.lock(); 
        for( var x:int=0; x<BITMAP_W; x++ ){ 
            for( var y:int=0; y<BITMAP_H; y++ ){ 
//                var col:int = PerlinNoise( x, y, 32.0, 0.4, 4 ) * mul;
                var col:int = PerlinNoise( x, y, 32.0, 0.75, 5 ) * mul;
                col = col + 128;
                col = col + (col<<8) + (col<<16);
                BmpData.setPixel(x, y, col); 
            }
        } 
        BmpData.unlock(); 

        var endTime:int = getTimer() - time;
        Text.text = "生成時間:" + endTime + "[ms]";   
    }
}  


// PerlinNoiseを生成
function PerlinNoise( x:Number, y:Number, frequency:Number, presistence:Number, octave:int ):Number{
    var total:Number = 0;
    var amplitude:Number = presistence;
    
    for( var i:int=0; i<octave; i++ ){
        total += makeNoise( x+7*i, y+3*i, frequency, amplitude );
        amplitude *= presistence;
        frequency *= 0.5;
    }

    if( total < -1.0 ) total = -1.0;
    if( total >  1.0 ) total =  1.0;
    return total;
}

// 周波数に対応したノイズを生成
function makeNoise( x:Number, y:Number, frequency:Number, amplitude:Number ):Number{
    return (rndSmooth(x/frequency,y/frequency) * amplitude);
}

// 入力値( x, y ) に対応した、滑らかな擬似乱数を生成 (補間の結果-1.0を下回ったり、1.0を超えることがある)
function rndSmooth( x:Number, y:Number ):Number{
    var tx:Number = (x - Math.floor(x));
    var txInv:Number = 1.0 - tx;
    var ty:Number = (y - Math.floor(y));
    var tyInv:Number = 1.0 - ty;
    var ix:int = x;
    var iy:int = y;

// 修正:09/04/18 CatmullRom補間をcos補間に変更 3437[ms] -> 1656[ms]
/*
    // CatmullRom補間
    var x0:Number = catmullRom( rnd(ix-1,iy-1), rnd(ix,iy-1), rnd(ix+1,iy-1), rnd(ix+2,iy-1), tx );
    var x1:Number = catmullRom( rnd(ix-1,iy  ), rnd(ix,iy  ), rnd(ix+1,iy  ), rnd(ix+2,iy  ), tx );
    var x2:Number = catmullRom( rnd(ix-1,iy+1), rnd(ix,iy+1), rnd(ix+1,iy+1), rnd(ix+2,iy+1), tx );
    var x3:Number = catmullRom( rnd(ix-1,iy+2), rnd(ix,iy+2), rnd(ix+1,iy+2), rnd(ix+2,iy+2), tx );
    return catmullRom( x0, x1, x2, x3, ty );
*/
    // cos補間
    var x0:Number = interpolate( rndB(ix, iy),   rndB(ix+1, iy),   tx );
    var x1:Number = interpolate( rndB(ix, iy+1), rndB(ix+1, iy+1), tx );
    return interpolate( x0, x1, ty );

}

// a から b をcosでなめらかに補間
function interpolate( a:Number, b:Number, t:Number ):Number{
    var ft:Number = t * Math.PI;
    var f:Number = (1.0 - Math.cos( ft )) * 0.5;
    return a * (1.0 - f) + b * f;
}

// x1 ~ x2 までの範囲をパラメータ t で catmullRom補間
function catmullRom( x0:Number, x1:Number, x2:Number, x3:Number, t:Number ):Number{ 
    var v0:Number = (x2 - x0) / 2.0;
    var v1:Number = (x3 - x1) / 2.0;
    var t2:Number = t * t;
    var t3:Number = t2 * t;
    return ( 2.0 * x1 - 2.0 * x2 + v0 + v1 ) * t3 + ( -3.0 * x1 + 3.0 * x2 - 2.0 * v0 - v1 ) * t2 + v0 * t + x1;
}

// 入力値( x, y ) に対応した、-1.0 ~ 1.0 の擬似乱数を生成
function rnd( x:int, y:int ):Number{
    x += y * 465 + 789221;    // 465=2次元での横幅に対応
    x = (x>>10) ^ x;
    var ret:int = (( (x * (x * x * 15731 + 789221) + 1376312589) ) / 1000000);
    
    return ((((ret & 0xff) + ((ret & 0xff00)>>8)+ ((ret & 0xff0000)>>16))&0x1ff) / 256) - 1.0;
}


// 256*256のランダムテーブルを生成 
var RNDTBL_SIZE:int = 256; 
var RndTbl:Vector.<Number> = new Vector.<Number>; 
function makeRndTbl():void{ 
    for( var y:int=0; y<RNDTBL_SIZE; y++ ){ 
        for( var x:int=0; x<RNDTBL_SIZE; x++ ){ 
            RndTbl[x + y*RNDTBL_SIZE] = rnd(x,y); 
        } 
    } 
} 

var BrownMul:Number = 0.09;

// ブラウンノイズのランダムテーブルを生成
var BrownRndTbl:Vector.<Number> = new Vector.<Number>; 
function makeBrownRndTbl():void{ 
    var x:int, y:int;
    for( y=0; y<RNDTBL_SIZE; y++ ){ 
        for( x=0; x<RNDTBL_SIZE; x++ ){ 
            BrownRndTbl[x + y*RNDTBL_SIZE] = 0; 
        } 
    } 

    // まず一列をランダムで埋める
    x=0; y=0;
    BrownRndTbl[x + y*RNDTBL_SIZE] = 0.0;
    // 上端一列のブラウンノイズを生成
    for( x=1; x<RNDTBL_SIZE; x++ ){ 
        BrownRndTbl[x + y*RNDTBL_SIZE] = BrownRndTbl[ x-1 + y*RNDTBL_SIZE] + rnd(x,y) * BrownMul - 0.0180;
    }
    // 左端一列のブラウンノイズを生成
    for( y=1; y<RNDTBL_SIZE; y++ ){ 
        BrownRndTbl[x + y*RNDTBL_SIZE] = BrownRndTbl[ x + (y-1)*RNDTBL_SIZE] + rnd(x*13,y*17) * BrownMul - 0.018;
    }

    // 左上から順に足してみる。これだと右下に向かって指向性ができてしまう・・。
    for( x=1; x<RNDTBL_SIZE; x++ ){ 
        for( y=1; y<RNDTBL_SIZE; y++ ){ 
            BrownRndTbl[x + y*RNDTBL_SIZE] = 
                0.5 * BrownRndTbl[x-1 + y*RNDTBL_SIZE] + 
                0.5 * BrownRndTbl[x + (y-1)*RNDTBL_SIZE] +
                rnd(x,y) * BrownMul - 0.010;
        } 
    } 
} 


// 入力値( x, y ) に対応した、-1.0 ~ 1.0 のブラウンノイズを生成
function rndB( x:int, y:int ):Number{
    x &= 0xff;
    y &= 0xff;
    return BrownRndTbl[x + y*RNDTBL_SIZE];
}