现在的位置: 首页 > 综合 > 正文

view matrix 计算

2013年12月08日 ⁄ 综合 ⁄ 共 3159字 ⁄ 字号 评论关闭

一、列主序(OPENGL)和行主序(Direct3D)

在计算ViewMatrix之前先讲明列主序(OPENGL)和行主序(Direct3D),搞清楚这个,理解算法程序会很有帮助。
1.矩阵在内存中的存储
    不管是D3D还是OpenGL,使用的矩阵都是线性代数标准的矩阵,只是在存储方式上有所不同。分别为:行主序(Direct3D),列主序(OpenGL)
    存储顺序说明了线性代数中的矩阵如何在线性的内存数组中存储。例如:内存中使用一个二维数组m存储矩阵,第i行第j列的表示方法分别为:
    行主序:m[i][j]
    列主序:m[j][i]
线性代数意义的同一个矩阵,在D3D和GL中的存储顺序:
线代: a11,a12,a13,a14 d3d : a11,a12,a13,a14 gl: a11,a21,a31,a41
       a21,a22,a23,a24       a21,a22,a23,a24     a12,a22,a32,a42
       a31,a32,a33,a34       a31,a32,a33,a34     a13,a23,a33,a43
       a41,a42,a43,a44       a41,a42,a43,a44     a14,a24,a34,a44
2.行主序的矩阵与列主序的矩阵如何转换呢?
    不难发现,M行=M列的转稚
总结
     OpenGL与Direct3D几点不同(坐标系,向量,绕序):  

 

OpenGL

Direct3D

坐标系

右手坐标系

左手坐标系

向量

列向量

行向量

矩阵存储方式

列主序

行主序

多边形正面顶点绕序

逆时针

顺时针


     向量的行列性导致矩阵向量乘法方式有所不同:
     列向量 ==> 矩阵右乘向量
     行向量 ==> 矩阵左乘向量
     其中OpenGL可以设置顺时针为多边形正面顶点绕序。

二、视点矩阵计算
    视点矩阵(view matrix)模拟我们的眼睛或者摄像机。 在流水线(pipeline)中, 视点矩阵将作用于所有顶点.在进行投影转换时设置的视景体, 决定了我们能在屏幕上看见什么.
    在D3D中,视景体是以坐标原点为视点, 直视Z轴正方向. 所以, 如果希望看到3D空间中不同位置, 不同角度的图像. 就需要将视点转换回坐标原点.从本质上讲,
所有这些矩阵变换都将作用于顶点. 所以都是模型的变换.

假设视点位于P(Px, Py, Pz)点, 方向为Q(Qx, Qy, Qz), 头顶方向U(Ux, Uy, Uz)根据这些计算视点矩阵. 
    第一步: 将视点移回原点. 这个矩阵很好计算:
              关于ViewMatrix计算
    第二步: 建立视点坐标系.
         在这里, 我们需要根据Q和U计算出三个互相垂直的单位向量, 用来表示当前的视点坐标系. Q相对于Z轴正方向, W相对于Y轴正方向, S相对于X轴正方向.
     第三步: 将XYZ坐标系下的点转换到SWQ坐标系下.
         这里需要一些思考, 现在的S(Sx, Sy, Sz), W(Wx, Wy, Wz), Q(Qx, Qy, Qz)都是在XYZ坐标系下表示的向量. XYZ坐标系下的点, 要转换到SWQ坐标系下, 其实并不难. 假设点K(Kx, Ky, Kz)是XYZ坐标系下的点, L是SWQ坐标系下的点:
           Lx = Kx * Sx + Ky * Sy + Kz * Sz;
           Ly = Kx * Wx + Ky * Wy + Kz * Wz;
           Lz = Kx * Qx + Ky * Qy + Kz * Qz;
由此, 我们可以推出转换矩阵:
              关于ViewMatrix计算
    第四步 将第一步和第二步的矩阵相乘, 我们就可以得出最终的view矩阵:
          关于ViewMatrix计算

                     关于ViewMatrix计算

在OPENGL中,列主序,视点矩阵为:
             关于ViewMatrix计算

                         关于ViewMatrix计算

实现子程序(OPENGL)
static void buildLookAtMatrix(double eyex, double eyey, double eyez, //eye position
                              double centerx, double centery, double centerz, // view center:(0, 0, 0)
                              double upx, double upy, double upz,//up vector :(0, 1, 0)
                              float m[16]) //View Matrix
{
  double x[3], y[3], z[3], mag;
  // Difference eye and center vectors to make Z vector. 
  z[0] = eyex - centerx;
  z[1] = eyey - centery;
  z[2] = eyez - centerz;
  // Normalize Z. 
  mag = sqrt(z[0]*z[0] + z[1]*z[1] + z[2]*z[2]);
  if (mag) {
    z[0] /= mag;
    z[1] /= mag;
    z[2] /= mag;
  }
  // Up vector makes Y vector. 
  y[0] = upx;
  y[1] = upy;
  y[2] = upz;
  // X vector = Y cross Z. 
  x[0] =  y[1]*z[2] - y[2]*z[1];
  x[1] = -y[0]*z[2] + y[2]*z[0];
  x[2] =  y[0]*z[1] - y[1]*z[0];
  // Recompute Y = Z cross X. 
  y[0] =  z[1]*x[2] - z[2]*x[1];
  y[1] = -z[0]*x[2] + z[2]*x[0];
  y[2] =  z[0]*x[1] - z[1]*x[0];
  // Normalize X. 
  mag = sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
  if (mag) {
    x[0] /= mag;
    x[1] /= mag;
    x[2] /= mag;
  }
  // Normalize Y. 
  mag = sqrt(y[0]*y[0] + y[1]*y[1] + y[2]*y[2]);
  if (mag) {
    y[0] /= mag;
    y[1] /= mag;
    y[2] /= mag;
  }
  // Build resulting view matrix. 
  m[0*4+0] = x[0];  m[0*4+1] = x[1];
  m[0*4+2] = x[2];  m[0*4+3] = -x[0]*eyex + -x[1]*eyey + -x[2]*eyez;
  m[1*4+0] = y[0];  m[1*4+1] = y[1];
  m[1*4+2] = y[2];  m[1*4+3] = -y[0]*eyex + -y[1]*eyey + -y[2]*eyez;
  m[2*4+0] = z[0];  m[2*4+1] = z[1];
  m[2*4+2] = z[2];  m[2*4+3] = -z[0]*eyex + -z[1]*eyey + -z[2]*eyez;
  m[3*4+0] = 0.0;   m[3*4+1] = 0.0;  m[3*4+2] = 0.0;  m[3*4+3] = 1.0;
}
申明:
程序选自:NVIDIA Corporation\Cg\examples\OpenGL\basic\08_vertex_transform

抱歉!评论已关闭.