话说,这个月的游戏坑掉了,都是因为看了好多书的说
3D数学基础:图形与游戏开发,DirectX_9.0_3D游戏开发编程基础,C++ Primer
争取下个月给力些吧~
进入整体,在stage3D中实现一个相机. 3D的相机如果不做复杂的室内相机(避免穿越到墙壁外部)的话. 真是比2D相机好简单多呢.
在3D中,相机就是一个向量. 因此我们需要2个值, 相机的位置 以及 相机的朝向.
在stage3D中,表示一个向量或是坐标,都可以使用Matrix3D这个类.我们在创建相机的时候,通过appendTranslate来设置位置
var camera : Matrix3D= new Matrix3D();
camera.appendTranslate(0,0,0);
之后,我们通过设置相机的朝向,来确定相机这个向量.
camera.pointAt(目标位置(Vector3D类型),世界坐标系中的前方(Vector3D类型),世界坐标系中的上方(Vector3D类型);
stage3D中,一般约定使用右手坐标系,因此 前方 就是 Z轴为负的向量. 上方 无论右手还是左手坐标系 都是 Y轴为正的向量.
那么如果我们要看一个位置为 0,0,-10 的方向.可以这么设置
camera.pointAt(new Vector3D(0,0,-10), new Vector3D(0,0,1), new Vector3D(0,1,0));
通过上面几个步骤,3D摄像机就基本设置完毕了. 但是有一个很重要的地方. 在3D世界中,假设你让一个物体往左边移动,本质并不是物体往左边移动,而是整个世界往右边移动了.
作为相机,必须与世界反向.
所以之前所有的属性都必须为反向,这样,当我们反转相机之后,值才正确.
那么相机的pointAt中的 朝向和上方都要写反值,坐标也要取反
camera.pointAt(new Vector3D(0,0,-10), new Vector3D(0,0,-1), new Vector3D(0,-1,0));
最后在渲染矩阵的时候,然如下顺序添加个矩阵,即可
finalMatrix.append(模型);
finalMatrix.append(相机);
finalMatrix.append(世界);
finalMatrix.append(屏幕投影);
下面是一个相机的Demo : http://www.dreamfairy.cn/blog/work/flash/3d/stage3dCamera/CubeCamera.html
W,S,A,D来控制相机瞄准的飞船移动
方向键来控制相机的移动
接下来是源码:
CubeMesh.as 正方体网格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | package C3 { import flash.display3D.Context3D; import flash.display3D.Context3DProgramType; import flash.display3D.Context3DVertexBufferFormat; import flash.display3D.IndexBuffer3D; import flash.display3D.Program3D; import flash.display3D.VertexBuffer3D; import flash.geom.Matrix3D; import flash.geom.Vector3D; public class CubeMesh { private var m_matrix : Matrix3D = new Matrix3D(); private var m_transform : Matrix3D = new Matrix3D(); private var m_context3D : Context3D; private var m_vertexBuffer : VertexBuffer3D; private var m_indexBuffer : IndexBuffer3D; private var m_cubeVertex : Vector.<Number>; private var m_cubeIndex : Vector.<uint>; private var m_pos : Vector3D = new Vector3D(); private var m_rotate : Vector3D = new Vector3D(); private var m_needUpdateTransform : Boolean = false; public function CubeMesh(context3D : Context3D) { m_context3D = context3D; setup(); } public function render(view : Matrix3D, proj : Matrix3D, shader : Program3D) : void { updateTransform(); m_matrix.identity(); m_matrix.append(m_transform); m_matrix.append(view); m_matrix.append(proj); m_context3D.setProgram(shader); m_context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m_matrix, true); m_context3D.setVertexBufferAt(0,m_vertexBuffer,0,Context3DVertexBufferFormat.FLOAT_3); m_context3D.drawTriangles(m_indexBuffer,0,m_cubeIndex.length / 3); m_context3D.setVertexBufferAt(0,null); m_context3D.setVertexBufferAt(1,null); } public function updateTransform() : void { if(!m_needUpdateTransform) return; m_transform.identity(); m_transform.appendRotation(m_rotate.x, Vector3D.X_AXIS); m_transform.appendRotation(m_rotate.y, Vector3D.Y_AXIS); m_transform.appendRotation(m_rotate.z, Vector3D.Z_AXIS); m_transform.appendTranslation(m_pos.x,m_pos.y,m_pos.z); } public function moveTo(x : Number, y : Number, z : Number) : void { m_pos.x = x; m_pos.y = y; m_pos.z = z; m_needUpdateTransform = true; } public function rotation(value : Number, axis : Vector3D) : void { switch(axis){ case Vector3D.X_AXIS: m_rotate.x = value; break; case Vector3D.Y_AXIS: m_rotate.y = value; break; case Vector3D.Z_AXIS: m_rotate.z = value; break; } m_needUpdateTransform = true; } public function move(x : Number, y : Number, z : Number) : void { m_pos.x += x; m_pos.y += y; m_pos.z += z; m_needUpdateTransform = true; } public function get position() : Vector3D { return m_transform.position; } private function setup() : void { m_cubeVertex = new Vector.<Number>(); m_cubeVertex.push(-1,-1,-1); m_cubeVertex.push(-1,1,-1); m_cubeVertex.push(1,1,-1); m_cubeVertex.push(1,-1,-1); m_cubeVertex.push(-1,-1,1); m_cubeVertex.push(-1,1,1); m_cubeVertex.push(1,1,1); m_cubeVertex.push(1,-1,1); m_cubeIndex = new Vector.<uint>(); m_cubeIndex.push(0,1,2); m_cubeIndex.push(0,2,3); m_cubeIndex.push(4,6,5); m_cubeIndex.push(4,7,6); m_cubeIndex.push(4,5,1); m_cubeIndex.push(4,1,0); m_cubeIndex.push(3,2,6); m_cubeIndex.push(3,6,7); m_cubeIndex.push(1,5,6); m_cubeIndex.push(1,6,2); m_cubeIndex.push(4,0,3); m_cubeIndex.push(4,3,7); m_vertexBuffer = m_context3D.createVertexBuffer(m_cubeVertex.length / 3, 3); m_vertexBuffer.uploadFromVector(m_cubeVertex,0,m_cubeVertex.length / 3); m_indexBuffer = m_context3D.createIndexBuffer(m_cubeIndex.length); m_indexBuffer.uploadFromVector(m_cubeIndex,0,m_cubeIndex.length); } } } |
文档类
CubeCamera.as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | package C3 { import com.adobe.utils.AGALMiniAssembler; import com.adobe.utils.PerspectiveMatrix3D; import flash.display.Sprite; import flash.display.Stage3D; import flash.display3D.Context3D; import flash.display3D.Context3DProgramType; import flash.display3D.Program3D; import flash.events.Event; import flash.events.KeyboardEvent; import flash.geom.Matrix3D; import flash.geom.Vector3D; import flash.text.TextField; import flash.ui.Keyboard; [SWF(width="640",height="480",frameRate="60")] public class CubeCamera extends Sprite { public function CubeCamera() { stage ? init() : addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null) : void { stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContextCreate); stage.stage3Ds[0].requestContext3D(); var tf : TextField = new TextField(); tf.textColor = 0xffffff; tf.width = 300; tf.text = "W,S,A,D 控制飞船移动n方向键控制相机移动"; addChild(tf); } private function onContextCreate(e:Event) : void { if(hasEventListener(Event.ENTER_FRAME)) removeEventListener(Event.ENTER_FRAME, onEnter); m_context = (e.target as Stage3D).context3D; m_context.configureBackBuffer(stage.stageWidth,stage.stageHeight,2,true); m_context.enableErrorChecking = true; setup(); addEventListener(Event.ENTER_FRAME, onEnter); stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); } private function onKeyUp(e:KeyboardEvent) : void { delete m_key[e.keyCode]; } private function onKeyDown(e:KeyboardEvent) : void { m_key[e.keyCode] = true; } private function setup() : void { var count : uint = 30; for(var i : int = 0; i < count ; i++) { var cubeMesh : CubeMesh = new CubeMesh(m_context); cubeMesh.moveTo(Math.random() * -count, Math.random() * -count, Math.random() * -count); m_cubeList.push(cubeMesh); } m_teapotMesh = new TeapotMesh(m_context); m_teapotMesh.moveTo(0,0,0); m_teapotMesh.rotation(-90,Vector3D.Z_AXIS); // m_teapotMesh.rotation(90, Vector3D.X_AXIS); m_shader = m_context.createProgram(); var vertexShader : AGALMiniAssembler = new AGALMiniAssembler(); vertexShader.assemble(Context3DProgramType.VERTEX, [ "m44 op, va0, vc0", "mov v0, va0", "mov v1, va1", ].join("n")); var fragmentShader : AGALMiniAssembler = new AGALMiniAssembler(); fragmentShader.assemble(Context3DProgramType.FRAGMENT, [ "tex ft0, v1, fc0<2d,wrap,linear>", "mov oc, ft0", ].join("n")); m_shader.upload(vertexShader.agalcode, fragmentShader.agalcode); m_shaderNoTexture = m_context.createProgram(); vertexShader = new AGALMiniAssembler(); vertexShader.assemble(Context3DProgramType.VERTEX, [ "m44 op, va0, vc0", "mov v0, va0", ].join("n")); fragmentShader = new AGALMiniAssembler(); fragmentShader.assemble(Context3DProgramType.FRAGMENT, [ "mov oc, v0", ].join("n")); m_shaderNoTexture.upload(vertexShader.agalcode, fragmentShader.agalcode); m_proj.identity(); m_proj.perspectiveFieldOfViewRH(45,stage.stageWidth / stage.stageHeight, 0.001, 1000); m_viewMatrix.appendTranslation(0,0,10); } private function onEnter(e:Event) : void { m_context.clear(); renderScene(); renderKeyBoard(); m_context.present(); } private var n : Number = 0; private function renderScene() : void { n += .01; //相机上下浮动 // m_viewMatrix.appendTranslation(0,Math.sin(y) / 10,0); m_viewMatrix.pointAt(m_teapotMesh.position, CAM_FACING, CAM_UP); m_camera = m_viewMatrix.clone(); m_camera.invert(); //矩形做自转运动 m_cubeList[0].rotation(n * 33.3,Vector3D.Y_AXIS); for each(var cubeMesh : CubeMesh in m_cubeList) { cubeMesh.render(m_camera,m_proj,m_shaderNoTexture); } m_teapotMesh.render(m_camera,m_proj,m_shader); } private function renderKeyBoard() : void { var speed : Number = .5; if(m_key[37]) m_viewMatrix.appendTranslation(-speed,0,0); if(m_key[38]) m_viewMatrix.appendTranslation(0,0,-speed); if(m_key[39]) m_viewMatrix.appendTranslation(speed,0,0); if(m_key[40]) m_viewMatrix.appendTranslation(0,0,speed); if(m_key[Keyboard.A]){ m_teapotMesh.move(-speed,0,0); } if(m_key[Keyboard.D]){ m_teapotMesh.move(speed,0,0); } if(m_key[Keyboard.W]){ m_teapotMesh.move(0,speed,0); } if(m_key[Keyboard.S]){ m_teapotMesh.move(0,-speed,0); } } private static const CAM_FACING:Vector3D = new Vector3D(0, 0, -1); private static const CAM_UP:Vector3D = new Vector3D(0, -1, 0); private var m_teapotMesh : TeapotMesh; private var m_cubeList : Vector.<CubeMesh> = new Vector.<CubeMesh>(); private var m_context : Context3D; private var m_shader : Program3D; private var m_shaderNoTexture : Program3D; private var m_key : Object = new Object(); private var m_proj : PerspectiveMatrix3D = new PerspectiveMatrix3D(); private var m_viewMatrix : Matrix3D = new Matrix3D(); private var m_camera : Matrix3D; } } |