[翻译]XNA 3.0 Game Programming Recipes之two
PS:自己翻译的,转载请著明出处
2-2.指定你的摄象机的目标
问题
当您确定您的浏览矩阵,其中一个特点您需要指定的目标向量。 这一矢量设置了你的摄象机的旋转,可提供具有挑战性的。
解决方案
当旋转摄像头,摄象机的位置是不变的。摄象机的位置和观察目标被浏览矩阵所指定而且浏览矩阵是基于摄象机的位置,观察目标
它的上部,旋转的实现是靠改变摄象机目标的点和摄象机的上部向量方向。你可以发现目标向量你可以找到目标向量,采取通常的(0,0,-1)
转变向量和运用您的旋转这一向量,这将导致新的摄象机的目标点。可以用相同的方法得到上部向量。
如何工作的
摄象机在它被定义需要它的位置,观察目标和上部向量。在3D空间内如果你想在一个固定的点上旋转你的摄象机,位置向量必须保持
不变。但是观察目标向量和上部向量是可以变化的。
鉴于转角围绕三个坐标系,一个办法是手动计算目标位置。但是,导致非常复杂的计算,而更简便和更快速的方法是可行的。
最简单的例子:相机在初始地,向上旋转向量
让我们来看看这个坐标系摄象机的位置在(0,0,0).摄象机朝向(0,0,-1)的方向默认的上部矢量是(0,1,0).在这种情况下,可以得到
以下代码:
2 Vector3 cameraTarget=new Vector3(0,0,-1);
3 Vector3 cameraUpVector=new Vector3(0,1,0);
4 viewMatrix=Matrix.CreateLookAt(cameraPosition,cameraTarget,cameraUpVector);
换句话说浏览矩阵和上部矢量保持旋转角度是45度。假设你的头是一个摄象机,这将导致把你的头右侧的45度。当计算新的浏览矩阵,你的位置向量和上部向量需要被保持不变,但是你需要找出你的新目标观察向量。你可以找到观察目标向量靠"转换"这个默认(0,0,-1)用45度的旋转目标向量。也就是说你将会发现的向量是把初始观察目标向量旋转后的版本。下面是你需要的代码:
2 Vector3 cameraPosition=new Vector3(0,0,0);
3 Vector3 cameraUpVector=new Vector3(0,1,0);
4 Vector3 cameraOriginalTarget=new Vector3(0,0,-1);
5 Vector3 cameraRotatedTarget=Vector3.Transform(cameraOriginalTarget,cameraRotation);
6 viewMatix=Matrix.CreateLookAt(cameraPosition,cameraRotatedTarget,cameraUpVector);
注意 矩阵是一个强大的对象,可以代表任何类型的转变。矩阵可以代表旋转,平移,缩放,或这些变化的任何组合。您可以找到更
多的例子4-2 。
第一行创建一个矩阵围绕上部坐标旋转45度,相当于1/4的弧度。第2行到结束用旋转矩阵转换你初始(0,0,-1)目标向量和保存
旋转过的目标向量到cameraRotatedTarget变量中,这个变量常用来创建一个新的浏览矩阵。
注意:这一转变是什么神奇的,它的增殖在向量和一个矩阵之间,简单归结为16乘以12这么普通的数字之间的运算。
第二个例子:照相机在原地任意旋转
现在,让我来看下这个例子有一点复杂。在上部向量方向旋转你的摄象机,你可以在任意的坐标轴
旋转摄象机。一般不用到这个例子,让我围绕(1,0,0)右边的向量旋转45度。假设你的头是个摄象机,这将导致向上看45度。
因为你仅仅只旋转了你的摄象机,摄象机的位置还是不会变。在前面例子中的目标向量会改变,这是因为摄象机需要朝向
不同的点。
这种情况下,虽然,上部向量将会改变。在上面例子里把你的头转向右边,不会改变头部向上的坐标系。现在这个例子,
当你移动你的头向上看时,你头部向上的向量和观察目标都会改变。
您最多转化向量是一样的前向量:您有一个存储在旋转矩阵和确定原来的向上的向量。下一步,用旋转矩阵来改变初始的向量
为了得到新的被改变的上部向量。这是你的代码:
2 Vector3 cameraPosition=new Vector3(0,0,0);
3 Vector3 cameraOriginalUpVector=new Vector3(0,1,0);
4 Vector3 cameraOriginalTarget=new Vector3(0,0,-1);
5 Vector3 cameraRotatedTarget=Vector3.Transform(cameraOriginalTarget,cameraRotation);
6 Vector3 cameraRotatedUpVector=Vector3.Transform(cameraOriginalUpVector,cameraRotation);
7 viewMatrix =Matrix.CreateLookAt(cameraPosition,cameraRotatedTarget,cameraRotatedUpVector);
在这里,“任意”旋转矩阵只是一个简单旋转于X轴,让您仍然能够很容易想象它。相同的代码,但是,能够处理任何旋转,如
下面的一个,它结合了旋转于三坐标系。下面的代码生成一个矩阵,结合旋转-45度围绕着Z -轴(相机逆时针旋转) ,
围绕Y轴旋转22.5度(旋转摄像头的左侧) ,X轴旋转90度(相机向下旋转) :
摄象机的位置始终不变,你必须找出你的摄象机的上部向量和旋转后的最终版本。
第三个例子:照相机在指定点,任意旋转
一般情况下,你需要设置一个在摄象机上任意的旋转和指定在3D场景中一个固定点的摄象机的位置,假设你的摄象机的位置在3D
场景的位置是(10,20,30)点,并没有旋转。很简单,你摄象机的位置向量可能是(10,20,30)
没有旋转,你要的摄象机朝向(0,0,-1)的方向。
注意:请记住,您必须指定目标点,而不是目标的方向!说明(0,0 ,-1) 为目标向量将是错误的,因为这会使您的相机总是看(0,0 ,-1)
点。想象一下,后来您想要移动到您的相机( -10,20,30 )点,例如。如果您仍
指定(0,0,-1)为目标向量,相机仍然会朝(0,0,-1)点,因此摄象机的朝向希望也会变更!
为了使相机的位置(10,20,30)朝向(0,0 ,-1)的方向,您需要指定(10,20,29)为目标向量。你可以找到这个向量总结您的摄像机的位置
目标方向,象这样的:
2 Vector3 cameraOriginalTarget=new Vertor3(0,0,-1);
3 cameraTargetPoint=cameraPosition+cameraOriginalTarget;
现在,是把所有东西整合在一起了。你会定义一个在(10,20,30)点位置任意旋转的摄象机。摄象机的位置一直都是(10,20,30)
为了得到目标点,你要再一次从(0,0,-1)这个朝向开始。在旋转应用于摄象机上之后可以找到新的朝向,用旋转矩阵来改变它。
最后,摄象机在(10,20,30)的位置上将朝向旋转后方向的目标向量。你需要增加(10,20,30)到这个旋转方向.同样上部向量也是用
想同的方法得到。代码如下:
2 Vector3 cameraPosition=new Vector3(10,20,30);
3 Vector3 cameraOriginalUpVector=new Vector3(0,1,0);
4 Vector3 cameraOriginalTarget=new Vector3(0,0,-1);
5 Vector3 cameraRotatedTarget=Vector3.Transform(cameraOriginalTarget,cameraRotation);
6 Vector3 cameraFinalTarget=cameraPostion+cameraRotatedTarget;
7 Vector3 cameraRotatedUpVector=Vector3.Transform(cameraOriginalUpVector,cameraRotation);
8 Vector3 cameraFinalUpVector=cameraPosition+cameraRotatedUpVector;
9 viewMatrix=Matrix.createLookAt(cameraPosition,cameraFinalTarget,cameraFinalUpVector);
现在,你有摄像头的位置上你想寻找到正确的方向,移动摄象机的朝向又是一个新的挑战。
如果您希望相机向前进,只需添加(0,0,-1)方向向量到位置向量将不会工作,因为您必须先找出相对的旋转摄像头前进向量。
你可以这样处理这第一个例子了用旋转的矩阵改变(0,0,-1)的朝向。一旦你做了这些,只需简单添加位置向量:
2 Vector3 cameraOriginalForward=new Vector3(0,0,-1);
3 Vector3 cameraRotatedForward=Vector3.Transform(cameraOriginalForward,cameraRotation);
4 cameraPosition+=moveSpeed*cameraRotatedForward;
改变moveSpeed的值将使你的摄象机的移动增加或者减少,这是因为这个值乘以被旋转过的方向。
同样的方法使你的摄象机向侧面移动。而不是从(0,0,-1)前进向量,你开始与(1,0,0)的右部向量,而这又是第一
需要改变,让您得到右部分的相对于目前的摄像机的旋转向
代码
这种方法,您的相机需要跟踪只有其目前的位置和旋转。只要其中任何变化视图矩阵将需要被更新。由于用户的输入导致这
些变化,在2-3和2-4节你会发现2个详细的方法。当每一个矩阵需要初始化,首先要设置cameraRotation矩阵为Identity矩阵,这是
单位元素的乘法矩阵。
选择坐标系统
该向量的前(0,0,-1)和上(0,1,0)的方向是以前使用的“官方”的XNA向量这些用法同样作为Vector3.Forward和Vector3.Up捷径。
尽管他们只有一个协订;如果你想用,可以定义一个完全不同坐标系在你的应用程序上。比如把(0,0,1)做为上,而(0,1,0)做为前的方向,
(1,0,0)作为右的方向,归根到底是你为你的项目决定自己的坐标系。
但是,有一个规则的三个载体必须遵守。在XNA,X,Y,Z坐标系是右手坐标系统,这句话的意思是一旦你知道2个坐标系,你可以
找到第3个坐标系的方向。延出您的拇指和右手的食指。下一步,您中指弯曲为90度,它与你的中指和拇指垂直相交。现在,想象
一下你3个指头是你的坐标系统。如果你会使用了右手坐标系方法,那么你的拇指是你图坐标的X轴,右手食指是你的Y轴,中指是你的Z
轴
这里为轴线中所描述的第一段,这里对应的是你的拇指指向右你的中指指向上。在XNA"官方"坐标系,保持你的拇指向右,中指向
上,和你的食指向背后。所以这就是为什么在(0,0,-1)有减号的原因。