package { import flash.display.Sprite; import flash.events.Event; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.TriangleCulling; import flash.geom.PerspectiveProjection; import flash.geom.Utils3D; import flash.geom.Vector3D; import flash.geom.Matrix3D; import flash.display.StageAlign; import flash.events.MouseEvent; import flash.display.StageScaleMode; [SWF(backgroundColor="0x000000", width="800", height="600", frameRate="30")] public class Moon extends Sprite { [Embed(source="assets/moon-surface1k.jpg")] public var MoonMap:Class; private var texture:BitmapData = new MoonMap().bitmapData; private var vertices:Vector.; private var indices:Vector.; private var uvtData:Vector.; private var perspective: PerspectiveProjection; private var projectionMatrix : Matrix3D; private var projectedVerts:Vector.; private var focalLength:Number = 50; private var container:Sprite; private var targetPoint:Sprite; private var targetPointRadius:Number = 250; private var targetPointXR:Number = 0; private var oldTargetPointXR:Number = 0; private var targetPointYR:Number = 0; private var oldTargetPointYR:Number = 0; private var targetContainer:Sprite; //x,yz rotation private var rx:Number = 0; private var ry:Number = 0; private var rz:Number = 0; private var dragStartX:Number; private var dragStartY:Number; public function Moon() { init(); } private function init():void { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; vertices = new Vector.(); indices = new Vector.(); uvtData = new Vector.(); //set up perspective perspective = new PerspectiveProjection(); perspective.fieldOfView = 50; //3D transformation matrix - used to rotate object projectionMatrix = perspective.toMatrix3D(); projectedVerts = new Vector.(); //container to hold scene container = new Sprite(); container.x = stage.stageWidth/2; container.y = stage.stageHeight/2; addChild(container); createSphere(200, 10, 10); addEventListener(Event.ENTER_FRAME, onEnterFrame); addTarget(); addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); } private function onMouseDown(event:MouseEvent):void { oldTargetPointXR = targetPointXR; dragStartX = container.mouseX; dragStartY = container.mouseY; addEventListener(MouseEvent.MOUSE_MOVE, onDrag); addEventListener(MouseEvent.MOUSE_UP, onMouseUp); addEventListener(MouseEvent.MOUSE_OUT, onMouseUp); } private function addTarget():void { targetContainer = new Sprite(); targetPoint = new Sprite(); targetContainer.addChild(targetPoint); addChild(targetContainer); //initialize position to avoid jump when dragging starts targetPointXR = (oldTargetPointXR) % 360; //position target targetPoint.x = targetPointRadius*Math.cos(targetPointXR*Math.PI/180); targetPoint.z = targetPointRadius*Math.sin(targetPointXR*Math.PI/180); targetPoint.y = 0; } private function onDrag(event:MouseEvent):void { //get distance dragged var dx:Number = container.mouseX - dragStartX; var dy:Number = container.mouseY - dragStartY; var zR:Number = Math.atan2(dy,dx); targetPointXR = (oldTargetPointXR + dx) % 360; //get angle dragged //position target targetPoint.x = targetPointRadius*Math.cos(targetPointXR*Math.PI/180); targetPoint.z = targetPointRadius*Math.sin(targetPointXR*Math.PI/180); targetPoint.y = 0; } private function onMouseUp(event:MouseEvent):void { removeEventListener(MouseEvent.MOUSE_MOVE, onDrag); removeEventListener(MouseEvent.MOUSE_UP, onDrag); } private function createSphere(radius:Number, latspacing:int, longspacing:int):void { //sphere for(var lat:int = 0; lat <= 180; lat += latspacing){ for(var long:int = 0; long< 360; long += longspacing){ //get x,y,z for the point at lat, long //x = r*cos(long)*sin(lat) //y = r*cos(lat) //z = r*sin(long)*sin(lat) var _x:Number = radius*Math.cos(long*Math.PI/180)*Math.sin(lat*Math.PI/180); var _y:Number = radius*Math.cos(lat*Math.PI/180); var _z:Number = radius*Math.sin(long*Math.PI/180)*Math.sin(lat*Math.PI/180); vertices.push(_x,_y,_z); uvtData.push(long/360,lat/180,1); } } //uvtData //OK, now for triangles var rows:Number = 180/latspacing; var cols:Number = 360/longspacing; /* triangle arrangement i--------(i+1) | / | | / | | / | |/ | i2 ------(i2 +1) */ for(var row:int = 0; row < rows; row++){//-2 because n & s pole rows are done separately for(var col:int = 0; col < cols; col++){ var i:int = row*(cols) + col; var i2:int = (row+1)*(cols) + col; if(col+1 != cols) { indices.push(i, i + 1, i2); indices.push(i2, i + 1, i2 + 1); } else { //last rectangle - back to start indices.push(i, i - cols + 1, i2); indices.push(i2, i - cols + 1, i2 - cols + 1); } } } } private function onEnterFrame(event:Event):void { update(); render(); } private function update():void { container.x = stage.stageWidth/2 ; container.y = stage.stageHeight/2 ; projectionMatrix = perspective.toMatrix3D(); //projectionMatrix.prependTranslation(0.0,0.0,1); //rotate sphere /*projectionMatrix.prependRotation(rx,new Vector3D(1,0,0)[>Vector3D.X_AXIS<]); projectionMatrix.prependRotation(ry,new Vector3D(0,1,0)[>Vector3D.Y_AXIS<]); projectionMatrix.prependRotation(rz,new Vector3D(0,0,1)[>Vector3D.Z_AXIS<]);*/ projectionMatrix = Utils3D.pointTowards(1,projectionMatrix,targetPoint.transform.getRelativeMatrix3D(targetContainer).position, new Vector3D(0,0,-1), new Vector3D(0,-1,0)); } private function render():void { Utils3D.projectVectors(projectionMatrix, vertices, projectedVerts, uvtData); container.graphics.clear(); container.graphics.beginBitmapFill(texture,null, false, false); //container.graphics.beginFill(0xFF00FF); //container.graphics.lineStyle(1,0xFF0000,1); //container.graphics.drawTriangles(projectedVerts, indices, null, TriangleCulling.POSITIVE); container.graphics.drawTriangles(projectedVerts, indices, uvtData, TriangleCulling.POSITIVE); container.graphics.endFill(); } } }