http://www.adobe.com/cn/devnet/flashplayer/articles/3d-cameras.html
介绍
这篇教程是对使用3d cameras的介绍,一个3d cameras 可以让开发者创建一个在3d场景中漫游的应用。在本教程中描述了编写一个以第一视角在3d场景中漫游的简单程序。
使用3d cameras
为了更好的解理3d cameras,设想你在拍一部电影。你必须建立一个场景并且需要一个camera。为了得到连接的镜头,你需要带着cameras在场景中漫步,从不同的角度和观察点拍下场景中的物体。
这与使用3d cameras是相同的拍摄过程。你需要一个虚拟的相机漫步于虚拟的场景中。
在观看世界时有两种流行的拍摄方法,一种是通过一个角色的眼睛(也就是第一视角),一种是把摄像机定在一个位置保持所有物体可见(也就是第三视角)
对3d cameras的基本作用:可以用于漫游于3d场景中并且在一个具体的视角渲染出连续的画面。
理解世界空间和观察空间
需要实现这种行为:你将渲染位于3d cameras观察点看到的所有3d世界中的物体,并不仅仅是世界坐标系的观察点,或其它观察点。
一般来过,一个3d场景包含一系列的3d模型,模型是由一系列的结点和三角形相对于它们自己的坐标系定义的。定义模型的空间叫做模型空间。
把模型放在3d场景中后,你可以用世界坐标转换矩阵对它他的结点进行转换。每一个物体有它们自己的坐标矩阵来说明他们的位置和方向。
这个新的参照系统被称作世界空间或全局空间,一个简单的方式去控制他就是通过变换矩阵关联每个物体。
为了实现3d cameras的行为,你必须按照以下步骤,你要参照世界坐标系统而不3d cameras自身的。
对待3d cameras的一个很好的方式就是把看成一个真实的3d物体,像其它3d物体一样,你使用世界坐标变换矩阵把3d cameras放在你期望的位置和期望的朝向。这个世界坐标转换矩阵把camera的方向期望的沿z轴角度转到实际的在世界中的位置。
图1展示了世界坐标系 (x, y, z) 和view视口坐标系 (camera)(x', y', z')间的关系
图1 世界坐标系与视口坐标系关系
现在你可能好奇一旦你增加一个3D cameras 到方程式中,之前教程(Working with Stage3D and perspective projection)说的投影变换矩阵,会发生什么。它的工作方式是这样的,你仍可以应用你最后的投影变换,因此,如果你要在3D cameras 的视点去渲染你的3d场景,你之前要应用3D cameras 的视口坐标变换,之后才能用投影变换。
因此,全部应用在3d场景里的3d模型的转换像这样。
model space -> world space
world space -> view space
view space -> projection space
3D camera 转换
在这部分你将学到如何加速世界坐标到视口坐标的转换
用/camera的世界转换矩阵,把camera从世界原点的位置和它看上去的角度变换到3d实际的位置和角度。
设想你如同使用一个矩阵的属性一样使用转换。
protected var cameraWorldTransform:Matrix3D = new Matrix3D();
你可以通过改变矩阵来设置相机的位置。
cameraWorldTransform.appendRotation(20, Vector3D.Y_AXIS);
cameraWorldTransform.appendTranslation(2, 3, 5);
最后,为了把物体转换成他们从观察点看到的那样,你需要对camera的世界坐标矩阵反转。
viewTransform = cameraWorldTransform.clone()
viewTransform.invert();
之后,当你渲染每个物体时,仅仅是将viewTransform前乘每一个物体的worldTransform。
建立一个 3D camera的应用程序
在这个小节,你将以创建一个简单的有漫游3d场景的3D camera程序。我会以 Working with Stage3D and perspective projection.中的教学代码开始。
一个camera键盘控制器
恰当处理 3D camera控制的过程并不像看起来的那么简单。一个好的 3D camera应该显得很自然。一个 3D camera不应该挡住用户的路。它应该感觉非常自然而忘了他的存在。
有太多的方法实现 3D camera控制器代码。控制一个 3D camera,可以如同严格控制相机每一步一样简单,通过限制用户按键时固定通过场景物体的数量。或者控制一个 3D camera,它可以附加一个风吹的物理系统并包括物体碰撞检测系统。
例子中解释了如何建一个简单的 3D camera 控制器,它可以使用恒定的加速度和一些减速来控制基于键盘交互的 3D camera。首先,你要先写一些代码还转换和旋转camera当用户按键时。以定义恒定的camera加速度开始,然后计算camera的周期来设置位置和角度。
protected const MAX_FORWARD_VELOCITY:Number = 0.05;
protected const MAX_ROTATION_VELOCITY:Number = 0.5;
protected const LINEAR_ACCELERATION:Number = 0.0005;
protected const ROTATION_ACCELERATION:Number = 0.01;
protected const DAMPING:Number = 1.09;
...
stage.addEventListener( KeyboardEvent.KEY_DOWN, keyDownEventHandler );
stage.addEventListener( KeyboardEvent.KEY_UP, keyUpEventHandler );
...
protected function keyDownEventHandler(e:KeyboardEvent):void
{
switch (e.keyCode)
{
case 37: // left arrow
cameraRotationAcceleration = -ROTATION_ACCELERATION;
break
case 38: // up arrow
cameraLinearAcceleration = LINEAR_ACCELERATION;
break
case 39: // right arrow
cameraRotationAcceleration = ROTATION_ACCELERATION;
break;
case 40: // down arrow
cameraLinearAcceleration = -LINEAR_ACCELERATION;
break;
}
}
protected function keyUpEventHandler(e:KeyboardEvent):void
{
switch (e.keyCode)
{
case 37: // left arrow
case 39: // right arrow
cameraRotationAcceleration = 0;
break
case 38: // up arrow
case 40: // down arrow
cameraLinearAcceleration = 0;
break
}
}
基于键盘的输入,上面的两个键盘事件处理函数简单的设置了线性和角度的加速度。这些加速度一会在updateViewMatrix函数里用来计算计算位置和旋转角度。
在这个例子中,用户按左和右方向来旋转camera。 3D camera的向上的轴一直指向上方,也就是说,camera将垂直的放在那指向前方。然后旋转camera会使它绕y轴转。updateViewMatrix 函数会以当前点作为注册点应用之个旋转角度。
当用户按向上和向下箭头时,可以把camera向前和向后移。现在这个camera在应用世界转换坐标矩阵之前会一直指向z轴,因此,在camera自身的坐标系中,整体向前的向量是(0,0,1)。因此camera向前周期的矢量仍在它本身的坐标系中,像这样(0, 0, forwardVelocity)。
updateViewMatrix函数计算它的位置,简单的通过将这个向前的周期矢量转换到世界坐标系中。
protected function updateViewMatrix():void
{
cameraLinearVelocity.z = calculateUpdatedVelocity(cameraLinearVelocity.z, cameraLinearAcceleration, MAX_FORWARD_VELOCITY);
cameraRotationVelocity = calculateUpdatedVelocity(cameraRotationVelocity, cameraRotationAcceleration, MAX_ROTATION_VELOCITY);
cameraWorldTransform.appendRotation(cameraRotationVelocity, Vector3D.Y_AXIS, cameraWorldTransform.position);
cameraWorldTransform.position = cameraWorldTransform.transformVector(cameraLinearVelocity);
viewTransform.copyFrom(cameraWorldTransform);
viewTransform.invert();
}
由于viewTransform作为cameraWorldTransform的逆函数,所以updateViewMatrix 函数也是3D camera魔法发生的地方,
下面的calculateUpdatedVelocity 函数简单的计算出以现在加速度开始更新的周期。
protected function calculateUpdatedVelocity(curVelocity:Number, curAcceleration:Number, maxVelocity:Number):Number
{
var newVelocity:Number;
if (curAcceleration != 0)
{
newVelocity = curVelocity + curAcceleration;
if (newVelocity > maxVelocity)
{
newVelocity = maxVelocity;
}
else if (newVelocity < -maxVelocity)
{
newVelocity = - maxVelocity;
}
}
else
{
newVelocity = curVelocity / DAMPING;
}
return newVelocity;
}
camera渲染
在开始控制之后,处理渲染的过程非常简单。在每一进行渲染之前,你将调用updateViewMatrix。
然后像这样
protected function onRender(e:Event):void
{
...
updateViewMatrix();
var m:Matrix3D = new Matrix3D();
m.appendRotation(getTimer()/30, Vector3D.Y_AXIS);
m.appendRotation(getTimer()/10, Vector3D.X_AXIS);
m.appendTranslation(0, 0, 2);
m.append(viewTransform);
m.append(projectionTransform);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
...
}
全部原代码看原文章