从Model Space到Canonical view volume转换矩阵的计算

来源:互联网 发布:淘宝上最正宗的冷吃兔 编辑:程序博客网 时间:2024/06/05 17:50

从Model Space到Canonical view volume转换矩阵的计算

 (2011-10-12 13:18:39)
转载
标签: 

canonical

 

view

 

volume

 

model

 

space

 

3d

 

opengl

 

矩阵

 分类: 技术
一、计算旋转矩阵RotateMatrix
    3D中绕任意轴n单位向量)旋转θ 的公式推导见书《3D数学基础:图形与游戏开发》第91页(8.2.3 3D中绕任意轴的旋转)一节,贴出公式如下公式8.5。旋转矩阵R(n,θ)为:
 从Model <wbr>Space到Canonical <wbr>view <wbr>volume转换矩阵的计算

适用于OPENGL(右手坐标系)的实现程序
void makeRotateMatrix(float angle,//旋转角度 单位:度
                      float ax, float ay, float az,//旋转轴
                      float m[16])//旋转矩阵
{
  float radians, sine, cosine, ab, bc, ca, tx, ty, tz;
  float axis[3];
  float mag;

  axis[0] = ax;
  axis[1] = ay;
  axis[2] = az;
  mag = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
  if (mag) {
    axis[0] /= mag;
    axis[1] /= mag;
    axis[2] /= mag;
  }

  radians = angle * myPi / 180.0;//弧度转换
  sine = sin(radians);
  cosine = cos(radians);
  ab = axis[0] * axis[1] * (1 - cosine);
  bc = axis[1] * axis[2] * (1 - cosine);
  ca = axis[2] * axis[0] * (1 - cosine);
  tx = axis[0] * axis[0];
  ty = axis[1] * axis[1];
  tz = axis[2] * axis[2];

  m[0]  = tx + cosine * (1 - tx);
  m[1]  = ab + axis[2] * sine;
  m[2]  = ca - axis[1] * sine;
  m[3]  = 0.0f;
  m[4]  = ab - axis[2] * sine;
  m[5]  = ty + cosine * (1 - ty);
  m[6]  = bc + axis[0] * sine;
  m[7]  = 0.0f;
  m[8]  = ca + axis[1] * sine;
  m[9]  = bc - axis[0] * sine;
  m[10] = tz + cosine * (1 - tz);
  m[11] = 0;
  m[12] = 0;
  m[13] = 0;
  m[14] = 0;
  m[15] = 1;
}

二、计算位移矩阵
    位移矩阵比较简单,在列主序矩阵中,即在第四列前三元素为位移量,左上3X3矩阵为单位正矩阵。
典型的位移矩阵为:
           从Model <wbr>Space到Canonical <wbr>view <wbr>volume转换矩阵的计算
适用于OPENGL(右手坐标系)的实现程序
void makeTranslateMatrix(float x, float y, float z, float m[16])
{
  m[0]  = 1;  m[1]  = 0;  m[2]  = 0;  m[3]  = x;
  m[4]  = 0;  m[5]  = 1;  m[6]  = 0;  m[7]  = y;
  m[8]  = 0;  m[9]  = 0;  m[10] = 1;  m[11] = z;
  m[12] = 0;  m[13] = 0;  m[14] = 0;  m[15] = 1;
}

三、计算ModelMatrix
    模型矩阵的功能就是将模型空间转化为世界坐标系。因为我们创作某个模型时是在模型自身的坐标系内完成的,而要描述模型间的相对位置关系时,需要引入世界坐标系。所以需要进行顶点坐标从模型空间转换为世界坐标空间。转换公式为:
     ModelMatrix TranslateMatrix RotateMatrix (先移位后旋转)

四、计算ModelViewMatrix(模型坐标转换为眼坐标空间)
    每个人都是从各自的视点出发观察这个世界,无论是主观世界还是客观世界。同样,在计算机中每次只能从唯一的视角出发渲染物体。在游戏中,都会提供视点漫游的功能,屏幕显示的内容随着视点的变化而变化。这是因为GPU 将物体顶点坐标从world space 转换到了eye space。所谓eye space,即以camera(视点或相机)为原点,由视线方向、视角和远近平面,共同组成一个梯形体的三维空间,称之为viewing frustum(视锥),
如图 4 所示。近平面,是梯形体较小的矩形面,作为投影平面,远平面是梯形体较大的矩形,在这个梯形体中的所有顶点数据是可见的,而超出这个梯形体之外的场景数据,会被视点去除(Frustum Culling,也称之为视锥裁剪)。(摘自GPU Programming and Cg language Primer)
        从Model <wbr>Space到Canonical <wbr>view <wbr>volume转换矩阵的计算
      在GPU管线(pipeline)中,通过ViewMatrix * ModelMatrix将模型坐标空间的坐标转换为世界坐标空间,再转换为眼坐标空间。转换公式为:
         ModelViewMatrix = ViewMatrix * ModelMatrix
      关于眼坐标空间中ViewMatrix的计算见我的博客《关于ViewMatrix计算》一节。

五、投影矩阵(ProjMatrix)的计算(理解这一部分非常重要)
   透视投影是GPU流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical
View
Volume
)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。投影矩阵公式为:
        从Model <wbr>Space到Canonical <wbr>view <wbr>volume转换矩阵的计算

    其中,
        N:为眼睛或摄像机中心到近裁剪面的距离;
        F:为眼睛或摄像机中心到远裁剪面的距离;
        left:为投影平面左边界值;
        right:为投影平面右边界值;
        top:为投影平面上边界值;
        bottom:为投影平面下边界值;
    M即为最终投影变换矩阵。相机空间中的顶点,如果在视锥体中,则变换后就在CVV中。如果在视锥体外,变换后就在CVV外。而CVV本身的规则性对于多边形的裁剪很有利。OpenGL在构建透视投影矩阵的时候就使用了M的形式。注意到M的最后一行不是(0 0 0 1)而是(0 0 -1 0),因此可以看出透视变换不是一种仿射变换,它是非线性的。另外一点你可能已经想到,对于投影面来说,它的宽和高大多数情况下不同,即宽高比不为1,比 如640/480。而CVV的宽高是相同的,即宽高比永远是1。这就造成了多边形的失真现象,比如一个投影面上的正方形在CVV的面上可能变成了一个长方 形。解决这个问题的方法就是在对多变形进行透视变换、裁剪、透视除法之后,在归一化的设备坐标(Normalized Device Coordinates)上进行的视口(viewport)变换中进行校正,它会把归一化的顶点之间按照和投影面上相同的比例变换到视口中,从而解除透视 投影变换带来的失真现象。进行校正前提就是要使投影平面的宽高比和视口的宽高比相同。
gluPerspective(fov, aspect, near, far)
    fov即视野,是视锥体在xz平面或者yz平面的开角角度,具体哪个平面都可以。OpenGL和 D3D都使用yz平面。
    aspect即投影平面的宽高比。
    near是近裁剪平面的距离。
    far是远裁剪平面的距离。
(本节部分材料摘自未知姓名的网友word文档,未能找到相关链接,在此表示感谢!)

适用于OPENGL的程序实现
     在程序中,读者朋友您可能对于投影变换的计算很迥异,因为这和上面的公式完全不同形式。但是,当你深入了解其本质后,你会发现,其实他们是同质的。
在上面公式中隐含着这样一些条件:
  aspectRatio = right/top
  top = N * tan(fov/2)
  bottom = -top
  right = top * aspectRatio
  right = -left

化简上面的M后,投影矩阵变为:
            从Model <wbr>Space到Canonical <wbr>view <wbr>volume转换矩阵的计算

然后再结合下面程序理解,就应该明了。

void buildPerspectiveMatrix(double fieldOfView,
                                   double aspectRatio,//width / height
                                   double zNear, double zFar,
                                   float m[16])
{
  double sine, cotangent, deltaZ;
  double radians = fieldOfView / 2.0 * myPi / 180.0;
  
  deltaZ = zFar - zNear;
  sine = sin(radians);
  // Should be non-zero to avoid division by zero. 
  assert(deltaZ);
  assert(sine);
  assert(aspectRatio);
  cotangent = cos(radians) / sine;

  m[0*4+0] = cotangent / aspectRatio;
  m[0*4+1] = 0.0;
  m[0*4+2] = 0.0;
  m[0*4+3] = 0.0;
  
  m[1*4+0] = 0.0;
  m[1*4+1] = cotangent;
  m[1*4+2] = 0.0;
  m[1*4+3] = 0.0;
  
  m[2*4+0] = 0.0;
  m[2*4+1] = 0.0;
  m[2*4+2] = -(zFar + zNear) / deltaZ;
  m[2*4+3] = -2 * zNear * zFar / deltaZ;
  
  m[3*4+0] = 0.0;
  m[3*4+1] = 0.0;
  m[3*4+2] = -1;
  m[3*4+3] = 0;
}

五、计算ModelViewProjMatrix
    通过ModelViewProjMatrix矩阵就可以使从模型坐标空间的坐标变换到CVV(规范立方体,Canonical view
volume
, CVV)空间坐标了,该立方体的对角顶点分别是(-1,-1,-1)和(1,1,1),CVV 的近平面(梯形体较小的矩形面)的X、Y 坐标对应屏幕像素坐标(左下角是0、0),Z 坐标则是代表画面像素深度。
。ModelViewProjMatrix计算公式为:
      modelViewProjMatrix = projectionMatrix * modelViewMatrix
   至此,完成了从模型坐标空间到CVV的坐标转换。其简图示意为:
从Model <wbr>Space到Canonical <wbr>view <wbr>volume转换矩阵的计算
(此图来自于The Cg Tutorial)
程序选自:NVIDIA Corporation\Cg\examples\OpenGL\basic\08_vertex_transform

    在自己学习的过程中,将这些难点整理出来,请雅正。同时希望能对正在阅读的您也有所帮助,最重要的还是动手去实现,再结合一些经典教材去理解。个人觉得这样才能有更深刻的理解。
0 0
原创粉丝点击