XNA学习笔记——相机设置

相机这部分比想象当中要难缠。现在也不是特别清楚,只是根据教程XNARecipes中第二章的2、3两节做一些必要的记录。

 

最简单的例子:相机在初始位置,绕着Up向量

相机在(0,0,0)初始坐标,朝(0,0,-1) Forward方向观察,以默认的(0,1,0) Up向量作为向上方向。在这个情况中,可以使用以下代码:

   1: Vector3 cameraPosition = new Vector3(0, 0, 0); 
   2: Vector3 cameraTarget = new Vector3(0, 0, -1); 
   3: Vector3 cameraUpVector = new Vector3(0, 1, 0);
   4:  
   5: viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraTarget, cameraUpVector);

Vector3 direction = camaraTarget – cameraPosition = (0, 0, -1)
这一句虽然在这里很显然,但之后的很多问题就是跟这个direction有关。

如果创建一个绕Up向量旋转45度的View矩阵。假设头就是相机,只要向右旋转45度(向右看)。当计算新View矩阵时,Position向量和Up向量保持不变,但Target向量变了。可以通过将使用45度旋转“转换”默认的(0,0,-1) Target向量获取新Target向量。这意味着新的Target向量是初始Target向量的旋转版本。下面是代码:

   1: Matrix cameraRotation = Matrix.CreateRotationY(MathHelper.PiOver4);
   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:  
   6: Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation); 
   7: viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraRotatedTarget, cameraUpVector);

由于Position没变,那么Vector3 direction = camaraTarget – cameraPosition 不再是 (0, 0, -1)。
也就是你把头转过去看旁边的东西了,而不再是正前方的某个东西

 

第二个例子:相机在初始位置,任意旋转

现在进一步来看。你想使相机绕着任意轴旋转而不是绕着Up向量。例如,绕着(1,0,0) Right轴旋转45度,假设头就是相机,这就相当于抬起头45度看天空。和前面一个例子一样,Target向量会变化,Position向量保持不变。

但是这种情况中Up向量会发生变化(头仰起了嘛!)。在前面的例子中你将头部转向右边,Up向量并不会变化。这个例子中,将头部向上旋转,Up向量和Target向量都要发生改变。

变换Up向量和变换Target向量的方法是一样的:通过旋转矩阵变换初始Up向量获取新的Up向量。下面是代码:

   1: Matrix cameraRotation = Matrix.CreateRotationX(MathHelper.PiOver4);
   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:  
   6: Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation); 
   7: Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation); 
   8: viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraRotatedTarget, cameraRotatedUpVector);

这里的“任意”旋转矩阵只是一个简单绕x轴的旋转。这个代码也可以处理任何旋转,例如下面的这个情况,它组合了三根轴上的旋转。下面的代码生成一个矩阵,这个矩阵是绕z轴–45度和y轴22.5度,x轴90度旋转的组合:

   1: Matrix cameraRotation = Matrix.CreateRotationX(MathHelper.PiOver2)* Matrix.CreateRotationY(MathHelper.Pi/8.0f)* Matrix.CreateRotationZ(-MathHelper.PiOver4);

但这时要小心了,别把脖子扭了。
Vector3 direction = camaraTarget – cameraPosition 不是 (0, 0, -1)。为什么强调这个direction,虽然到现在为止还体现不出什么,因为没有涉及到移动。这也是刚开始看教程时,容易忽略的一点,以至于看到后面糊涂了。

这里要说明一点:顺时针转是正,逆时针转是负。还有从人的视觉出发,只要Up向量大致朝上,物体是不会颠倒的。这也是后面Quake式相机只有左右和上下的旋转。也就是抬头,低头,看左,看右,没有歪着脖子的。

 

第三个例子:相机在指定位置,任意旋转

对于这个例子,教程上的解释不大明白。特别是按照前两个例子的顺序学下来。
现在必须要有一个direction,方向。先看代码:

   1: Matrix cameraRotation =Matrix.CreateRotationX(MathHelper.PiOver2)*  Matrix.CreateRotationY(MathHelper.Pi/8.0f)*Matrix.CreateRotationZ(-MathHelper.PiOver4); 
   2: Vector3 cameraPosition = new Vector3(10, 20, 30); 
   3: Vector3 cameraOriginalTarget = new Vector3(0, 0, -1); 
   4: Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
   5:  
   6: Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
   7: Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget;
   8:  
   9: Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);
  10: Vector3 cameraFinalUpVector = cameraPosition + cameraRotatedUpVector;
  11:  
  12: viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraFinalUpVector);

Position是在位置(10,20,30)。代码中有一个cameraOriginalTarget,注意这个Target不是一个点,而是一个矢量方向。为什么呢?一般来讲,设置观察矩阵,需要一个视点。假如cameraOriginalTarget代表的是一个点,那么direction = (-10,-20,-31)。因为对于前两个例子,(0,0,-1)既可以表示视点,也可以表示方向(Position在初始位置)。所以当看到Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation); 的时候,也能够理解,视点的位置从(0,0,-1)变成了(x,y,z),方向也从(0,0,-1)改变到(x,y,z)。

但在这个例子中,怎么理解这两行:

   1: Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
   2: Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget;

为什么会有cameraRotatedTarget还有cameraFinalTarget。direction=cameraFinalTarget – cameraPosition = cameraRotatedTarget

cameraRotatedTarget是由cameraOriginalTarget变换过来的。我们知道如果cameraOriginalTarget是视点的话,那么初始的方向是
direction =cameraOriginalTarget -  cameraPosition =(-10,-20,-31)。 变换的时候Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation); cameraOriginalTarget参数所在的位置应该是(-10,-20,-31)才对。

从上面的反证中,可以得出结论,cameraOriginalTarget代表一个方向,不代表视点。不像前两个例子中,cameraOriginalTarget既是视点,又是方向。理解了这个,对于 cameraRotatedUpVector和cameraFinalUpVector也能理解了。

 

到这里,看第二节教程所带的源代码,才能看明白。特别是自己写的时候,出现问题时也能够知道是哪里出了问题。下面是自己写的代码

   1: protected override void Initialize()
   2: {
   3:     // TODO: Add your initialization logic her
   4:     moveSpeed = 0.02f;
   5:  
   6:     float fov = MathHelper.PiOver4;
   7:     float aspect = GraphicsDevice.DisplayMode.AspectRatio;
   8:     float nearClip = 0.5f;
   9:     float farClip = 100.0f;
  10:     projMat = Matrix.CreatePerspectiveFieldOfView(fov, aspect, nearClip, farClip);
  11:  
  12:     camPosition = new Vector3(30, 30, 30);
  13:     cameraRotation = Matrix.CreateRotationX(-MathHelper.Pi / 8.0f) * Matrix.CreateRotationY(-MathHelper.Pi / 8.0f);
  14:     UpadteViewMatrix();
  15:     base.Initialize();
  16: }

先是Initialize(),设置好投影矩阵,相机的位置,旋转的角度

   1: private void UpadteViewMatrix()
   2: {
   3:     Vector3 originalForward = new Vector3(-1.7f, -1, -1);
   4:     Vector3 originalUp = new Vector3(0, 1, 0);
   5:  
   6:     Vector3 rotatedForward = Vector3.Transform(originalForward, cameraRotation);
   7:     Vector3 rotatedUp = Vector3.Transform(originalUp, cameraRotation);
   8:  
   9:     Vector3 finalLook = camPosition + rotatedForward;
  10:  
  11:     viewMat = Matrix.CreateLookAt(camPosition, finalLook, rotatedUp);
  12: }

这里直接将originalTarget这样容易混淆的名字改成originalForward,而且是(-1.7f,-1,-1),旋转变换之后差不多就是(-1,-1,-1)的方向,也。因为相机的初始位置是(30,30,30),而我的观察方向是要看向坐标源点。

   1: private void MoveCameraPosition()
   2: {
   3:     Vector3 originalForward = new Vector3(-1.7f, -1, -1);
   4:     Vector3 rotatedForward = Vector3.Transform(originalForward, cameraRotation);
   5:     camPosition += moveSpeed * rotatedForward;
   6:  
   7:     UpadteViewMatrix();
   8:  
   9: }

这里camPosition也是朝着源点向前移动变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值