欢迎阅读指正和转载,但请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com
 
深度探索DxFramework
 
第10章 进入三维的世界 5
 
10.6.3.设置相机
 

//根据相机自身的坐标,观察目标的坐标,以及垂直向上的向量,创建相机的矩阵
void C_Viewport::SetCamera(D3DXVECTOR3 position, D3DXVECTOR3 target, D3DXVECTOR3 up) 
{
    this->position = position;

   //把自身坐标到观察目标的坐标的连线,作为观察坐标系的Z轴
   zNormal = target - position; 
   D3DXVec3Normalize(&zNormal, &zNormal);

  //利用叉积求到相机的观察坐标系的X轴
  D3DXVec3Cross(&xNormal, &up, &zNormal);
  D3DXVec3Normalize(&xNormal, &xNormal);

  //再根据观察坐标系轴的Z轴和X轴求到坐标系的Y轴
  D3DXVec3Cross(&yNormal, &zNormal, &xNormal);

  //调用库函数得到观察矩阵view
  D3DXMatrixLookAtLH(&view, &position, &target, &up);

  // Obtain the xNormal from the cross product of z and y
  //再从坐标系的Y轴和X轴反求回X轴
  D3DXVec3Cross(&xNormal, &zNormal, &yNormal);
}

 
//根据相机的位置坐标和相机的pitch角,yaw角,roll角设置相机
void C_Viewport::SetCamera(D3DXVECTOR3 position, D3DXVECTOR3 angle)
{
    this->position = position;
    D3DXMATRIX matT, matR;
    D3DXQUATERNION qR;
    
    D3DXMatrixTranslation(&matT, position.x,  position.y, position.z);

    //根据pitch,yaw,roll角构造表示旋转的四元数
    D3DXQuaternionRotationYawPitchRoll(&qR, angle.y, angle.x, angle.z);

    //然后从四元数中得到旋转矩阵
    D3DXMatrixRotationQuaternion(&matR, &qR);

    //利用向量和旋转矩阵相乘,分别从旋转矩阵中获取到相机的X,Y,Z坐标轴
    zNormal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
    D3DXVec3TransformCoord (&zNormal, &zNormal, &matR);
    yNormal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
    D3DXVec3TransformCoord (&yNormal, &yNormal, &matR);

    // Multiply the two transformations, tranlation and rotation
    // 把旋转矩阵和平移矩阵相乘,然后得到其逆矩阵,就能得到观察矩阵。
    D3DXMatrixMultiply(&matT, &matR, &matT);
    D3DXMatrixInverse(&view, NULL, &matT);
    D3DXVec3Cross(&xNormal, &zNormal, &yNormal);
}
 
//设定根据透视投影。垂直视野角,视野高宽比,远近截距来决定
void C_Viewport::SetPerspective(FLOAT fov, FLOAT aspect,  FLOAT nearClip, FLOAT farClip)
{
    D3DXMatrixPerspectiveFovLH(&projection, fov,  aspect, nearClip, farClip);
    zNear = nearClip;
    zFar = farClip;
    fovY = fov;
    //根据垂直视野角计算水平视野角
    fovX = (float)(2 * atan(aspect * tan(fov / 2)));
}

 
//根据给定的屏幕坐标,计算出从相机坐标到
void C_Viewport::GetScreenRayEdge( D3DXVECTOR2* p_ScreenPosition, 
        D3DXVECTOR3* p_PointOnNearPlane, D3DXVECTOR3* p_PointOnFarPlane) 
{
    // Quaternions that are used to rotate around Y axis and
    //X axis(= Cross(lookatnormal, yNormal) )
    D3DXQUATERNION rotateYQ, rotateXQ;      

    // Matrices that are used to rotate the corner 
    //points of Frustum volume
    D3DXMATRIX    rotateYMat, rotateXMat; 
    XFLOAT xAngle;    // Angle of screen coordinate around X axis
    XFLOAT yAngle;    // Angle of screen coordinate around Y axis

    //计算交点中点的Y坐标到屏幕中点的Y坐标的差值
    XFLOAT tempY = p_ScreenPosition->y - 
    ( C_View::WINDOW_HEIGHT / 2 ); 
    // Displacement from screen center in Y axis
   //计算交点中点的X坐标到屏幕中点的X坐标的差值
    XFLOAT tempX = p_ScreenPosition->x - 
    ( C_View::WINDOW_WIDTH / 2 ); 
    
   //计算交线在YZ平面上的投影,和视截体中线在XZ平面上的投影的夹角
    xAngle = -atan(tempY /((XFLOAT)(C_View::WINDOW_HEIGHT / 2)) * tan((XFLOAT)fovY / 2));
    //计算交线在XZ平面上的投影,和视截体中线在XZ平面上的投影的夹角
    yAngle = atan(tempX / ((XFLOAT)(C_View::WINDOW_WIDTH / 2)) * tan((XFLOAT)fovX / 2));

    // 得到绕相机的y坐标轴旋转yAngle度的四元数,接着转换成旋转矩阵
    D3DXQuaternionRotationAxis(&rotateYQ, &yNormal, (float)yAngle);

    //得到绕相机的x坐标轴旋转xAngle度的四元数,接着转换成旋转矩阵
    D3DXQuaternionRotationAxis(&rotateXQ, &xNormal,(float)xAngle);
    D3DXMatrixRotationQuaternion(&rotateYMat, &rotateYQ);
    D3DXMatrixRotationQuaternion(&rotateXMat, &rotateXQ);

    // Find distance from the camera to the 4 corners at 
    // z = zNear of the viewing volume 
    // 计算得到相机坐标到近截面四个角的距离。
    XFLOAT distanceToNearPlane = (XFLOAT)(((XFLOAT)zNear) /  (cos(xAngle) * cos(yAngle)));

    // Find distance from the camera to the 4 corners at z
    // = zfat of the viewing volume 
    // 计算得到相机坐标到远截面四个角的距离
    XFLOAT distanceToFarPlane = (XFLOAT)(((XFLOAT)zFar) / (cos(xAngle) * cos(yAngle))); 

    // Find points on near plane and far plane
    //把相机的Z坐标向量绕Y轴旋转yAngle度
    D3DXVec3TransformCoord(p_PointOnNearPlane, &zNormal, &rotateYMat);
    D3DXVec3TransformCoord(p_PointOnNearPlane,   p_PointOnNearPlane, &rotateXMat);
    //然后再把这向量绕X轴旋转xAngle度,这样就把一个和相机的zNormal
    //同向的向量变换到沿视截体边同向。
    //然后,用“相机到近截面的距离”乘以视截体方向,
    //就得到那个和近截面相交的交点
    *p_PointOnFarPlane = (*p_PointOnNearPlane) * (float)(distanceToFarPlane) + position;
    //然后,用“相机到远截面的距离”乘以视截体方向,
     //就得到那个和远截面相交的交点
    *p_PointOnNearPlane = (*p_PointOnNearPlane) *  (float)(distanceToNearPlane) + position;
}

 
//设置透视投影矩阵
void C_Viewport::SetPerspective(FLOAT fov, FLOAT aspect, FLOAT nearClip, FLOAT farClip)
{
    D3DXMatrixPerspectiveFovLH(&projection, fov,  aspect, nearClip, farClip);
    // We also need to keep the informations for creating the viewing Frustum
    zNear = nearClip;
    zFar = farClip;
    fovY = fov;
    fovX = (float)(2 * atan(aspect * tan(fov / 2)));
}

D3DXVECTOR3 C_Viewport::GetPosition()

    return position; 
}

D3DXVECTOR3 C_Viewport::GetZNormal() 

    return zNormal; 
}

D3DXMATRIX* C_Viewport::GetViewMatrix() 

    return &view; 
}

C_BoundingBox* C_Viewport::GetFrustumVolume() 
{    
    return p_FrustumVolume;
}

D3DXMATRIX* C_Viewport::GetProjectionMatrix() 

    return &projection; 
}

 
// 把某顶点从世界坐标变换到观察坐标
void C_Viewport::WorldToView(D3DXVECTOR3* p_ViewOut, D3DXVECTOR3* p_WorldIn) 
{
    D3DXVec3TransformCoord(p_ViewOut, p_WorldIn, &view);
}

// 把某顶点从观察坐标变换成屏幕坐标
void C_Viewport::ViewToScreen(D3DXVECTOR3* p_ScreenOut, D3DXVECTOR3* p_ViewIn) 
{
    D3DXVec3Project( p_ScreenOut, p_ViewIn, &d3dViewport, &projection, &matIdentity, &matIdentity);
}