開発環境 Apache Flex SDK 4.12.1
FlashDevelop 4.6.2.5
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 ActionScript 3/AS3 Project
プロジェクト名 Orbit


Project/Properties
Output
Flash Player 14.0

Main.as
package 
{
    import com.adobe.utils.*;
    import flash.display.*;
    import flash.display3D.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.ui.*;
 
    public class Main extends Sprite 
    {
        // 3D
        private var context3D:Context3D;
        private var vertexBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
 
        // model
        private var vertexData:Vector.<Number> = new Vector.<Number>;
        private var indexData:Vector.<uint> = new Vector.<uint>;
        private var numVertices:int = 0;
        private const colorFixed:Vector.<Number> = Vector.<Number>([1, 1, 1, 1]);
        private var numFixed:int;
        private var indexSphere:int;
        private var numSphere:int;
 
        // matrix
        private var view:Matrix3D;
        private var projection:PerspectiveMatrix3D;
 
        // input
        private var keyDown:Array = new Array;
        private var mDown:Boolean = false;
        private var mX:Number;
        private var mY:Number;
 
        //
        private const au:Number = 149597870.700; // 天文単位(km)
        private var planet:Vector.<Object>;
 
        // camera
        private var camDist:Number = 2 * au;
        private var camLat:Number = 0;
        private var camLon:Number = 180;
 
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
 
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
 
            stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
            stage.stage3Ds[0].requestContext3D();
        }
 
        private function onContext3DCreate(e:Event):void 
        {
            context3D = stage.stage3Ds[0].context3D;
            context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2);
            context3D.setCulling(Context3DTriangleFace.BACK);
 
            // program
            var vertexProgram:AGALMiniAssembler = new AGALMiniAssembler;
            vertexProgram.assemble(Context3DProgramType.VERTEX,
                "m44 op va0 vc0"
            );
            var fragmentProgram:AGALMiniAssembler = new AGALMiniAssembler;
            fragmentProgram.assemble(Context3DProgramType.FRAGMENT,
                "mov oc fc0"
            );
            var program:Program3D = context3D.createProgram();
            program.upload(vertexProgram.agalcode, fragmentProgram.agalcode);
            context3D.setProgram(program);
 
            //
            projection = new PerspectiveMatrix3D;
            projection.perspectiveFieldOfViewLH(
                toRadians(45), stage.stageWidth / stage.stageHeight, 0.1 * au, 10 * au);
 
            //
            generate();
 
            //
            stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void {
                keyDown[e.keyCode] = true;
            });
            stage.addEventListener(KeyboardEvent.KEY_UP, function(e:KeyboardEvent):void {
                keyDown[e.keyCode] = false;
            });
            stage.addEventListener(Event.DEACTIVATE, function(e:Event):void {
                keyDown = new Array;
            });
 
            stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
                mDown = true;
            });
            stage.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void {
                mDown = false;
            });
            stage.addEventListener(MouseEvent.MOUSE_WHEEL, function(e:MouseEvent):void {
                camDist -= e.delta * au * 0.1;
            });
 
            stage.addEventListener(Event.ENTER_FRAME, render);
        }
 
        private function generate():void 
        {
            // R:直径(km) a:軌道長半径(au) E:公転周期(year)
            planet = new Vector.<Object>(4);
            planet[0] = { R:1392038, color:Vector.<Number>([1, 1, 0, 1]) };
            planet[1] = { R:4879.4, a:0.38709927, E:0.241, color:Vector.<Number>([0, 1, 1, 1]) };
            planet[2] = { R:12103.6, a:0.72333566, E:0.615, color:Vector.<Number>([1, 0.5, 0, 1]) };
            planet[3] = { R:12756.3, a:1.00000261, E:1.000, color:Vector.<Number>([0, 0, 1, 1]) };
 
            for each (var p:Object in planet) 
            {
                p.lon = 0;
                genCircle(p.a * au, p.R * 50, 64);
            }
            numFixed = indexData.length / 3;
 
            indexSphere = indexData.length;
            genSphere();
            numSphere = (indexData.length - indexSphere) / 3;
 
            vertexBuffer = context3D.createVertexBuffer(numVertices, 3);
            vertexBuffer.uploadFromVector(vertexData, 0, numVertices);
 
            indexBuffer = context3D.createIndexBuffer(indexData.length);
            indexBuffer.uploadFromVector(indexData, 0, indexData.length);
 
            context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
        }
 
        // a=軌道長半径 R=直径
        private function genCircle(a:Number, R:Number, slice:int):void 
        {
            const vertices:Vector.<int> = Vector.<int>([
            //  x, y, z, x=start/end z=in/out
                0, 0, 0,
                0, 1, 0,
                0, 1, 1,
                0, 0, 1,
                1, 0, 0,
                1, 1, 0,
                1, 1, 1,
                1, 0, 1,
            ]);
            const indices:Vector.<uint> = Vector.<uint>([
                0, 1, 5, 5, 4, 0, // in
                1, 2, 6, 6, 5, 1, // +y
                2, 3, 7, 7, 6, 2, // out
                3, 0, 4, 4, 7, 3, // -y
            ]);
 
            for (var s:int = 0; s < slice; s++) 
            {
                for (var i:int = 0; i < 8; i++) 
                {
                    var base:int = i * 3;
                    var lon:Number = 2 * Math.PI * (s + vertices[base]) / slice;
                    var y:Number = (vertices[base + 1] - 0.5) * R;
                    var r:Number = a + (vertices[base + 2] - 0.5) * R;
 
                    vertexData.push(Math.sin(lon) * r);
                    vertexData.push(y);
                    vertexData.push(Math.cos(lon) * r);
                }
                for (i = 0; i < indices.length; i++) 
                {
                    indexData.push(numVertices + indices[i]);
                }
                numVertices += 8;
            }
        }
 
        // r=半径
        private function genSphere():void 
        {
            const vertices:Vector.<int> = Vector.<int>([
            //  x, y, z,
                0, 1, 0,
                0, 0, 1,
                1, 0, 0,
                0, 0, -1,
                -1, 0, 0,
                0, -1, 0,
            ]);
            const indices:Vector.<uint> = Vector.<uint>([
                0, 1, 2,
                0, 2, 3,
                0, 3, 4,
                0, 4, 1,
                1, 5, 2,
                2, 5, 3,
                3, 5, 4,
                4, 5, 1,
            ]);
 
            for (var i:int = 0; i < 6; i++) 
            {
                var base:int = i * 3;
                vertexData.push(vertices[base + 0]);
                vertexData.push(vertices[base + 1]);
                vertexData.push(vertices[base + 2]);
            }
            for (i = 0; i < indices.length; i++) 
            {
                indexData.push(numVertices + indices[i]);
            }
            numVertices += 6;
        }
 
        private function render(e:Event):void 
        {
            updateView();
 
            context3D.clear(0.39, 0.58, 0.93);
 
            var m:Matrix3D = new Matrix3D;
            m.append(view);
            m.append(projection);
            context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
            context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, colorFixed);
            context3D.drawTriangles(indexBuffer, 0, numFixed);
 
            for each (var p:Object in planet) 
            {
                m.identity();
                m.append(calcWorld(p));
                m.append(view);
                m.append(projection);
                context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
                context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, p.color);
                context3D.drawTriangles(indexBuffer, indexSphere, numSphere);
            }
 
            context3D.present();
        }
 
        private function updateView():void 
        {
            if (keyDown[Keyboard.W]) camLat += 1;
            if (keyDown[Keyboard.S]) camLat -= 1;
            if (keyDown[Keyboard.A]) camLon += 1;
            if (keyDown[Keyboard.D]) camLon -= 1;
            if (keyDown[Keyboard.PAGE_UP]) camDist -= 0.01 * au;
            if (keyDown[Keyboard.PAGE_DOWN]) camDist += 0.01 * au;
 
            if (mDown)
            {
                camLon += mouseX - mX;
                camLat += mouseY - mY;
            }
            mX = mouseX;
            mY = mouseY;
 
            if (camLat < -90) camLat = -90;
            if (90 < camLat) camLat = 90;
            while (camLon < 0) camLon += 360;
            while (360 <= camLon) camLon -= 360;
            if (camDist < 0) camDist = 0;
 
            var lat:Number = toRadians(camLat);
            var y:Number = Math.sin(lat) * camDist;
            var r:Number = Math.cos(lat) * camDist;
            var lon:Number = toRadians(camLon);
            var z:Number = Math.cos(lon) * r;
            var x:Number = Math.sin(lon) * r;
 
            view = lookAt(new Vector3D(x, y, z), new Vector3D, Vector3D.Y_AXIS);
        }
 
        private function calcWorld(p:Object):Matrix3D
        {
            var s:Number;
            var x:Number;
            var z:Number;
 
            if (p.hasOwnProperty("E"))
            {
                s = p.R * 300;
 
                var lon:Number = p.lon + 1 / p.E;
                if (360 <= lon) lon -= 360;
                p.lon = lon;
 
                var r:Number = p.a * au;
                var rad:Number = toRadians(lon);
                x = Math.cos(rad) * r;
                z = Math.sin(rad) * r;
            }
            else
            {
                s = p.R * 5;
                x = z = 0;
            }
 
            var world:Matrix3D = new Matrix3D;
            world.appendScale(s, s, s);
            world.appendTranslation(x, 0, z);
            return world;
        }
 
        private function lookAt(
            cameraPosition:Vector3D, cameraTarget:Vector3D, cameraUpVector:Vector3D):Matrix3D
        {
            var zaxis:Vector3D = cameraTarget.subtract(cameraPosition);
            zaxis.normalize();
            var xaxis:Vector3D = cameraUpVector.crossProduct(zaxis);
            xaxis.normalize();
            var yaxis:Vector3D = zaxis.crossProduct(xaxis);
 
            return new Matrix3D(Vector.<Number>([
                xaxis.x, yaxis.x, zaxis.x, 0,
                xaxis.y, yaxis.y, zaxis.y, 0,
                xaxis.z, yaxis.z, zaxis.z, 0,
                -xaxis.dotProduct(cameraPosition), -yaxis.dotProduct(cameraPosition),
                -zaxis.dotProduct(cameraPosition), 1
            ]));
        }
 
        private function toRadians(degrees:Number):Number
        {
            return degrees * Math.PI / 180;
        }
 
    }
 
}
 
最終更新:2014年09月23日 16:18