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


参考

Main.as
package 
{
    import com.adobe.utils.*;
    import flash.display.*;
    import flash.display3D.*;
    import flash.display3D.textures.Texture;
    import flash.events.*;
    import flash.geom.*;
    import flash.text.*;
    import flash.ui.Keyboard;
    import mx.utils.StringUtil;
 
    public class Main extends Sprite 
    {
        private const viewWidth:int = 800;
        private const viewHeight:int = 600;
 
        [Embed(source = "earthmap1k.jpg")]
        private const EarthMap:Class;
        private var texture:Texture;
 
        private var context3D:Context3D;
        private var vertexBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
 
        private var model:Matrix3D = new Matrix3D;
        private var view:Matrix3D = new Matrix3D;
        private var projection:PerspectiveMatrix3D = new PerspectiveMatrix3D;
 
        private var keyDown:Array = new Array;
        private var tf:TextField = new TextField;
 
        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
 
            var stage3D:Stage3D = stage.stage3Ds[0];
            stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
            stage3D.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(viewWidth, viewHeight, 2);
            context3D.setCulling(Context3DTriangleFace.BACK);
 
            // vertexBuffer
            const stackNum:int = 32; // 輪切りの数。2の倍数。最小2。
            var vertices:Vector.<Number> = new Vector.<Number>;
 
            vertices.push(0, 1, 0, 0.5, 0); // x, y, z, u, v
            for (var stack:int = 1; stack < stackNum; stack++) 
            {
                var v:Number = stack / stackNum;
                var rad:Number = ((stackNum - 2 * stack) / stackNum) * Math.PI / 2;
                var y:Number = Math.sin(rad);
                var r:Number = Math.cos(rad);
                var sliceNum:int = 4 * Math.min(stack, stackNum - stack); // 放射頂点の数
                for (var slice:int = 0; slice <= sliceNum; slice++) 
                {
                    rad = (slice / sliceNum) * Math.PI * 2;
                    var x:Number = Math.cos(rad) * r;
                    var z:Number = Math.sin(rad) * r;
                    vertices.push(x, y, z, 1 - slice / sliceNum, v);
                }
            }
            vertices.push(0, -1, 0, 0.5, 1);
 
            const perVertex:int = 5;
            const numVertices:int = vertices.length / perVertex;
            vertexBuffer = context3D.createVertexBuffer(numVertices, perVertex);
            vertexBuffer.uploadFromVector(vertices, 0, numVertices);
 
            // indexBuffer
            var indices:Vector.<uint> = new Vector.<uint>;
 
            var prevHead:int = 0; // 前の先頭頂点番号
            var prevVert:int = 1; // 前の頂点数
            for (stack = 0; stack < stackNum / 2; stack++) 
            {
                var currHead:int = prevHead + prevVert; // 現在の先頭頂点番号
                var currVert:int = 4 * (stack + 1) + 1; // 現在の頂点数
                for (var quad:int = 0; quad < 4; quad++) // 4象限
                {
                    var prevQuad:int = quad * stack; // 前の象限オフセット
                    var currQuad:int = quad * (stack + 1); // 現在の象限オフセット
                    for (var n:int = 0; ; n++) 
                    {
                        indices.push(prevHead + prevQuad + n);
                        indices.push(currHead + currQuad + n);
                        indices.push(currHead + currQuad + n + 1);
                        if (stack <= n) break;
                        indices.push(prevHead + prevQuad + n);
                        indices.push(currHead + currQuad + n + 1);
                        indices.push(prevHead + prevQuad + n + 1);
                    }
                }
                prevHead = currHead;
                prevVert = currVert;
            }
            for (stack = stackNum / 2 - 1; 0 <= stack; stack--) 
            {
                currHead = prevHead + prevVert;
                currVert = 4 * stack + 1;
                for (quad = 0; quad < 4; quad++) // 4象限
                {
                    prevQuad = quad * (stack + 1);
                    currQuad = quad * stack;
                    for (n = 0; ; n++) 
                    {
                        indices.push(currHead + currQuad + n);
                        indices.push(prevHead + prevQuad + n + 1);
                        indices.push(prevHead + prevQuad + n);
                        if (stack <= n) break;
                        indices.push(currHead + currQuad + n);
                        indices.push(currHead + currQuad + n + 1);
                        indices.push(prevHead + prevQuad + n + 1);
                    }
                }
                prevHead = currHead;
                prevVert = currVert;
            }
 
            indexBuffer = context3D.createIndexBuffer(indices.length);
            indexBuffer.uploadFromVector(indices, 0, indices.length);
 
            // texture
            var bitmap:Bitmap = new EarthMap;
            var bitmapData:BitmapData = new BitmapData(1024, 512, false);
            bitmapData.draw(bitmap.bitmapData,
                new Matrix(1024 / 1000, 0, 0, 512 / 500), null, null, null, true);
            texture = context3D.createTexture(
                bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
            texture.uploadFromBitmapData(bitmapData);
 
            // 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,
                "tex ft0 v0 fs0 <2d,linear>\n" +
                "mov oc ft0"
            );
            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_2);
            context3D.setTextureAt(0, texture);
            context3D.setProgram(program);
 
            view.appendTranslation(0, 0, -2);
            projection.perspectiveFieldOfViewRH(45, viewWidth / viewHeight, 0.1, 100);
 
            stage.addEventListener(Event.ENTER_FRAME, render);
        }
 
        private function render(e:Event):void 
        {
            if (IsKeyDown(Keyboard.DOWN)) view.appendTranslation(0, 0, -0.1);
            if (IsKeyDown(Keyboard.UP)) view.appendTranslation(0, 0, 0.1);
            if (IsKeyDown(Keyboard.W)) model.appendRotation(2, Vector3D.X_AXIS);
            if (IsKeyDown(Keyboard.S)) model.appendRotation(-2, Vector3D.X_AXIS);
            if (IsKeyDown(Keyboard.A)) model.appendRotation(2, Vector3D.Y_AXIS);
            if (IsKeyDown(Keyboard.D)) model.appendRotation(-2, Vector3D.Y_AXIS);
            if (IsKeyDown(Keyboard.E)) model.appendRotation(-2, Vector3D.Z_AXIS);
            if (IsKeyDown(Keyboard.Q)) model.appendRotation(2, Vector3D.Z_AXIS);
 
            var v:Vector.<Vector3D> = model.decompose();
            tf.text = StringUtil.substitute("driverInfo: {0}\nmodel: x={1} y={2} z={3}\nview: z={4}",
                context3D.driverInfo,
                degrees(v[1].x), degrees(v[1].y), degrees(v[1].z),
                view.position.z.toFixed(1));
 
            //
            context3D.clear(.3, .3, .3);
            var matrix:Matrix3D = new Matrix3D;
 
            matrix.identity();
            matrix.append(model);
            matrix.append(view);
            matrix.append(projection);
            context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, matrix, true);
            context3D.drawTriangles(indexBuffer);
 
            context3D.present();
        }
 
        private function IsKeyDown(keyCode:uint):Boolean 
        {
            return (keyDown[keyCode]) ? true : false;
        }
 
        private function degrees(x:Number):int
        {
            return x * 180 / Math.PI;
        }
    }
 
}
 

Sphere
+ ...
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 const viewWidth:int = 800;
        private const viewHeight:int = 600;
 
        private var context3D:Context3D;
        private var vertexBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
 
        private var model:Matrix3D = new Matrix3D;
        private var view:Matrix3D = new Matrix3D;
        private var projection:PerspectiveMatrix3D = new PerspectiveMatrix3D;
 
        private var keyDown:Array = new Array;
        private var tf:TextField = new TextField;
 
        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
 
            var stage3D:Stage3D = stage.stage3Ds[0];
            stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
            stage3D.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(viewWidth, viewHeight, 2);
            context3D.setCulling(Context3DTriangleFace.BACK);
 
            // vertexBuffer
            const stackNum:int = 32; // 輪切りの数。2の倍数。最小2。
            var vertices:Vector.<Number> = new Vector.<Number>;
 
            vertices.push(0, 1, 0, 0.5, 1, 0.5); // x, y, z, r, g, b
            for (var stack:int = 1; stack < stackNum; stack++) 
            {
                var v:Number = stack / stackNum;
                var rad:Number = ((stackNum - 2 * stack) / stackNum) * Math.PI / 2;
                var y:Number = Math.sin(rad);
                var r:Number = Math.cos(rad);
                var sliceNum:int = 4 * Math.min(stack, stackNum - stack); // 放射頂点の数
                for (var slice:int = 0; slice <= sliceNum; slice++) 
                {
                    rad = (slice / sliceNum) * Math.PI * 2;
                    var x:Number = Math.cos(rad) * r;
                    var z:Number = Math.sin(rad) * r;
                    vertices.push(x, y, z, x / 2 + 0.5, y / 2 + 0.5, z / 2 + 0.5);
                }
            }
            vertices.push(0, -1, 0, 0.5, 0, 0.5);
 
            const perVertex:int = 6;
            const numVertices:int = vertices.length / perVertex;
            vertexBuffer = context3D.createVertexBuffer(numVertices, perVertex);
            vertexBuffer.uploadFromVector(vertices, 0, numVertices);
 
            // indexBuffer
            var indices:Vector.<uint> = new Vector.<uint>;
 
            var prevHead:int = 0; // 前の先頭頂点番号
            var prevVert:int = 1; // 前の頂点数
            for (stack = 0; stack < stackNum / 2; stack++) 
            {
                var currHead:int = prevHead + prevVert; // 現在の先頭頂点番号
                var currVert:int = 4 * (stack + 1) + 1; // 現在の頂点数
                for (var quad:int = 0; quad < 4; quad++) // 4象限
                {
                    var prevQuad:int = quad * stack; // 前の象限オフセット
                    var currQuad:int = quad * (stack + 1); // 現在の象限オフセット
                    for (var n:int = 0; ; n++) 
                    {
                        indices.push(prevHead + prevQuad + n);
                        indices.push(currHead + currQuad + n);
                        indices.push(currHead + currQuad + n + 1);
                        if (stack <= n) break;
                        indices.push(prevHead + prevQuad + n);
                        indices.push(currHead + currQuad + n + 1);
                        indices.push(prevHead + prevQuad + n + 1);
                    }
                }
                prevHead = currHead;
                prevVert = currVert;
            }
            for (stack = stackNum / 2 - 1; 0 <= stack; stack--) 
            {
                currHead = prevHead + prevVert;
                currVert = 4 * stack + 1;
                for (quad = 0; quad < 4; quad++) // 4象限
                {
                    prevQuad = quad * (stack + 1);
                    currQuad = quad * stack;
                    for (n = 0; ; n++) 
                    {
                        indices.push(currHead + currQuad + n);
                        indices.push(prevHead + prevQuad + n + 1);
                        indices.push(prevHead + prevQuad + n);
                        if (stack <= n) break;
                        indices.push(currHead + currQuad + n);
                        indices.push(currHead + currQuad + n + 1);
                        indices.push(prevHead + prevQuad + n + 1);
                    }
                }
                prevHead = currHead;
                prevVert = currVert;
            }
 
            indexBuffer = context3D.createIndexBuffer(indices.length);
            indexBuffer.uploadFromVector(indices, 0, indices.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);
 
            view.appendTranslation(0, 0, -2);
            projection.perspectiveFieldOfViewRH(45, viewWidth / viewHeight, 1, 500);
 
            stage.addEventListener(Event.ENTER_FRAME, render);
        }
 
        private function render(e:Event):void 
        {
            if (IsKeyDown(Keyboard.DOWN)) view.appendTranslation(0, 0, -0.1);
            if (IsKeyDown(Keyboard.UP)) view.appendTranslation(0, 0, 0.1);
            if (IsKeyDown(Keyboard.W)) model.appendRotation(-2, Vector3D.X_AXIS);
            if (IsKeyDown(Keyboard.S)) model.appendRotation(2, Vector3D.X_AXIS);
            if (IsKeyDown(Keyboard.A)) model.appendRotation(-2, Vector3D.Y_AXIS);
            if (IsKeyDown(Keyboard.D)) model.appendRotation(2, Vector3D.Y_AXIS);
            if (IsKeyDown(Keyboard.E)) model.appendRotation(-2, Vector3D.Z_AXIS);
            if (IsKeyDown(Keyboard.Q)) model.appendRotation(2, Vector3D.Z_AXIS);
 
            var v:Vector.<Vector3D> = model.decompose();
            tf.text = StringUtil.substitute("driverInfo: {0}\nmodel: x={1} y={2} z={3}\nview: z={4}",
                context3D.driverInfo,
                degrees(v[1].x), degrees(v[1].y), degrees(v[1].z),
                view.position.z.toFixed(1));
 
            //
            context3D.clear(.3, .3, .3);
            var matrix:Matrix3D = new Matrix3D;
 
            matrix.identity();
            matrix.append(model);
            matrix.append(view);
            matrix.append(projection);
            context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, matrix, true);
            context3D.drawTriangles(indexBuffer);
 
            context3D.present();
        }
 
        private function IsKeyDown(keyCode:uint):Boolean 
        {
            return (keyDown[keyCode]) ? true : false;
        }
 
        private function degrees(x:Number):int
        {
            return x * 180 / Math.PI;
        }
    }
 
}
 
最終更新:2014年07月08日 21:49