|開発環境|Apache [[Flex]] SDK 4.12.1| ||FlashDevelop 4.6.2.5| |実行環境|Microsoft Windows 8.1 (64bit)| |プロジェクトの種類|ActionScript 3/AS3 Project| |プロジェクト名|PolygonModel| #table_zebra(project, #fff, #eee) http://www.maroon.dti.ne.jp/lance/flash/PolygonModel.html Project/Properties Output |Flash Player|14.0| |Dimensions|640 x 480 px| #table_zebra(prop, #fff, #eee) Main.as #highlight(actionscript){{ 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 #highlight(javascript){{ <!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> }}