|開発環境|Apache [[Flex]] SDK 4.12.1| ||FlashDevelop 4.6.2.5| |実行環境|Microsoft Windows 8.1 (64bit)| |プロジェクトの種類|ActionScript 3/AS3 Project| |プロジェクト名|FreeCamera| #table_zebra(project, #fff, #eee) http://www.maroon.dti.ne.jp/lance/flash/freecamera.html Main.as #highlight(actionscript){{ package { import com.adobe.utils.*; import flash.display.*; import flash.display3D.*; import flash.events.*; import flash.geom.*; import flash.text.*; import flash.ui.*; import mx.utils.*; 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; // matrix private var view:Matrix3D; private var projection:PerspectiveMatrix3D; // input private var keyDown:Array = new Array; // camera private var camPos:Vector3D = new Vector3D(0, 0, -3); private var camPitch:int = 0; private var camYaw:int = 0; // 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(); 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; }); tfParams = addTextField(0, 0); } 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 onContext3DCreate(e:Event):void { context3D = (e.target as Stage3D).context3D; context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2); context3D.setCulling(Context3DTriangleFace.BACK); generateBox(); 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, 1, 100); stage.addEventListener(Event.ENTER_FRAME, render); } private function generateBox():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(vertices[base + 0]); vertexData.push(vertices[base + 1]); vertexData.push(vertices[base + 2]); 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 m:Matrix3D = new Matrix3D; 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 front:int = 0; var cross:int = 0; var up:int = 0; if (keyDown[Keyboard.W]) { camPitch += 1; if (89 < camPitch) camPitch = 89; } if (keyDown[Keyboard.S]) { camPitch -= 1; if (camPitch < -89) camPitch = -89; } if (keyDown[Keyboard.A]) { camYaw -= 1; if (camYaw < 0) camYaw += 360; } if (keyDown[Keyboard.D]) { camYaw += 1; if (360 <= camYaw) camYaw -= 360; } if (keyDown[Keyboard.UP]) front += 1; if (keyDown[Keyboard.DOWN]) front += -1; if (keyDown[Keyboard.LEFT]) cross += 1; if (keyDown[Keyboard.RIGHT]) cross += -1; if (keyDown[Keyboard.PAGE_UP]) up += 1; if (keyDown[Keyboard.PAGE_DOWN]) up += -1; var pitch:Number = radians(camPitch); var y:Number = Math.sin(pitch); var r:Number = Math.cos(pitch); var yaw:Number = radians(camYaw); var z:Number = Math.cos(yaw) * r; var x:Number = Math.sin(yaw) * r; var camFront:Vector3D = new Vector3D(x, y, z); updatePos(camFront, front); var camCross:Vector3D = camFront.crossProduct(Vector3D.Y_AXIS); updatePos(camCross, cross); var camUp:Vector3D = camCross.crossProduct(camFront); updatePos(camUp, up); view = lookAt(camPos, camPos.add(camFront), Vector3D.Y_AXIS); displayParams(); } private function updatePos(vector:Vector3D, scale:int):void { vector.normalize(); if (scale == 0) return; var v:Vector3D = vector.clone(); v.scaleBy(scale * 0.1); camPos = camPos.add(v); } private function displayParams():void { tfParams.text = StringUtil.substitute( "Pos:{0} {1} {2}\nPitch:{3} Yaw:{4}", camPos.x.toFixed(1), camPos.y.toFixed(1), camPos.z.toFixed(1), camPitch, camYaw); } 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; } } } }}