第 3 讲:坐标系、相机与投影

“相机在看物体”只是直觉。数学上并没有真的搬动一台相机,而是不断换坐标系,最终把三维点映到二维屏幕。

从模型到像素的坐标流水线

1. 换坐标系到底在算什么

设新坐标系的三条基向量为 u,v,w\mathbf u,\mathbf v,\mathbf w,原点为 q\mathbf q。从新坐标到旧坐标可写成

C=(uxvxwxqxuyvywyqyuzvzwzqz0001).C= \begin{pmatrix} u_x&v_x&w_x&q_x\\ u_y&v_y&w_y&q_y\\ u_z&v_z&w_z&q_z\\ 0&0&0&1 \end{pmatrix}.

若已知一个点在旧坐标中的表示,要得到它在新坐标中的坐标,就用 C−1C^{-1}。这里常见的混淆是:

  • 变换几何:真的把点移动了。
  • 变换坐标:点没动,只换一把尺子描述。

两者矩阵互为逆,但数字可能长得很像。

2. 物体、世界与相机坐标

模型通常在自己的局部坐标里建好,模型矩阵 MM 把它摆进世界。每个物体可以有不同的 MM,世界坐标则让所有物体共享同一参照。

相机矩阵 CC 表示“相机局部坐标怎样进入世界”;视图矩阵要把世界改写到相机坐标,因此

V=C−1.V=C^{-1}.

给定相机位置 e\mathbf e、观察目标 c\mathbf c 和参考上方向 up\mathbf{up},OpenGL 风格相机可取

z=e−c∥e−c∥,x=up×z∥up×z∥,y=z×x.\mathbf z= \frac{\mathbf e-\mathbf c}{\|\mathbf e-\mathbf c\|}, \quad \mathbf x= \frac{\mathbf{up}\times\mathbf z}{\|\mathbf{up}\times\mathbf z\|}, \quad \mathbf y=\mathbf z\times\mathbf x.

相机朝本地 −z-z 方向看。把这组基和相机位置组成 CC 后求逆,或直接利用旋转矩阵转置,就得到 LookAt 视图矩阵。

3. 法线为什么用逆转置

假设切向量 t\mathbf t 与法线 n\mathbf n 正交,即 tTn=0\mathbf t^T\mathbf n=0。几何变换后切向量为 MtM\mathbf t。要让新法线 n′\mathbf n' 仍满足

(Mt)Tn′=0,(M\mathbf t)^T\mathbf n'=0,

可推出

n′=(M−1)Tn.\mathbf n'=(M^{-1})^T\mathbf n.

平移对方向无效;纯旋转时逆转置又等于旋转本身,所以错误往往要等到非均匀缩放才暴露。

4. 正交投影

正交投影把长方体视景体

[l,r]×[b,t]×[n,f][l,r]\times[b,t]\times[n,f]

平移到原点并缩放到标准立方体。它保留平行关系,远近不改变物体大小,适合工程图、界面和某些阴影计算。

视口宽高比若与投影视景体不一致,最终图像会被拉伸。投影矩阵负责“看多大范围”,视口负责“画到屏幕哪一块”,两者不要混在一起。

5. 透视投影

透视投影沿穿过相机中心的射线投到近裁剪面,因此会出现近大远小和平行线汇聚。课件的推导先把截锥体挤压成长方体,再复用正交投影。

关键不是背整张矩阵,而是理解齐次分量的作用:投影矩阵让裁剪坐标的 wcw_c 与深度相关,之后做

(xndc,yndc,zndc)=(xcwc,ycwc,zcwc).(x_{ndc},y_{ndc},z_{ndc}) = \left( \frac{x_c}{w_c}, \frac{y_c}{w_c}, \frac{z_c}{w_c} \right).

这一步叫透视除法。越远的点通常除以越大的量,屏幕投影因此越小。在透视除法之前进行齐次裁剪,可以正确处理跨过相机或近裁剪面的图元。

6. 从 NDC 到屏幕

透视除法后,点位于标准化设备坐标。把 [−1,1]2[-1,1]^2 映到左下角 (tx,ty)(t_x,t_y)、宽高为 W,HW,H 的视口:

xs=tx+xndc+12W,ys=ty+yndc+12H.x_s=t_x+\frac{x_{ndc}+1}{2}W, \qquad y_s=t_y+\frac{y_{ndc}+1}{2}H.

还要留意屏幕坐标原点在左下还是左上;不同图形 API 和图像库可能不同。

7. 一条点的完整路径

列向量约定下:

pclip=PVMpobject.\mathbf p_{clip}=PVM\mathbf p_{object}.

然后依次做裁剪、透视除法、视口映射和光栅化。调试一个“看不见”的物体时,按顺序检查:

  1. 模型是否真的在世界中。
  2. 相机朝向是否正确,up 是否与视线平行。
  3. near、far、FOV 和宽高比是否合理。
  4. 裁剪坐标是否落在视锥内,ww 的符号是否正常。
  5. 深度测试、背面剔除和视口是否把结果丢掉。

逐坐标系检查,比盲目改矩阵符号有效得多。

评论