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


Main.as
package 
{
    import com.adobe.utils.*;
    import flash.display.*;
    import flash.display3D.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.text.*;
    import flash.ui.Keyboard;
    import mx.utils.StringUtil;
 
    public class Main extends Sprite 
    {
        private var context3D:Context3D;
        private var vertexBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
 
        private var vertexData:Vector.<Number> = new Vector.<Number>;
        private var indexData:Vector.<uint> = new Vector.<uint>;
        private var numVertices:int = 0;
 
        private var view:Matrix3D;
        private var projection:PerspectiveMatrix3D;
 
        private var keyDown:Array = new Array;
        private var tf:TextField = new TextField;
 
        private var cameraPos:Vector3D = new Vector3D(0, 2, 0);
        private var cameraFront:Vector3D = new Vector3D(0, 0, 1);
        private var cameraUp:Vector3D = new Vector3D(0, 1, 0);
 
        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();
 
            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;
            });
 
            tf.defaultTextFormat = new TextFormat(null, 20, 0xffffff);
            tf.autoSize = TextFieldAutoSize.LEFT;
            addChild(tf);
        }
 
        private function onContext3DCreate(e:Event):void 
        {
            context3D = (e.target as Stage3D).context3D;
            context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2);
            context3D.setCulling(Context3DTriangleFace.BACK);
 
            generateSurface();
            generateCloud(0, 5, 0, 1, 1, 1);
 
            vertexBuffer = context3D.createVertexBuffer(numVertices, 6);
            vertexBuffer.uploadFromVector(vertexData, 0, numVertices);
 
            indexBuffer = context3D.createIndexBuffer(indexData.length);
            indexBuffer.uploadFromVector(indexData, 0, indexData.length);
 
            // program
            var vertexProgram:AGALMiniAssembler = new AGALMiniAssembler;
            vertexProgram.assemble(Context3DProgramType.VERTEX,
                "m44 op va0 vc0\n" +
                "mov v0 va1"
            );
            var fragmentProgram:AGALMiniAssembler = new AGALMiniAssembler;
            fragmentProgram.assemble(Context3DProgramType.FRAGMENT,
                "mov oc v0"
            );
            var program:Program3D = context3D.createProgram();
            program.upload(vertexProgram.agalcode, fragmentProgram.agalcode);
 
            //
            context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setProgram(program);
 
            //
            projection = new PerspectiveMatrix3D;
            projection.perspectiveFieldOfViewLH(
                radians(45), stage.stageWidth / stage.stageHeight, 0.1, 100);
 
            stage.addEventListener(Event.ENTER_FRAME, render);
        }
 
        private function generateSurface():void 
        {
            const vertices:Vector.<Number> = Vector.<Number>([
            //  x, y, z,
                0, 0, 0,
                0, 0, 1,
                1, 0, 1,
                1, 0, 0,
            ]);
            const indices:Vector.<uint> = Vector.<uint>([
                0, 1, 2, 2, 3, 0,
            ]);
 
            for (var z:int = 0; z < 10; z++) 
            {
                for (var x:int = 0; x < 10; x++) 
                {
                    for (var i:int = 0; i < 4; i++) 
                    {
                        var base:int = i * 3;
                        vertexData.push(vertices[base + 0] + x);
                        vertexData.push(vertices[base + 1]);
                        vertexData.push(vertices[base + 2] + z);
                        vertexData.push(0, (x + z) / 18, 0);
                    }
                    for (i = 0; i < indices.length; i++)
                    {
                        indexData.push(numVertices + indices[i]);
                    }
                    numVertices += 4;
                }
            }
        }
 
        private function generateCloud(
            x0:Number, y0:Number, z0:Number, x1:Number, y1:Number, z1:Number):void 
        {
            const vertices:Vector.<Number> = Vector.<Number>([
            //  x, y, z, r, g, b,
                0, 0, 0, 0.5, 0.5, 0.5,
                1, 0, 0, 0.5, 0.5, 0.5,
                1, 0, 1, 0.5, 0.5, 0.5,
                0, 0, 1, 0.5, 0.5, 0.5,
                0, 1, 0, 1, 1, 1,
                1, 1, 0, 1, 1, 1,
                1, 1, 1, 1, 1, 1,
                0, 1, 1, 1, 1, 1,
            ]);
            const indices:Vector.<uint> = Vector.<uint>([
                0, 4, 5, 5, 1, 0, // -z
                1, 5, 6, 6, 2, 1, // +x
                2, 6, 7, 7, 3, 2, // +z
                3, 7, 4, 4, 0, 3, // -x
                0, 1, 2, 2, 3, 0, // -y
                4, 7, 6, 6, 5, 4, // +y
            ]);
 
            for (var i:int = 0; i < 8; i++) 
            {
                var base:int = i * 6;
                vertexData.push(x0 + vertices[base + 0] * x1);
                vertexData.push(y0 + vertices[base + 1] * y1);
                vertexData.push(z0 + vertices[base + 2] * z1);
                vertexData.push(vertices[base + 3]);
                vertexData.push(vertices[base + 4]);
                vertexData.push(vertices[base + 5]);
            }
            for (i = 0; i < indices.length; i++) 
            {
                indexData.push(numVertices + indices[i]);
            }
            numVertices += 8;
        }
 
        private function render(e:Event):void 
        {
            updateView();
 
            context3D.clear(0.39, 0.58, 0.93);
 
            var curx:int = Math.floor(cameraPos.x / 10);
            var curz:int = Math.floor(cameraPos.z / 10);
 
            for (var z:int = -1; z <= 1; z++) 
            {
                for (var x:int = -1; x <= 1; x++) 
                {
                    var world:Matrix3D = new Matrix3D;
                    world.appendTranslation((curx + x) * 10, 0, (curz + z) * 10);
 
                    var m:Matrix3D = new Matrix3D;
                    m.append(world);
                    m.append(view);
                    m.append(projection);
 
                    context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
                    context3D.drawTriangles(indexBuffer, 0, -1);
                }
            }
 
            context3D.present();
        }
 
        private function updateView():void 
        {
            var roll:Number = 0;
            var pitch:Number = 0;
            var yaw:Number = 0;
            var velocity:Number = 0;
 
            if (keyDown[Keyboard.Q]) velocity += .1;
            if (keyDown[Keyboard.A]) velocity += -.1;
            if (keyDown[Keyboard.Z]) yaw += -1;
            if (keyDown[Keyboard.X]) yaw += 1;
            if (keyDown[Keyboard.LEFT]) roll += 1;
            if (keyDown[Keyboard.RIGHT]) roll += -1;
            if (keyDown[Keyboard.UP]) pitch += -1;
            if (keyDown[Keyboard.DOWN]) pitch += 1;
 
            var cameraCross:Vector3D = cameraFront.crossProduct(cameraUp); // Left
            var m:Matrix3D = new Matrix3D;
 
            m.identity();
            m.prependRotation(yaw, cameraUp);
            cameraFront = m.transformVector(cameraFront);
            cameraCross = m.transformVector(cameraCross);
 
            m.identity();
            m.prependRotation(pitch, cameraCross);
            cameraFront = m.transformVector(cameraFront);
            cameraUp = m.transformVector(cameraUp);
 
            m.identity();
            m.prependRotation(roll, cameraFront);
            cameraCross = m.transformVector(cameraCross);
            cameraUp = m.transformVector(cameraUp);
 
            var forward:Vector3D = cameraFront.clone();
            forward.scaleBy(velocity);
            cameraPos = cameraPos.add(forward);
 
            view = lookAt(cameraPos, cameraPos.add(cameraFront), cameraUp);
 
            displayParams();
        }
 
        private function displayParams():void 
        {
            var camPitch:Number = degrees(Math.asin(cameraFront.y));
            var camYaw:Number = degrees(Math.atan2(cameraFront.x, cameraFront.z));
            if (camYaw < 0) camYaw += 360;
 
            var camCross:Vector3D = new Vector3D(-1, 0, 0); // Left
            var camUp:Vector3D = Vector3D.Y_AXIS;
            var m:Matrix3D = new Matrix3D;
 
            m.identity();
            m.prependRotation(camYaw, Vector3D.Y_AXIS);
            camCross = m.transformVector(camCross);
 
            m.identity();
            m.prependRotation(camPitch, camCross);
            camUp = m.transformVector(camUp);
 
            var camRoll:Number = degrees(Math.acos(clamp(camUp.dotProduct(cameraUp), -1, 1)));
            if (0 < camCross.dotProduct(cameraUp)) camRoll = -camRoll;
 
            tf.text = StringUtil.substitute(
                "Pos:{0} {1} {2}\nRoll:{3} Pitch:{4} Yaw:{5}",
                cameraPos.x.toFixed(1), cameraPos.y.toFixed(1), cameraPos.z.toFixed(1),
                camRoll.toFixed(0), camPitch.toFixed(0), camYaw.toFixed(0));
        }
 
        private function lookAt(
            cameraPosition:Vector3D, cameraTarget:Vector3D, cameraUpVector:Vector3D):Matrix3D
        {
            var zaxis:Vector3D = cameraTarget.subtract(cameraPos);
            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 radians(x:Number):Number
        {
            return x * Math.PI / 180;
        }
 
        private function degrees(x:Number):Number
        {
            return x * 180 / Math.PI;
        }
 
        private function clamp(x:Number, min:Number, max:Number):Number
        {
            if (x <= min) return min;
            if (max <= x) return max;
            return x;
        }
 
    }
 
}
 
最終更新:2014年07月30日 17:00