スポンサーサイト

-------- | --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

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

2007-11-30 | 20:11

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

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;
        }
}
スポンサーサイト

Comment

Post a comment

Secret

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。