• Directx11学习笔记【十九】 摄像机的实现


    本文由zhangbaochong原创,转载请注明出处:http://www.cnblogs.com/zhangbaochong/p/5785100.html

      之前为了方便观察场景,我们采用的方法是鼠标控制旋转视角和镜头拉伸,但是观察点依然限制在一个球面内,目标点也始终为坐标原点。为了能够自由的从各个角度、各个位置观察场景,实现一个第一人称摄像机是必不可少的。

    1.摄像机视角矩阵推导

      摄像机在空间有着特定的位置及朝向,它所观察到的物体取决于物体与摄像机的相对位置。为了表示摄像机位置,我们可以使用一个3维向量;对于摄像机的的朝向,可以使用三个相互垂直的坐标轴的惟一地确定,即右、上、前三个方向。以摄像机为参考点,即以之为原点来观察物体。因此,视角变换,本质上即把场景中所有的物体、连同摄像机,使用相同的变换,使得变换后摄像机位于场景的原点,且其三个坐标轴(右、上、前)与世界坐标系的X、Y、Z坐标轴重合。这时,变换后的所有物体的坐标值,即变为与摄像机的相对位置了。

           我们把摄像机位置用[ px, py, pz ]来表示,其三个表示朝向的坐标轴分别表示为[ Rx, Ry, Rz ]、[ Ux, Uy, Uz ]、[ Lx, Ly, Lz ]。而视角变换的目的即把它的这些参数转换为:位置[ 0, 0, 0 ],以及三个坐标轴:[ 1, 0,0 ]、[ 0, 1, 0 ]、 [ 0, 0, 1 ]。由于有平移和旋转同时存在,因此该变换可以分为两步进行:1. 平移到原点;2. 旋转。

           平移操作很简单,即把[Px,Py, Pz,1]移回到原点,矩阵为:

           

           旋转操作需要点小技巧。我们的目的是把三个轴分别转换成[1,0,0]、[0,1,0]、[0,0,1],令旋转矩阵为M,可以表示为如下所示:

           

           由上面式子可以看出,左边的矩阵与M相乘后变为右边的单位矩阵。这正是关键所在!我们知道,一个矩阵与它的逆矩阵相乘结果为单位矩阵,因此,要求矩阵M,我们可以求它的逆矩阵。求逆矩阵需要大量的计算,有没有更好的方法?

           答案是有的!有一点需要知道,正交矩阵的逆矩阵等于它的转置矩阵。而正交矩阵的一个特点:正交矩阵的每行(每列)相互垂直。回来看下我们左边的矩阵,每行分别对应了摄像机的三个相互垂直的轴,显然它正是正交矩阵!好了,这下M的计算,就变成求它的转置矩阵了。而转置的计算再简单不过了,直接给出:

           

           现在,两步需要的矩阵都有了,那最终的视角矩阵即两次转换的乘积,当然,由于平移变换的存在,现在要在4x4矩阵了,如下所示:

           

           结果中P*R、P*U、P*L分别是位置向量与R、U、L三个向量的点积,通过查看左边的矩阵相乘很容易看出来。

           OK, 视角矩阵的推导完毕,现在我们知道:

           任一时刻,通过摄像机位置P(Px,Py,Pz),以及三个坐标轴(R,U,L),可以得到当前的视角变换矩阵:

           

    2.摄像机类的实现

      摄像机参数主要有:位置、三个坐标轴、视角矩阵、投影矩阵、生成投影矩阵的四个参数(视角大小,宽高比,近裁剪平面,远裁剪平面)。

      实现的功能比较简单,主要实现移动(前后左右移动),视角旋转(左右摇头,上下点头)。

      由于代码比较简单,故不再详细说明了:

     1 #pragma once
     2 
     3 #include <Windows.h>
     4 #include <DirectXMath.h>
     5 #include <cmath>
     6 class Camera
     7 {
     8 public:
     9     Camera();
    10 
    11     //设置摄像机位置
    12     void SetPosition(float x, float y, float z) { m_position = DirectX::XMFLOAT3(x, y, z); }
    13     void SetPosition(DirectX::FXMVECTOR pos) { DirectX::XMStoreFloat3(&m_position, pos); }
    14 
    15     //获得摄像机位置方向等相关参数
    16     DirectX::XMFLOAT3 GetPosition() const { return m_position; }
    17     DirectX::XMFLOAT3 GetRight() { return m_right; }
    18     DirectX::XMFLOAT3 GetLook() { return m_look; }
    19     DirectX::XMFLOAT3 GetUp() { return m_up; }
    20 
    21     DirectX::XMVECTOR GetPosotionXM() const { return DirectX::XMLoadFloat3(&m_position); }
    22     DirectX::XMVECTOR GetRightXM() const { return DirectX::XMLoadFloat3(&m_right); }
    23     DirectX::XMVECTOR GetLookXM() const { return DirectX::XMLoadFloat3(&m_look); }
    24     DirectX::XMVECTOR GetUpXM() const { return DirectX::XMLoadFloat3(&m_up); }
    25 
    26     //获得投影相关参数
    27     float GetNearZ() const { return m_nearZ; }
    28     float GetFarZ() const { return m_farZ; }
    29     float GetFovY() const { return m_fovY; }
    30     float GetFovX() const { return atan(m_aspect * tan(m_fovY * 0.5f)) * 2.f; }
    31     float GetAspect() const { return m_aspect; }
    32 
    33     //获得视图投影矩阵
    34     DirectX::XMMATRIX GetView() const { return DirectX::XMLoadFloat4x4(&m_view); }
    35     DirectX::XMMATRIX GetProj() const { return DirectX::XMLoadFloat4x4(&m_proj); }
    36     DirectX::XMMATRIX GetViewProj() const { return XMLoadFloat4x4(&m_view) * XMLoadFloat4x4(&m_proj); }
    37 
    38     //设置投影矩阵
    39     void SetLens(float fovY, float aspect, float nearz, float farz);
    40 
    41     //设置视角矩阵
    42     void LookAtXM(DirectX::FXMVECTOR pos, DirectX::FXMVECTOR lookAt, DirectX::FXMVECTOR worldUp);
    43     void LookAt(const DirectX::XMFLOAT3& pos, const DirectX::XMFLOAT3& lookAt, 
    44         const DirectX::XMFLOAT3& worldUp);
    45 
    46     //基本操作
    47     void Walk(float dist);            //前后行走
    48     void Strafe(float dist);            //左右平移
    49     void Pitch(float angle);            //上下点头
    50     void RotateY(float angle);        //左右摇头
    51 
    52     //更新矩阵
    53     void UpdateViewMatrix();
    54 private:
    55     DirectX::XMFLOAT3 m_right;        //位置和三个坐标轴
    56     DirectX::XMFLOAT3 m_up;
    57     DirectX::XMFLOAT3 m_look;
    58     DirectX::XMFLOAT3 m_position;
    59 
    60     float m_aspect;                    //投影相关参数
    61     float m_fovY;
    62     float m_nearZ;
    63     float m_farZ;
    64 
    65     DirectX::XMFLOAT4X4 m_view;        //视角矩阵
    66     DirectX::XMFLOAT4X4 m_proj;        //投影矩阵
    67 };
      1 #include "Camera.h"
      2 using namespace DirectX;
      3 
      4 Camera::Camera():
      5     m_position(0.f,0.f,0.f),
      6     m_look(0.f,0.f,1.f),
      7     m_up(0.f,1.f,0.f),
      8     m_right(1.f,0.f,0.f)
      9 {
     10     SetLens(0.25*XM_PI, 800.f / 600, 1.f, 1000.f);
     11 }
     12 
     13 //设置投影矩阵
     14 void Camera::SetLens(float fovY, float aspect, float nearz, float farz)
     15 {
     16     m_fovY = fovY;
     17     m_aspect = aspect;
     18     m_nearZ = nearz;
     19     m_farZ = farz;
     20     XMMATRIX P = XMMatrixPerspectiveFovLH(fovY, aspect, nearz, farz);
     21     XMStoreFloat4x4(&m_proj, P);
     22 }
     23 
     24 //设置视角矩阵
     25 void Camera::LookAtXM(DirectX::FXMVECTOR pos, DirectX::FXMVECTOR lookAt, DirectX::FXMVECTOR worldUp)
     26 {
     27     XMVECTOR look = XMVector3Normalize(lookAt - pos);
     28     XMVECTOR right = XMVector3Normalize(XMVector3Cross(worldUp, look));
     29     XMVECTOR up = XMVector3Cross(look, right);
     30 
     31     XMStoreFloat3(&m_position, pos);
     32     XMStoreFloat3(&m_look, look);
     33     XMStoreFloat3(&m_right, right);
     34     XMStoreFloat3(&m_up, up);
     35 }
     36 
     37 void Camera::LookAt(const DirectX::XMFLOAT3& pos, const DirectX::XMFLOAT3& lookAt, 
     38     const DirectX::XMFLOAT3& worldUp)
     39 {
     40     XMVECTOR p = XMLoadFloat3(&pos);
     41     XMVECTOR l = XMLoadFloat3(&lookAt);
     42     XMVECTOR u = XMLoadFloat3(&worldUp);
     43 
     44     LookAtXM(p, l, u);
     45 }
     46 
     47 //前后行走
     48 void Camera::Walk(float dist)
     49 {
     50     XMVECTOR pos = XMLoadFloat3(&m_position);
     51     XMVECTOR look = XMLoadFloat3(&m_look);
     52     pos += look * XMVectorReplicate(dist); //XMVectorReplicate(x)返回XMVector(x,x,x,x)
     53     XMStoreFloat3(&m_position, pos);
     54 }
     55 
     56 //左右平移
     57 void Camera::Strafe(float dist)
     58 {
     59     XMVECTOR pos = XMLoadFloat3(&m_position);
     60     XMVECTOR right = XMLoadFloat3(&m_right);
     61     pos += right * XMVectorReplicate(dist);
     62 
     63     XMStoreFloat3(&m_position, pos);
     64 }
     65 
     66 //上下点头
     67 void Camera::Pitch(float angle)
     68 {
     69     XMMATRIX rotation = XMMatrixRotationAxis(XMLoadFloat3(&m_right), angle);
     70                             //向量矩阵相乘
     71     XMStoreFloat3(&m_up, XMVector3TransformNormal(XMLoadFloat3(&m_up), rotation));
     72     XMStoreFloat3(&m_look, XMVector3TransformNormal(XMLoadFloat3(&m_look), rotation));
     73 }
     74 
     75 //左右摇头
     76 void Camera::RotateY(float angle)
     77 {
     78     XMMATRIX rotation = XMMatrixRotationY(angle);
     79 
     80     XMStoreFloat3(&m_right, XMVector3TransformNormal(XMLoadFloat3(&m_right), rotation));
     81     XMStoreFloat3(&m_up, XMVector3TransformNormal(XMLoadFloat3(&m_up), rotation));
     82     XMStoreFloat3(&m_look, XMVector3TransformNormal(XMLoadFloat3(&m_look), rotation));
     83 }
     84 
     85 //更新视角矩阵
     86 void Camera::UpdateViewMatrix()
     87 {
     88     XMVECTOR r = XMLoadFloat3(&m_right);
     89     XMVECTOR u = XMLoadFloat3(&m_up);
     90     XMVECTOR l = XMLoadFloat3(&m_look);
     91     XMVECTOR p = XMLoadFloat3(&m_position);
     92 
     93     r = XMVector3Normalize(XMVector3Cross(u, l));
     94     u = XMVector3Normalize(XMVector3Cross(l, r));
     95     l = XMVector3Normalize(l);
     96 
     97     float x = -XMVectorGetX(XMVector3Dot(p, r));
     98     float y = -XMVectorGetX(XMVector3Dot(p, u));
     99     float z = -XMVectorGetX(XMVector3Dot(p, l));
    100 
    101     XMStoreFloat3(&m_right, r);
    102     XMStoreFloat3(&m_up, u);
    103     XMStoreFloat3(&m_look, l);
    104     XMStoreFloat3(&m_position, p);
    105 
    106     m_view(0, 0) = m_right.x;    m_view(0, 1) = m_up.x;    m_view(0, 2) = m_look.x;     m_view(0, 3) = 0;
    107     m_view(1, 0) = m_right.y;    m_view(1, 1) = m_up.y;    m_view(1, 2) = m_look.y;     m_view(1, 3) = 0;
    108     m_view(2, 0) = m_right.z;    m_view(2, 1) = m_up.z;    m_view(2, 2) = m_look.z;     m_view(2, 3) = 0;
    109     m_view(3, 0) = x;            m_view(3, 1) = y;         m_view(3, 2) = z;            m_view(3, 3) = 1;
    110 }

    3.摄像机的使用

      例子是上个demo,只不过是把控制视角的方式换成了刚实现的摄像机而已。

      代码下载:http://files.cnblogs.com/files/zhangbaochong/CameraDemo.zip

  • 相关阅读:
    iOS8.1 To iOS8.2
    OAuth授权验证说明
    iOS消息推送
    Swift2
    Swift1
    数据结构,每次看都有不一样的体会
    修改CS、IP的指令(学习汇编)
    C,C++中的堆与栈
    12864显示菜单处理编程
    C编程常见的内存错误
  • 原文地址:https://www.cnblogs.com/zhangbaochong/p/5785100.html
Copyright © 2020-2023  润新知