矩阵变换那些事

2014-04-01 by fatboyzz in 码农 tags: c++ opengl math

view 矩阵

void gluLookAt (
    GLdouble    eyeX,
    GLdouble    eyeY,
    GLdouble    eyeZ,
    GLdouble    centerX,
    GLdouble    centerY,
    GLdouble    centerZ,
    Gldouble    upX,
    GLdouble    upY,
    GLdouble    upZ
);

这个函数可以生成 view 矩阵,作用相当于更换了基底。

opengl 默认基底 原点在视口中心,x 轴向右,y 向上,z 向屏幕外,相机处于原点,向 z 轴负半轴看去。

如果想要换一个角度看世界,就需要坐标变换。把基底变换到新的位置,让 z 轴的负半轴指向相机所看的方向。

声明一下,矩阵以列的方式看,顶点,向量都看成列矩阵(只有一列的矩阵)。

坐标变换就是换基底

基底,可以看成是矩阵的列向量。比如基底分别为 \(vx,vy,vz\) 坐标为 \(v_0(x_0,y_0,z_0)\) 的点可以表示为:

$$\left( {\begin{array}{*{20}{c}}{{v_x}}&{{v_y}}&{{v_z}}\end{array}} \right){v_0} = {v_x}{x_0} + {v_y}{y_0} + {v_z}{z_0}$$

理解为 用坐标分量对基底进行线性组合。

\(I\) 为单位矩阵 则默认基底下坐标对应的值就是 \(Iv\)

现在如果想要换一套坐标,变成用矩阵 \(M\) 的列向量作为基底,并且还要使得最终计算出的点是向量空间中的同一个点则:

$$Iv = M(M^{ - 1}v)$$

把右边 \({M^{ - 1}}v\) 看成整体,它意味着,若要换 \(M\) 为基底,所有坐标都要左乘 \({M^{-1}}\)

复合换基底

gluLookAt 对基底做了两个变换。它先旋转了基底,使其 z 负半轴指向 center - eye ,然后位移到 eye 。

这相当于新的基底为 :

$$M = TRI$$

理解为,将 \(I\) 按列(即基底)切开,每列做了 \(TR\) 变换后再合起来。

所以坐标变换需要的矩阵就是 \((TR)^{-1}\)\(R^{-1}T^{-1}\)

gluLookAt 的实现

先通过规范化与叉乘,得到旋转后的基底。注意 :

  • \(F\) 为相机方向即基底 z 轴负半轴方向。
  • \(R\) 是正交矩阵 所以 \(R^T=R^{-1}\)

所以第三行添上负号。这就是 opengl 文档中的 \(M\)

\(T\) 是位移矩阵,所以 \(T^{-1}\) 就是反方向位移。

这就是 opengl 文档中的 glTranslated(-eyex, -eyey, -eyez) 。

合起来就是 \(R^{-1}T^{-1}\)

(ps: opengl 文档 s = f x up' 缺少规范化)





Comments