フラクタルノイズの雲Flash

こんにちは。逆から読んでもきつつきです。


最近、やっとFLASHに目覚め初めています。
そんなわけで今回はActionScript3.0の話題ですが、勉強中の適当なサンプルを掲載しても面白くないので、学生時代に一度書いたことのあるフラクタルノイズの雲をAS3で書いてみました。



読み込むたびに模様が変わります。
以下、サンプルコードです。

    package
    {
        import flash.display.*;
        import flash.events.*;
        import flash.geom.*;
        import flash.utils.Timer;

        [SWF(backgroundColor="#3333cc", frameRate="60",width="128",height="128" )]
        /**
         * ...
         * @author 啄木鳥@cybridge.jp
         */
        public class Main extends Sprite
        {
            public const SIZE:Number = 128;
            public var screen:BitmapData;

            public var CloudData:Array;        // 濃度
            public var CloudDataD:Array;    // 乱数テーブル
           
            public function Main():void
            {
                if (stage) init();
                else addEventListener(Event.ADDED_TO_STAGE, init);
            }
           
            private function init(e:Event = null):void
            {
                removeEventListener(Event.ADDED_TO_STAGE, init);
                // entry point
               
                // 背景色との加算合成
                this.blendMode = BlendMode.ADD;

                // BitmasDataの初期化
                screen = new BitmapData( stage.stageWidth, stage.stageHeight, true, 0xFF000000 );
                addChild( new Bitmap( screen ) );

                // 雲データの初期化
                initCloud();

                // 描画
                renderCloudData();
            }
           
            private function initCloud():void {
               
                // 配列の確保+乱数テーブルの作成
                CloudData = new Array(SIZE + 1);
                CloudDataD = new Array(SIZE + 1);
               
                var i:int;
                var j:int;
                for (i = 0; i < SIZE + 1;++i)
                {
                    CloudData[i] = new Array(SIZE + 1);
                    CloudDataD[i] = new Array(SIZE + 1);
                   
                    for (j = 0; j < SIZE + 1;++j) {
                        CloudDataD[i][j] = (Math.random()*2-1.0);
                    }
                }
               
                // 乱数テーブルから雲データの作成
                updateCloud();
            }
           
            private function updateCloud():void{

                // 初期の4点を求める
               
                CloudData[0][0] = CloudDataD[0][0] * SIZE ;
                CloudData[0][SIZE] = CloudDataD[0][SIZE] * SIZE ;
                CloudData[SIZE][0] = CloudDataD[SIZE][0] * SIZE ;
                CloudData[SIZE][SIZE] = CloudDataD[SIZE][SIZE] * SIZE ;
               
                // 再帰処理で残りの点を求める
                updateCloud_r(SIZE / 2);
            }
           
            private function updateCloud_r(level:int):void {

                // 再帰処理脱出
                if (level == 0)
                {
                    return;
                }
               
                var i:int;
                var j:int;

                // 前に計算した4点の中間点を求める
                for (i = level; i < SIZE; i += level*2 )
                {
                    for (j = level; j < SIZE; j += level*2 ) {
                        CloudData[i][j] = (CloudData[i - level][j - level] + CloudData[i - level][j + level] + CloudData[i + level][j - level] + CloudData[i + level][j + level]) / 4 + (CloudDataD[i][j] * level);
                    }
                }
               
                // 前に計算した2点と↑で計算した2点から中間点を求める
                var count:int;
                var c:Number;

                for (i = level; i < SIZE; i += level * 2 ) {
                    for (j = 0; j < SIZE + 1; j += level * 2 )
                    {
                        count = 0;
                        c = 0;
                        if (checkPoint(i - level, j)) {
                            ++count;
                            c += CloudData[i - level][ j];
                        }

                        if (checkPoint(i + level, j)) {
                            ++count;
                            c += CloudData[i + level][ j];
                        }

                        if (checkPoint(i, j - level)) {
                            ++count;
                            c += CloudData[i][ j - level];
                        }

                        if (checkPoint(i, j + level)) {
                            ++count;
                            c += CloudData[i][ j + level];
                        }
                       
                        CloudData[i][j] = c / count + (CloudDataD[i][j] * level);
                    }
                }
               
                for (i = 0; i < SIZE + 1 ; i += level * 2 )
                    for (j = level; j < SIZE; j += level * 2 ) {
                    {
                        count = 0;
                        c = 0;

                        if (checkPoint(i - level, j)) {
                            ++count;
                            c += CloudData[i - level][ j];
                        }

                        if (checkPoint(i + level, j)) {
                            ++count;
                            c += CloudData[i + level][ j];
                        }

                        if (checkPoint(i, j - level)) {
                            ++count;
                            c += CloudData[i][ j - level];
                        }

                        if (checkPoint(i, j + level)) {
                            ++count;
                            c += CloudData[i][ j + level];
                        }
                       
                        CloudData[i][j] = c / count+ (CloudDataD[i][j]*level);
                    }
                }
               
                // 再帰呼び出し
                updateCloud_r(level / 2);
            }
           
            // 座標が適切かどうか調べる
            private function checkPoint(i:int, j:int):Boolean
            {
                if (0 <= i && i < SIZE + 1 && 0 <= j && j < SIZE + 1) {
                    return true;
                }
               
                return false;
            }
           
            // レンダリング
            private function renderCloudData():void
            {
                var i:int;
                var j:int;
                var c:int;
                var c_max:Number;
                var c_min:Number;
                var d:Number;

                c_max = CloudData[0][0];
                c_min = -CloudData[0][0];

               
                for (i = 0; i < SIZE;++i) {
                    for (j = 0; j < SIZE;++j ) {
                        c_max = Math.max(c_max, CloudData[i][j]);
                        c_min = Math.min(c_min, CloudData[i][j]);
                    }
                }
               
                d = c_max - c_min;

                screen.lock();
               
                for (i = 0; i < SIZE;++i) {
                    for (j = 0; j < SIZE;++j ) {
                        c = 255 * (CloudData[i][j] - c_min) / d;
                        screen.setPixel32(i, j, (0xff000000 | (c<<16) | (c<<8) | c ));
                    }
                }
               
                screen.unlock();
            }
        }
       
    }

初期4点をランダムに求めたあと、その4点の中間点を、4点の濃度値の平均+ノイズで求め、そこからさらに4点を使って別の点を求め、・・・と再帰的に処理を行っていきます。
乱数をテーブル化しているのは次回への布石です。次回は雲を徐々に変化させます。

コメントする


画像の中に見える文字を入力してください。

トラックバック(0)

トラックバックURL

このトラックバックURLを使ってこの記事にトラックバックを送ることができます。

※この記事へのパーマリンク(固定リンク)が内容に含まれていない場合、掲載が保留されることがあります。また記事と直接関係のない内容のトラックバックはお断りする場合があります。

トラックバック一覧(0)

 

このブログ記事を参照しているブログ一覧: フラクタルノイズの雲