miscellaneous

[ActionScript 3.0] 地形データの自動生成 (PaperVision3D)

中点変位法という方法で領域を次々に分割していき、地形データを自動生成するデモです。
下のウィンドウをクリックするごとに領域が分割されて地形ができていきます。

package {
        import flash.display.*;
        import flash.events.*;
        import flash.text.*;
        import flash.filters.*;
        import flash.geom.*;
        import flash.utils.*;
        
        import org.papervision3d.core.* ;
        import org.papervision3d.core.geom.*;
        import org.papervision3d.scenes.*;
        import org.papervision3d.objects.*;
        import org.papervision3d.cameras.*;
        import org.papervision3d.materials.*;
        
        [SWF(width="700", height="400", backgroundColor="#0")]
        public class Fractal extends Sprite{
                
                private var canvas : Sprite;
                private var scene     : MovieScene3D;
                private var camera    : Camera3D;
                
                private var linesX:Array= new Array();
                private var linesZ:Array= new Array();
                
                private var landForm:LandForm;
                
                private var WIDTH:int = 700;
                private var HEIGHT:int = 400;
                
                public function Fractal():void
                {
                        stage.frameRate = 20;
                        stage.quality   = "MEDIUM";
                        stage.scaleMode = "noScale";
                        stage.align = StageAlign.TOP_LEFT;
                        
                        canvas = new Sprite();
                        canvas.x = WIDTH/2;
                        canvas.y = HEIGHT/5*4;
                        stage.addChild( canvas );
                        
                        scene = new MovieScene3D( canvas );
                        
                        var range:int = 128;
                        
                        var x:int,y:int,z:int;
                        
                        scene.addChild ( new Line3D([ new Vertex3D(-range,0,0), new Vertex3D(range,0,0)],
                                                                                             0xff0000, 0.5, 0.2));
                        scene.addChild( new Line3D([ new Vertex3D(0,-range,0), new Vertex3D(0,range,0)],
                                                                                            0xff00, 0.5, 0.2));
                        scene.addChild( new Line3D([ new Vertex3D(0,0,-range), new Vertex3D(0,0,range)],
                                                                                            0xff, 0.5, 0.2));
                        
                        
                        camera = new Camera3D();
                        camera.x = 100;
                        camera.y = 100;
                        camera.z = -400;
                        camera.focus = 100;
                        camera.zoom = 40;
                        
                        scene.renderCamera ( camera );
                        
                        landForm = new LandForm(range);
                        
                        stage.addEventListener(MouseEvent.CLICK, function(e:*):void{
                                landForm.split();
                                render();
                        });
                        stage.addEventListener(MouseEvent.MOUSE_MOVE, function(e:*):void{
                                var rad:Number = (WIDTH/2- stage.mouseX)/WIDTH*(Math.PI)*2;
                                camera.x = Math.cos(rad)*100 - Math.sin(rad)*(-HEIGHT);
                                camera.z = Math.sin(rad)*100 + Math.cos(rad)*(-HEIGHT);
                                
                                camera.zoom = Math.max((HEIGHT-stage.mouseY),30)/10 +10;
                                //camera.hover(0,stage.mouseX, stage.mouseY);
                                scene.renderCamera( camera );
                        });
                }
                
                
                private function rotateCamera(rad:Number):void{
                        var x:Number = camera.x;
                        var y:Number = camera.y;
                        var z:Number = camera.z;
                        camera.x = Math.cos(rad)*x - Math.sin(rad)*z;
                        //camera.y = Math.cos(rad)*x - Math.sin (rad)*z;
                        camera.z = Math.sin(rad)*x + Math.cos(rad)*z;
                }
                
                private function render():void
                {
                        for(var i:int = 0 ; i < linesX.length ; i++)
                        scene.removeChild(linesX[i]);
                        for(i = 0 ; i < linesZ.length ; i++)
                        scene.removeChild(linesZ[i]);
                        
                        for(var x:int = 0 ; x < landForm.length ; x++){
                                var vertexes:Array = [];
                                for(var z:int = 0 ; z < landForm.length ; z++){
                                        vertexes.push(new Vertex3D(landForm.scale*(x - ( landForm.length - 1)/2),
                                                                                            landForm.value(x,z),
                                                                                                           landForm.scale*(z - (landForm.length - 1)/2)));
                                }
                                var line:Line3D = new Line3D(vertexes, 0xffffff, 0.3, 0.05);
                                linesZ.push(line);
                                scene.addChild(line);
                        }
                        for(z = 0 ; z < landForm.length ; z++){
                                vertexes= [];
                                for(x = 0 ; x < landForm.length ; x++){
                                        vertexes.push(new Vertex3D(landForm.scale*(x - (landForm.length - 1)/2),
                                                                                            landForm.value(x,z),
                                                                                                           landForm.scale*(z - (landForm.length - 1)/2)));
                                }
                                line = new Line3D(vertexes, 0xffffff, 0.3, 0.05);
                                linesX.push(line);
                                scene.addChild(line);
                        }
                        
                        trace(landForm.value(landForm.length-1, landForm.length-1));
                        
                        scene.renderCamera(camera);
                }
        }
}
internal class LandForm{
        private var buffer:Array = new Array();
        
        private var range:int ;
        private var splitCnt:int = 0;
        private var base:Number = 10;
        
        // range は2の乗数であること
        public function LandForm(range:int){
                this.range = range;
                clear();
        }
        
        public function clear():void{
                buffer = [];
                // 変位が格納される2次元配列(w*h)
                for(var j:int = 0 ; j < range+1; j++){
                        var aa:Array = new Array();
                        for(var k:int = 0 ; k < range+1; k++)
                        aa.push(0);
                        buffer.push(aa);
                }
                buffer[0][0] = base*Math.random();
                buffer[range][0] = base*2*Math.random();
                buffer[0][range] = base*3*Math.random();
                buffer[range][range] = base*4*Math.random();
                //trace(buffer[128][128]);
        }
        
        public function split():void{
                if(Math.pow(2,splitCnt) >= range){
                        splitCnt=0;
                        clear();
                }
                splitCnt++;
                
                for(var x:int = 1 ; x < length ; x+=2){
                        for(var y:int = 1 ; y < length ; y+=2){
                                splitMidPoint(x, y);
                        }
                }
        }
        
        private function splitMidPoint(x:int, y:int):void{
                
                midPoint(x,y,true);
                midPoint(x-1,y);
                midPoint(x+1,y);
                midPoint(x,y-1);
                midPoint(x,y+1);
                
        }
        private function midPoint(x:int, y:int, squere:Boolean=false):void{
                //trace(x.toString() + ":" + y.toString());
                
                var sum:Array = [];
                if(squere){
                        if(x > 0 && y > 0 && value(x-1,y-1) != 0 )
                        sum.push(value(x-1, y-1));
                        if(x > 0 && y < length-1 && value(x-1,y+1) != 0)
                        sum.push(value(x-1, y+1));
                        if(x < length - 1 && y > 0 && value(x+1,y-1) != 0)
                        sum.push(value(x+1, y-1));
                        if(x < length - 1 && y < length - 1 && value(x+1,y+1) != 0)
                        sum.push(value(x+1, y+1));
                }else{ // diamonds
                        if(y > 0 && value(x,y-1) != 0)
                        sum.push(value(x, y-1));
                        if(x > 0 && value(x-1,y) != 0)
                        sum.push(value(x-1, y));
                        if(y < length - 1 && value(x,y+1) != 0)
                        sum.push(value(x, y+1));
                        if(x < length - 1 && value(x+1,y) != 0)
                        sum.push(value(x+1, y));
                }
                
                var sumOfHeight:Number = 0;
                for each(var v:Number in sum)
                sumOfHeight += v;
                
                var avg:Number = sumOfHeight / sum.length ;
                setValue(x,y, newHeight(avg));
                
        }
        
        private function newHeight(avg:Number):Number{
                //    return avg + (Math.random()*(Math.pow(2, - 0.3*splitCnt)));
                return avg*(1 + (Math.random ()*2 - 1) * scale * 0.019);
        }
        
        public function get length():int{
                return Math.pow(2, splitCnt) + 1;
        }
        
        public function get scale():int{
                return range / Math.pow(2,splitCnt);
        }
        
        public function value(x:int, z:int):Number{
                return buffer[x*scale][z*scale];
        }
        
        private function setValue(x:int, z:int, value:Number):void{
                buffer[x*scale][z*scale] = value;
        }
}



  1. 2007/11/30(金) 20:11:06|
  2. ActionScript 3.0
  3. | トラックバック:0
  4. | コメント:0
<<残像付き光 | ホーム | 鏡面反射光+拡散反射光+影>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバックURLはこちら
http://yamasv.blog92.fc2.com/tb.php/95-d69e35b5
この記事にトラックバックする(FC2ブログユーザー)
Google

プロフィール

Author:yamasv@gmail.com
コメント、トラックバック、リンクはお気軽に

最近の記事

ブログ検索

カテゴリー

-->

カレンダー

07 | 2008/08 | 09
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 - - - - - -

過去ログ

最近のコメント

最近のトラックバック

RSSフィード

リンク

このブログをリンクに追加する

全ての記事を表示する

全ての記事を表示する



あわせて読みたい