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

Saturn 3D, 토성, 고리 중첩 해결못한 것

토성 예제.
@author Yongho, Ji
@since 2009.07.06
@see http://help.adobe.com/ko_KR/ActionScript/3.0_ProgrammingAS3/WSF24A5A75-38D6-4a44-BDC6-927A2B123E90.html
Get Adobe Flash player
by jidolstar 07 Jul 2009
/**
 * Copyright jidolstar ( http://wonderfl.net/user/jidolstar )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/cL1u
 */

package
{
	import flash.display.BitmapData;
	import flash.display.GraphicsTrianglePath;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Matrix3D;
	import flash.geom.PerspectiveProjection;
	import flash.geom.Utils3D;
	import flash.geom.Vector3D;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.ui.Keyboard;
	import flash.utils.getTimer;

    [SWF(width=400, height=400, frameRate=32, backgroundColor=0x000000)]
	
	/**
	 * 토성 예제.
	 * @author Yongho, Ji
	 * @since 2009.07.06
	 * @see http://help.adobe.com/ko_KR/ActionScript/3.0_ProgrammingAS3/WSF24A5A75-38D6-4a44-BDC6-927A2B123E90.html
	 */ 	
	public class Saturn3D extends Sprite
	{
		// 투영된 토성 표면 Vertex 정보 
		private var saturnFaceProjected:Vector.<Number> = new Vector.<Number>(0, false);
		
		// 투영된 토성 링부분 Vertex 정보 
		private var saturnRingProjected:Vector.<Number> = new Vector.<Number>(0, false);
		
		// 투영
		private var projection:PerspectiveProjection = new PerspectiveProjection();
		
		// World 변환행렬
		private var world:Matrix3D = new Matrix3D;
		
		// View Port (3D 렌더링 대상)
		private var viewport:Shape = new Shape();
		
		// 토성 표면 Mesh 데이타 
		private var saturnFaceMesh:GraphicsTrianglePath;

		// 토성 고리 Mesh 데이타 
		private var saturnRingMesh:GraphicsTrianglePath;
		
		// 토성 표면 텍스쳐 
		private var saturnFaceTexture:BitmapData;
		
		// 토성 고리 텍스쳐 
		private var saturnRingTexture:BitmapData;

		
		private var texture:BitmapData;

		// Viewport의 Z축 위치 
		private var viewPortZAxis:Number = 200;
		
		// triangle을 보여줄지 여부  
		private var visibleTriangle:Boolean = true;		
		
		/**
		 * 생성자 
		 */ 
		public function Saturn3D()
		{
			super();
			
                            //Textures 
			saturnFaceTexture = new BitmapData( 400, 200, false );
			saturnRingTexture = new BitmapData( 60, 30, false );
			saturnFaceTexture.perlinNoise(64, 64, 3, 0, true, true, 7, true);
			saturnRingTexture.perlinNoise(64, 64, 3, 0, true, true, 7, true);

			
			//viewport를 화면의 중심으로 
			viewport.x = stage.stageWidth/2;
			viewport.y = stage.stageHeight/2;
			addChild(viewport);
			
			//projection의 fieldOfView를  60으로 지정 
			projection.fieldOfView = 60;
			
			//Mesh 데이타 
			saturnFaceMesh = createSphereMesh( 50, 32, 32 );
			saturnRingMesh = createRingMesh( 70, 20, 50 );
			
			
			//이벤트 처리 							
			stage.addEventListener( Event.RESIZE, onResize );
			stage.addEventListener( Event.ENTER_FRAME, onEnterFrame );
			
			stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseEvent );			
			stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyEvent );
			
			var textField:TextField = new TextField();
			textField.multiline = true;
			textField.textColor = 0xffffff;
			textField.htmlText = "Show/Hide Triangles : Space Key<br>Rotation : Mouse<br>Zoom In/Out : Left/Right Key<br>Change the field of view : Up/Down Key";
			textField.autoSize = TextFieldAutoSize.LEFT;
			addChild( textField ); 			
		}
		
		/**
		 * 사이즈 변경시 처리  
		 */ 
		private function onResize( event:Event ):void
		{
			//viewport는 항상 화면의 중심에 위치하도록 처리 
			viewport.x = stage.stageWidth/2;
			viewport.y = stage.stageHeight/2;	
		}
		
		private var xRotation:Number = -73;
		private var yRotation:Number = 68;
		private var prevX:Number;
		private var prevY:Number;

		/**
		 * 마우스 이벤트 - x,y축 회전
		 */ 
		private function onMouseEvent( event:MouseEvent ):void
		{
			switch( event.type )
			{
				case MouseEvent.MOUSE_DOWN:
					stage.addEventListener( MouseEvent.MOUSE_MOVE, onMouseEvent );
					stage.addEventListener( MouseEvent.MOUSE_UP, onMouseEvent );
					prevX = mouseX;
					prevY = mouseY;
					break;
				case MouseEvent.MOUSE_MOVE:
					if( event.buttonDown == false )
					{
						stage.removeEventListener( MouseEvent.MOUSE_MOVE, onMouseEvent );
						stage.removeEventListener( MouseEvent.MOUSE_UP, onMouseEvent );
						break;
					}
					var dx:Number = mouseX - prevX;
					var dy:Number = mouseY - prevY;
					yRotation += dx;
					xRotation += dy;
					//trace( xRotation, yRotation );
					prevX = mouseX;
					prevY = mouseY;
					break;
				case MouseEvent.MOUSE_UP:
					stage.removeEventListener( MouseEvent.MOUSE_MOVE, onMouseEvent );
					stage.removeEventListener( MouseEvent.MOUSE_UP, onMouseEvent );
					break;
			}	
		}
		
		/**
		 * 키보드 이벤트 - 확대/축소/삼각형 보이기,안보이기/Field Of View 조정 
		 */		
		private function onKeyEvent( event:KeyboardEvent ):void
		{
			trace( event.charCode );
			
			switch( event.keyCode )
			{
				//확대
				case Keyboard.RIGHT:
					viewPortZAxis += 10;
					break;
				//축소
				case Keyboard.LEFT:
					viewPortZAxis -= 10;
					break;
				//삼각형 보이기/안보기 
				case Keyboard.SPACE:
					visibleTriangle = !visibleTriangle
					break;
				//Field Of View 증가
				case Keyboard.UP:
					if( projection.fieldOfView < 179 )
					{ 
						projection.fieldOfView++;
					}				
					break; 
				//Field Of View 감소 
				case Keyboard.DOWN:
					if( projection.fieldOfView > 1 )
					{
						projection.fieldOfView--;
					}				
					break; 
				
			}
		}
		
		/**
		 * 프레임 마다 처리. 
		 */ 
		private function onEnterFrame( event:Event ):void
		{
			world.identity(); //단위행렬로 전환 
			world.appendRotation( getTimer() * 0.027, Vector3D.Z_AXIS );
			world.appendRotation( xRotation, Vector3D.X_AXIS );
			world.appendRotation( yRotation, Vector3D.Y_AXIS );
			world.appendTranslation(0, 0, viewPortZAxis); //이동 
			world.append(projection.toMatrix3D()); //투영 변환 적용 
			
			// mesh 데이터를  투영하여  projected 생성 
			// uvtData도 갱신된다. 갱신되는 데이터는 T값이다. 
			Utils3D.projectVectors( world, saturnFaceMesh.vertices, saturnFaceProjected, saturnFaceMesh.uvtData );
			Utils3D.projectVectors( world, saturnRingMesh.vertices, saturnRingProjected, saturnRingMesh.uvtData );	
			
			viewport.graphics.clear();

			// Triangle 라인을 그림 
			if( visibleTriangle )
			{
				viewport.graphics.lineStyle( 1, 0xff0000, 0.1 );
			}
			
			//Texture 입힌다.
			viewport.graphics.beginBitmapFill( saturnFaceTexture, null, false, true );
			viewport.graphics.drawTriangles( saturnFaceProjected, getSortedIndices(saturnFaceMesh), saturnFaceMesh.uvtData, saturnFaceMesh.culling );            	

			viewport.graphics.beginBitmapFill( saturnRingTexture, null, false, true );
			viewport.graphics.drawTriangles( saturnRingProjected, getSortedIndices(saturnRingMesh), saturnRingMesh.uvtData, saturnRingMesh.culling );            	
		
		}		
	}
}


import flash.display.GraphicsTrianglePath;
import flash.display.TriangleCulling;


/**
 * GraphicsTrianglePath를 기반으로, Z축으로 sort된 인덱스를 돌려준다.
 * 이 작업을 해주어야 z축 깊이에 따라 Triangle이 제대로 그려진다. 
 * @param mesh 정보 
 * @return sort된 index 데이터 
 */
function getSortedIndices( mesh:GraphicsTrianglePath ):Vector.<int> 
{
    var triangles:Array = [];
    var length:uint = mesh.indices.length;
    
    //z축 sort를 위한 기반 제작 
    for ( var i:uint=0; i < length; i += 3 ) 
    {
        var i1:uint = mesh.indices[ i+0 ];
        var i2:uint = mesh.indices[ i+1 ];
        var i3:uint = mesh.indices[ i+2 ];
        var z:Number = Math.min( mesh.uvtData[i1 * 3 + 2], mesh.uvtData[i2 * 3 + 2], mesh.uvtData[i3 * 3 + 2] );
        if (z > 0) 
        { 
        	triangles.push({i1:i1, i2:i2, i3:i3, z:z}); 
        }
    }
    
    //z축으로 sort
    triangles = triangles.sortOn("z", Array.NUMERIC);
    
    //sort된 값을 이용해 Vector값 만듬 
    var sortedIndices:Vector.<int> = new Vector.<int>(0, false);
    for each (var triangle:Object in triangles) 
    {
        sortedIndices.push(triangle.i1, triangle.i2, triangle.i3);
    }
    return sortedIndices;
}

/**
 * 구 Mesh 데이터 작성 
 * @param radius 구의 반지름  
 * @param hDiv 수평 방향의 조각 수 
 * @param vDiv 높이 방향의 조각수 
 * @return mesh 데이터 
 */
function createSphereMesh( radius:Number, hDiv:uint, vDiv:uint ):GraphicsTrianglePath
{
	var vertices:Vector.<Number> = new Vector.<Number>( 0, false );
	var indices:Vector.<int> = new Vector.<int>( 0, false );
	var uvtData:Vector.<Number> = new Vector.<Number>( 0, false );
	var mesh:GraphicsTrianglePath = new GraphicsTrianglePath( vertices, indices, uvtData, TriangleCulling.POSITIVE );
	
	for( var i:uint = 0; i <= hDiv; i++ )
	{
		var s1:Number = Math.PI * 2 * i / hDiv;
		for( var j:uint = 0; j <= vDiv; j++ )
		{
			var s2:Number = Math.PI * j / vDiv + Math.PI / 2;
			var cos1:Number = Math.cos( s1 );
			var sin1:Number = Math.sin( s1 );
			var cos2:Number = Math.cos( s2 );
			var sin2:Number = Math.sin( s2 ); 
			var x:Number = radius * cos2 * cos1;
			var y:Number = radius * cos2 * sin1;
			var z:Number = radius * sin2;  			
			mesh.vertices.push( x, y, z );	 
			mesh.uvtData.push( i / hDiv, j / vDiv, 1 );
			if( j < vDiv && i < hDiv )
			{
                var a:uint =  i      * (vDiv + 1) + j;
                var b:uint = (i + 1) * (vDiv + 1) + j;
                mesh.indices.push(a, a + 1, b, b + 1, b, a + 1); 
			} 
		}
	}	
	
    return mesh;
}

/**
 * 고리 Mesh 데이터 작성 
 * @param radius 고리 안쪽 반지름  
 * @param thickness 고리 두께
 * @param div 고리 조각수 
 * @return mesh 데이터 
 */
function createRingMesh( radius:Number, thickness:Number, div:uint ):GraphicsTrianglePath
{
	var vertices:Vector.<Number> = new Vector.<Number>( 0, false );
	var indices:Vector.<int> = new Vector.<int>( 0, false );
	var uvtData:Vector.<Number> = new Vector.<Number>( 0, false );
	var mesh:GraphicsTrianglePath = new GraphicsTrianglePath( vertices, indices, uvtData, TriangleCulling.NONE );

	var s:Number = 0;
	var x1:Number = radius;
	var x2:Number = radius + thickness;
	var y1:Number = 0;
	var y2:Number = 0;
	var z:Number = 0;  		
	var cos:Number;
	var sin:Number;	
	var n:Number = 0;
	
	for( var i:uint = 0; i < div; i++ )
	{
		//Vertices
		mesh.vertices.push( 
			x1, y1, z, 
			x2, y2, z 
		);
		s = Math.PI * 2 * (i + 1) / div;
		cos = Math.cos( s );
		sin = Math.sin( s );
		x1 = radius * cos;
		x2 = (radius + thickness) * cos;
		y1 = radius * sin;
		y2 = (radius + thickness) * sin;
		mesh.vertices.push( 
			x1, y1, z, 
			x2, y2, z 
		);

		//UVT
		mesh.uvtData.push( 
			0,1,1, 
			1,1,1, 
			0,0,1, 
			1,0,1 
		);
		
		//Indices
		n = i * 4;
		mesh.indices.push( n, n+1, n+2, n+2, n+1, n+3 ); 			
	}	
	
    return mesh;
}