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


Project/Properties
Output
Flash Player 14.0
Dimensions 640 x 480 px

Main.as
package 
{
    import com.adobe.utils.*;
    import flash.display.*;
    import flash.display3D.*;
    import flash.events.*;
    import flash.external.*;
    import flash.geom.*;
    import flash.text.*;
    import flash.ui.*;
    import mx.utils.StringUtil;
 
    public class Main extends Sprite 
    {
        // 3D
        private var context3D:Context3D;
        private var vertexBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
 
        // model
        private var vertexData:Vector.<Number>;
        private var indexData:Vector.<uint>;
        private var numVertices: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;
 
        // camera
        private var camDist:Number = 10;
        private var camPitch:int = 0;
        private var camYaw:int = 180;
 
        // display
        private var tfParams: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
 
            stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
            stage.stage3Ds[0].requestContext3D();
        }
 
        private function onContext3DCreate(e:Event):void 
        {
            context3D = (e.target as Stage3D).context3D;
            context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2);
            context3D.setCulling(Context3DTriangleFace.BACK);
            //context3D.setBlendFactors(
                //Context3DBlendFactor.SOURCE_COLOR, Context3DBlendFactor.DESTINATION_COLOR);
 
            // 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.setProgram(program);
 
            //
            projection = new PerspectiveMatrix3D;
            projection.perspectiveFieldOfViewLH(
                radians(45), stage.stageWidth / stage.stageHeight, 1, 100);
 
            tfParams = addTextField(0, 0);
 
            //
            ExternalInterface.addCallback("generate", 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;
            });
 
            stage.addEventListener(Event.ENTER_FRAME, render);
        }
 
        private function addTextField(x:Number, y:Number):TextField
        {
            var tf:TextField = new TextField;
            tf.defaultTextFormat = new TextFormat(null, 20, 0xffffff);
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.x = x;
            tf.y = y;
            addChild(tf);
            return tf;
        }
 
        private function render(e:Event):void 
        {
            updateView();
 
            context3D.clear(0.39, 0.58, 0.93);
 
            if (numVertices != 0)
            {
                var m:Matrix3D = new Matrix3D;
                m.append(view);
                m.append(projection);
                context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
                context3D.drawTriangles(indexBuffer);
            }
 
            context3D.present();
        }
 
        private function updateView():void 
        {
            if (keyDown[Keyboard.W]) camPitch += 1;
            if (keyDown[Keyboard.S]) camPitch -= 1;
            if (keyDown[Keyboard.A]) camYaw += 1;
            if (keyDown[Keyboard.D]) camYaw -= 1;
            if (keyDown[Keyboard.PAGE_UP]) camDist -= 0.1;
            if (keyDown[Keyboard.PAGE_DOWN]) camDist += 0.1;
 
            if (mDown)
            {
                camYaw += mouseX - mx;
                camPitch += mouseY - my;
            }
            mx = mouseX;
            my = mouseY;
 
            if (camPitch < -90) camPitch = -90;
            if (90 < camPitch) camPitch = 90;
            if (camYaw < 0) camYaw += 360;
            if (360 <= camYaw) camYaw -= 360;
            if (camDist < 1) camDist = 1;
 
            var pitch:Number = radians(camPitch);
            var y:Number = Math.sin(pitch) * camDist;
            var r:Number = Math.cos(pitch) * camDist;
            var yaw:Number = radians(camYaw);
            var z:Number = Math.cos(yaw) * r;
            var x:Number = Math.sin(yaw) * r;
 
            view = lookAt(new Vector3D(x, y, z), new Vector3D, Vector3D.Y_AXIS);
        }
 
        private function generate(csv:String):void 
        {
            var tbl:Array = parseCSV(csv);
 
            vertexData = new Vector.<Number>;
            indexData = new Vector.<uint>;
            numVertices = 0;
 
            for each (var fields:Array in tbl) 
            {
                switch (fields[0]) 
                {
                case "b":
                    genBox(fields);
                    break;
                case "t":
                    genTriangle(fields);
                    break;
                }
            }
 
            vertexBuffer = context3D.createVertexBuffer(numVertices, 6);
            vertexBuffer.uploadFromVector(vertexData, 0, numVertices);
 
            indexBuffer = context3D.createIndexBuffer(indexData.length);
            indexBuffer.uploadFromVector(indexData, 0, indexData.length);
 
            //
            context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
        }
 
        private function genBox(f:Array):void 
        {
            const vertices:Vector.<int> = Vector.<int>([
            //  x, y, z,
                0, 0, 0,
                1, 0, 0,
                1, 0, 1,
                0, 0, 1,
                0, 1, 0,
                1, 1, 0,
                1, 1, 1,
                0, 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 * 3;
                vertexData.push(vertices[base + 0] == 0 ? f[1] : f[2]);
                vertexData.push(vertices[base + 1] == 0 ? f[3] : f[4]);
                vertexData.push(vertices[base + 2] == 0 ? f[5] : f[6]);
                vertexData.push(color(f[10]), color(f[11]), color(f[12]));
            }
            for (i = 0; i < indices.length; i++) 
            {
                indexData.push(numVertices + indices[i]);
            }
            numVertices += 8;
        }
 
        private function genTriangle(f:Array):void 
        {
            for (var i:int = 0; i < 3; i++) 
            {
                var base:int = 1 + i * 3;
                vertexData.push(f[base + 0]);
                vertexData.push(f[base + 1]);
                vertexData.push(f[base + 2]);
                vertexData.push(color(f[10]), color(f[11]), color(f[12]));
                indexData.push(numVertices++);
            }
        }
 
        private function parseCSV(dat:String):Array
        {
            dat = dat.replace(/\s+$/);
 
            var csvDat:Array = new Array;
            var tmp:Array = dat.split("\n");
            var len:Number = tmp.length;
            for (var i:int = 0; i < len; i++) 
            {
                csvDat.push(tmp[i].split("\t"));
            }
            return csvDat;
        }
 
        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 radians(x:Number):Number
        {
            return x * Math.PI / 180;
        }
 
        private function color(s:String):Number
        {
            return parseInt(s, 16) / 0xff;
        }
 
    }
 
}
 

PolygonModel.html
<!doctype html>
<head>
<title>PolygonModel</title>
<script>
 
function generate()
{
	var data = document.getElementById("data");
	window.polymodel.generate(data.value);
}
 
</script>
</head>
 
<body>
<embed src="PolygonModel.swf" id="polymodel" width=640 height=480 wmode="direct"></embed><br>
WASD:move PageUp:near PageDown:far<br>
MouseDrag:move Wheel:near/far<br>
<br>
<textarea id="data" cols=120 rows=15>
type	1	2	3	4	5	6	7	8	9	r	g	b	comment
b	-2.5	-1.5	-0.5	0.5	-0.5	0.5				0	0	0	エンジン
b	-1.5	1.5	-0.5	0.5	-0.5	0.5				0	7f	0	胴体
b	-1	1	-0.4	-0.2	-5	5				0	7f	0	主翼
b	3.5	4.5	0	0.1	-2	2				0	7f	0	水平尾翼
b	4	5	0	1.2	-0.05	0.05				0	7f	0	垂直尾翼
b	-0.5	1.5	0.5	1	-0.3	0.3				0	ff	ff	風防
t	5.2	0	0	1.5	-0.5	-0.5	1.5	0.5	-0.5	0	7f	0	胴体後部z-
t	5.2	0	0	1.5	0.5	-0.5	1.5	0.5	0.5	0	7f	0	胴体後部y+
t	5.2	0	0	1.5	0.5	0.5	1.5	-0.5	0.5	0	7f	0	胴体後部z+
t	5.2	0	0	1.5	-0.5	0.5	1.5	-0.5	-0.5	0	7f	0	胴体後部y-
</textarea><br>
<br>
<button onclick="generate()">generate</button>
</body>
 
最終更新:2014年08月10日 17:01