头像

zjian

Just Code!

帖子照片墙关于

视图矩阵的推导

2024-06-21 23:41

在MVP(模型-视图-投影)变换的过程中,模型变换实际上就是对物体本身的变换,如平移、旋转物体。视图变换,就是计算出物体相对摄像机的位置,因为模型变换变换的是物体的绝对位置,那从摄像机作为原点出发,去看物体的位置,肯定就不是物体的绝对位置,所以视图变换做的就是这件事。

那么怎么算出一个矩阵M,使得任意的物体应用了该矩阵得出的坐标是相对摄像机的呢?

很容易知道,计算物体的相对摄像机的坐标,实际上就是在摄像机的位置为原点,去看各个物体。所以很容易我们可以把问题转为计算摄像机到原点的矩阵(因为摄像机变换了,那物体也应用这个矩阵算出的结果,实际就是以摄像机视角看到的坐标)。当然我们还要旋转摄像机,让摄像机能看向-z轴的方向,并且向上方向是(0, 1, 0),为什么要这样做主要是方便后面的计算。

首先,根据摄像机的坐标,我们可以很轻松推导出把摄像机移动到原点的矩阵(pos是摄像机坐标):

Mtransform=[100pos.x010pos.y001pos.z0001]
M_{transform} = \begin{bmatrix}
1 & 0 & 0 &-pos.x \
0 & 1 & 0 & -pos.y \
0 & 0 & 1 &-pos.z\ 0 & 0 & 0 & 1
\end{bmatrix}

然后就是旋转,首先要让镜头对准-z方向,所以要让镜头的朝向指向 (0, 0, -1)。假设原来朝向是 look(x,y,z), 所以 M ·( look.x, look.y, look.z ,1) = (0, 0, -1, 1)。

这样解M是很难解的,但是有个特性是:

如果 AB=CA \bullet B = C, 那 A1C=BA^{-1} \bullet C = B.

那么我们可以算出矩阵的逆:

M1=[??look.x0??look.y0??look.z00001]
M^{-1} = \begin{bmatrix} ? & ? & -look.x & 0 \
? & ? & -look.y & 0 \
? & ? & -look.z & 0 \
0 & 0 & 0 & 1
\end{bmatrix}

同理,原来的向上方向up(x,y,z) 要旋转到 (0, 1, 0), 可以更新M1M^{-1}:

M1=[?up.xlook.x0?up.ylook.y0?up.zlook.z00001]
M^{-1} = \begin{bmatrix} ? & up.x & -look.x & 0 \
? & up.y & -look.y & 0 \
? & up.z & -look.z & 0 \
0 & 0 & 0 & 1
\end{bmatrix}

那还有第一列还没有的出来。这个时候根据右手定理,-z方向叉乘y方向,实际上是x轴正方向。所以原来的x轴方向是 look×up=cross-look \times up = cross 这里定为 cross, 所以cross要旋转到 (1, 0, 0)。 所以我们又可以更新M1M^{-1}

M1=[cross.xup.xlook.x0cross.yup.ylook.y0cross.zup.zlook.z00001]
M^{-1} = \begin{bmatrix} cross.x & up.x & -look.x & 0 \
cross.y & up.y & -look.y & 0 \
cross.z & up.z & -look.z & 0 \
0 & 0 & 0 & 1
\end{bmatrix}

然后我们再取矩阵的逆,正交矩阵的逆就是转置,所以直接转置就可以算出矩阵M:

Mrotate=[cross.xcross.ycross.z0up.xup.yup.z0look.xlook.ylook.z00001]
M_{rotate} = \begin{bmatrix} cross.x & cross.y & cross.z & 0 \ up.x & up.y & up.z & 0 \
-look.x & -look.y & -look.z & 0 \
0 & 0 & 0 & 1
\end{bmatrix}

最后我们再结合平移矩阵(先平移再旋转,所以平移矩阵放在右边):

Mview=[cross.xcross.ycross.z0up.xup.yup.z0look.xlook.ylook.z00001][100pos.x010pos.y001pos.z0001]=[cross.xcross.ycross.zdot(cross,pos)up.xup.yup.zdot(up,pos)look.xlook.ylook.zdot(look,pos)0001]
M_{view} = \begin{bmatrix} cross.x & cross.y & cross.z & 0 \ up.x & up.y & up.z & 0 \
-look.x & -look.y & -look.z & 0 \
0 & 0 & 0 & 1
\end{bmatrix}\begin{bmatrix}
1 & 0 & 0 &-pos.x \
0 & 1 & 0 & -pos.y \
0 & 0 & 1 &-pos.z\ 0 & 0 & 0 & 1
\end{bmatrix} \= \begin{bmatrix} cross.x & cross.y & cross.z & -dot(cross, pos) \ up.x & up.y & up.z & -dot(up, pos) \
-look.x & -look.y & -look.z & dot(look, pos) \
0 & 0 & 0 & 1
\end{bmatrix}

到此,视图矩阵的推导过程就结束了。刚开始确实很难入手,手推一遍后,实际并不会特别难。

完)