Home > 梅原 > 地球儀2

地球儀2

20090629
Category:梅原 /Tags:

地球儀2zソートやライティングに対応してみた。ついでにFlashPlayer10のMatrix3DやVector3Dを使ってみた。
結果、キレイになったけど、重くなった。10FPSくらいしか出ない、、、。残念。

Matrix3DやVector3Dの特性を生かしたもっと上手い作り方があるかもしれないので、今後の研究課題。自分のオリジナル関数に置き換えたくなる誘惑にかられるけど(笑)

その他の部分に関しては、先日の地球儀とほぼ同じ。
http://www.mztm.jp/2009/06/26/地球儀/

▼Wonderfl

▼ActionScript AS3(FP10)

/*

地球儀
zSortやライティングをちゃんとやると、
やっぱ重くなる。

*/
package {
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.geom.Vector3D;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	import flash.geom.PerspectiveProjection;
	import flash.events.Event;
	import net.hires.debug.Stats;
	[SWF(backgroundColor="0x000000")]
	public class Main extends Sprite {
		private var spec_data:BitmapData = new BitmapData(100,50);
		private var _sp:Sprite=new Sprite;
		private var vectors_vec:Vector.<Vector.<Number>>;
		private var polyInt:int;
		private var scale:Number;
        private var loadFiles_array:Array;
		private var color_array:Vector.<int> = new Vector.<int>((100-1)*(50-1));
		private var spec_array:Array = new Array();
		private var _stageWidth:int = stage.stageWidth;
		private var _stageHeight:int = stage.stageHeight;
        private var MultiLoader:MultiLoaderClass = new MultiLoaderClass("http://mztm.heteml.jp/crossdomain.xml");

		private var baseBmpd:BitmapData = new BitmapData(230,465,false,0x33);

		public function Main():void {
			loadFiles_array = MultiLoader.setLoad(["http://mztm.heteml.jp/umhr/3d/earthmap100.png","http://mztm.heteml.jp/umhr/3d/earthbump100.png"],onImgComp);

			var pp:PerspectiveProjection=this.transform.perspectiveProjection;
			pp.projectionCenter=new Point(stage.stageWidth/4,stage.stageHeight/4);
			this.transform.perspectiveProjection=pp;
			_sp.z=_sp.z;
			_sp.x=stage.stageWidth/4;
			_sp.y=stage.stageHeight/4;
			addChild(_sp);
			addChild(new Stats());
		}
		private function onImgComp():void{
			var bmp_data:BitmapData = new BitmapData(100,50)
			bmp_data.draw(loadFiles_array[0]);
			spec_data.draw(loadFiles_array[1]);
			getPixels(bmp_data);
			vectors_vec = toSpherical(100,50);
			scale = 1.1;
			addEventListener(Event.ENTER_FRAME,ENTER_FRAME);
        }

		private function getPixels(_bmpd:BitmapData):void{
			var bmpw:int = _bmpd.width;
			var bmph:int = _bmpd.height;
			for (var h:uint = 0; h < bmph-1; h++) {
				for (var w:uint = 0; w < bmpw-1; w++) {
					color_array[w+(bmpw-1)*h] = _bmpd.getPixel(w,h);
				}
			}
		}
		private function toSpherical(_bmpw:uint,_bmph:uint):Vector.<Vector.<Number>>{
			var _array:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
			var temp_array:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
			for (var h:uint = 0; h < _bmph; h++) {
				for (var w:uint = 0; w < _bmpw; w++) {
					var nnx:Number = Math.PI*(2*(w-(_bmpw-1)/2)/(_bmpw-1));
					var nny:Number = -Math.PI*((h-(_bmph-1)/2)/(_bmph-1));
					var _scale:Number = 1+(spec_data.getPixel(w,h)/0xFFFFFF)/15;
					var nx:Number = Math.cos(nny)*Math.cos(nnx)*_scale;
					var ny:Number = Math.cos(nny)*Math.sin(nnx)*_scale;
					var nz:Number = Math.sin(nny)*_scale;
					nx = Math.abs(nx) < 0.001 ? 0: nx;
					ny = Math.abs(ny) < 0.001 ? 0: ny;
					var _a:Vector.<Number> = new Vector.<Number>(3,true);
					_a = Vector.<Number>([nx,ny,nz]);
					temp_array.push(_a);
				}
			}
			for (h = 0; h < _bmph-1; h++) {
				for (w = 0; w < _bmpw-1; w++) {
					_array.push(temp_array[h*_bmpw+w].concat(temp_array[h*_bmpw+w+1],temp_array[(h+1)*_bmpw+w+1],temp_array[(h+1)*_bmpw+w]));
				}
			}
			return _array;
		}

		private var _num:Number=0;
		private function ENTER_FRAME(e:Event=null):void {
			_num+=0.01;
			_sp.graphics.clear();
			var vv:Vector.<Vector3D>=new Vector.<Vector3D>(3);
			vv[0]=new Vector3D(0,0,0);//平行移動、
			vv[1]=new Vector3D(_num/20+90,_num,0);//回転、
			vv[2]=new Vector3D(180/scale,180/scale,180/scale);//拡大 / 縮小
			var matrix1:Matrix3D=new Matrix3D();
			matrix1.recompose(vv);
			var vectors_vec_length:int = vectors_vec.length;
			var vout_vec:Vector.<Vector.<Number>>=new Vector.<Vector.<Number>>(vectors_vec_length);
			for (var i:int=0; i<vectors_vec_length; i++) {
				vout_vec[i] = new Vector.<Number>(3);
				matrix1.transformVectors(vectors_vec[i],vout_vec[i]);
			}
			render(vout_vec);
		}

		private function render(_pozz:Vector.<Vector.<Number>>):void{
			var _len:int=_pozz.length;
			var _z_vector:Array=new Array();
			for (var i:int=0; i<_len; i++) {
				var i_len:int = _pozz[i].length/3;
				_z_vector[i] = 0;
				for (var j:int=0; j<i_len; j++) {
					_z_vector[i] += _pozz[i][j*3+2];
				}
			}
			_z_vector = _z_vector.sort(Array.NUMERIC|Array.RETURNINDEXEDARRAY|Array.DESCENDING);
			var _mouseX:Number = stage.mouseX-_stageWidth/2;
			var _mouseY:Number = stage.mouseY-_stageHeight/2;
			for (i=0; i<_len; i++) {
				drawLine(_pozz[_z_vector[i]],color_array[_z_vector[i]],_mouseX,_mouseY);
			}
		}
		private function drawLine(poz:Vector.<Number>,_color:int,_mouseX:Number,_mouseY:Number):void{
			//隠面消去
			var _vec:Vector3D = new Vector3D(poz[0]-poz[3],poz[1]-poz[4],poz[2]-poz[5]).crossProduct(new Vector3D(poz[0]-poz[6],poz[1]-poz[7],poz[2]-poz[8]));
			if(_vec.length == 0){
				_vec = new Vector3D(poz[0]-poz[3],poz[1]-poz[4],poz[2]-poz[5]).crossProduct(new Vector3D(poz[0]-poz[9],poz[1]-poz[10],poz[2]-poz[11]));
			}
			if(_vec.z > 0 ){
				return;
			}
			//フラットシェーディング
			_mouseX = Math.abs(_mouseX)>300?300*_mouseX/Math.abs(_mouseX):_mouseX;
			_mouseY = Math.abs(_mouseY)>300?300*_mouseY/Math.abs(_mouseY):_mouseY;
			var _ang:Number = Vector3D.angleBetween(_vec,new Vector3D(_mouseX,_mouseY,-500));
			//_sp.graphics.lineStyle(0,0xFF0000);
			_sp.graphics.beginFill (rgbBrightness(_color,(1-_ang/2)), 1);
			var _len:int=poz.length;
			var ps:Point=_sp.local3DToGlobal(new Vector3D(poz[_len-3],poz[_len-2],poz[_len-1]));
			_sp.graphics.moveTo(ps.x,ps.y);

			for (var i:int=0; i<_len/3; i++) {
				ps=_sp.local3DToGlobal(new Vector3D(poz[i*3],poz[i*3+1],poz[i*3+2]));
				_sp.graphics.lineTo(ps.x,ps.y);
			}
			_sp.graphics.endFill();
		}
		//
		/*
		色の明度を相対的に変える関数。
		rgb値と割合を与えて、結果を返す。
		rgbは、0xffffff段階の値。
		ratioが0の時に0x000000に、1の時にそのまま、2の時には0xffffffになる。
		相対的に、ちょっと暗くしたい時には、ratioを0.8に、
		ちょっと明るくしたい時にはratioを1.2などに設定する。
		*/
		public function rgbBrightness(rgb:int,ratio:Number = 1):int{
			if(ratio < 0 || 2 < ratio){ratio = 1}
			var _r:int = rgb >> 16;//16bit右にずらす。
			var _g:int = rgb >> 8 & 0xff;//8bit右にずらして、下位8bitのみを取り出す。
			var _b:int = rgb & 0xff;//下位8bitのみを取り出す。
			if(ratio <= 1){
				_r *= ratio;
				_g *= ratio;
				_b *= ratio;
			}else{
				_r = (255 - _r)*(ratio-1)+_r;
				_g = (255 - _g)*(ratio-1)+_g;
				_b = (255 - _b)*(ratio-1)+_b;
			}
			return _r<<16 | _g<<8 | _b;
		}
	}
}

class MultiLoaderClass{
    import flash.system.Security;
    import flash.net.URLRequest;
    import flash.net.URLLoader;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.display.Loader;
    //import flash.display.LoaderInfo;

    private var onComplete:Function = function():void{};
    private var loadNum:int;
    private var loadCompNum:int;

    public function MultiLoaderClass(_str:String = null){
        if(_str != null){
            Security.loadPolicyFile(_str);
        }
    }

    public function setLoad(__item_array:Array,_onComp:Function = null):Array{
        loadCompNum = loadNum = 0;
        onComplete = _onComp;
        var _array:Array = new Array();
        var _length:int = __item_array.length;
        for (var i:int = 0; i < _length; i++) {
            if(__item_array[i] == null){continue};
            var _extension:String = __item_array[i].substr(-4,4).toLowerCase();//拡張子を取り出す。
            if(_extension == ".xml"){
                loadNum ++;
                _array[i] = fnURLLoader(__item_array[i]);
            }else if(_extension == ".jpg" || _extension == ".png"){
                loadNum ++;
                _array[i] = fnLoader(__item_array[i]);
            }else{
                //_array[i] = null;
            }
        }
        return _array;
    }
    private function fnURLLoader(__url:String):URLLoader{
        var _loader : URLLoader = new URLLoader();
        _loader.load(new URLRequest(__url));
        _loader.addEventListener (Event.COMPLETE,completeHandler);
        _loader.addEventListener (IOErrorEvent.IO_ERROR, ioErrorHandler);
        return _loader;
    }

    private function fnLoader(__url:String):Loader{
        var _loader:Loader = new Loader();
        _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
        _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
        _loader.load(new URLRequest(__url));
        //_loader.name = __url;
        return _loader;
    }

    private function completeHandler(event:Event = null):void {
        loadCompNum ++;
        if(loadCompNum == loadNum){
            onComplete();
        }
        //var loaderInfo:LoaderInfo=event.currentTarget as LoaderInfo;
        //var loader:Loader=loaderInfo.loader;
        //addChild(loader);
    }

    private function ioErrorHandler(event:IOErrorEvent):void {
        //event.text = "Error #2035: URL が見つかりません。 URL: file:///~~~~~";
        //event.text = "Error #2036: 読み込みが未完了です。 URL: http://~~~~~";
        //から、URLのみを取り出す。
        //trace(String(event.text).substr(String(event.text).indexOf(" URL: ")+6),"*****");
        completeHandler();
    }
}

関連記事:

  1. No comments yet.
Comments are closed.