回看 LookAt 矩阵 #
在矩阵变换文章中专门解释过 lookAt 矩阵的原理。可以先看一下前面的文章了解下 LookAt 矩阵。
这里专门详细说明下,为什么 LookAt 矩阵的形式如下:

其中 (Rx,Ry,Rz) 表示摄像机的 X 轴方向向量,(Ux,Uy,Uz) 表示摄像机坐标系的Y轴方向,(Dx,Dy,Dz) 表示摄像机的视线方向及 Z 轴。 (Px,Py,Pz) 表示摄像机位置的世界坐标。
这张图里的 LookAt 矩阵,本质上不是“把摄像机变换到世界中”的矩阵,而是它的逆变换:
把一个世界坐标点,转换成以摄像机为原点、以摄像机三个方向为坐标轴的观察空间坐标。
文章也是按照这个思路定义 LookAt 的:世界坐标经过观察矩阵后,变成相对于摄像机位置和方向的观察坐标。(Pengfei XC)
下面假设使用 OpenGL/GLSL 常见的列向量右乘形式:
Pcamera=View⋅Pworld
1. 摄像机实际上定义了一个新的坐标系 #
假设摄像机具有:
- 世界坐标位置:(\mathbf P)
- 摄像机 X 轴:(\mathbf R),Right
- 摄像机 Y 轴:(\mathbf U),Up
- 摄像机 Z 轴:(\mathbf D)
其中:
R=RxRyRz,U=UxUyUz,D=DxDyDz可以把摄像机坐标系想象成:
U:摄像机上方
↑
|
P --------→ R:摄像机右方
/
/
D:摄像机 Z 轴
这些向量都是用世界坐标系描述的。
所以摄像机坐标系的完整信息是:
原点:P
X 轴:R
Y 轴:U
Z 轴:D
LookAt 要解决的问题是:
已知点在世界坐标系中的坐标,求它在这个摄像机坐标系中的坐标。
2. 第一步:让摄像机位于原点 #
假设世界中有一点:
X=xyz摄像机位于:
P=PxPyPz从摄像机观察这个点,首先需要求出“点相对于摄像机的位置”:
X−P因此需要把整个世界平移 −P:
T(−P)=100001000010−Px−Py−Pz1作用到世界坐标点上:
T(−P)xyz1=x−Pxy−Pyz−Pz1这一步很好理解:
世界点的位置 - 摄像机的位置
= 世界点相对于摄像机的位置
例如:
摄像机位置 P = (3, 0, 0)
世界点位置 X = (5, 1, 0)
那么从摄像机看来:
X−P=(2,1,0)所以矩阵中必须是 -Px、-Py、-Pz。
文章里所说的“移动的不是摄像机,而是整个场景,将场景向相反方向移动”,指的就是这个过程。(Pengfei XC)
3. 第二步:用摄像机的三个轴描述这个相对位置 #
经过平移以后,得到相对向量:
Q=X−P但这个向量当前仍然是用世界坐标轴描述的。
我们希望知道:
Q 在摄像机右方向上有多少?
Q 在摄像机上方向上有多少?
Q 在摄像机 Z 方向上有多少?
这正好通过点积计算:
xcamera=R⋅Qycamera=U⋅Qzcamera=D⋅Q展开:
xcamera=RxQx+RyQy+RzQzycamera=UxQx+UyQy+UzQzzcamera=DxQx+DyQy+DzQz把三个点积堆叠成矩阵:
xcameraycamerazcamera=RxUxDxRyUyDyRzUzDzQxQyQz 这就是图片中左侧矩阵的来源:
RxUxDx0RyUyDy0RzUzDz00001注意这里三个轴放在了行上,因为每一行都需要和世界坐标向量做一次点积:
第一行 · Q = 摄像机 x 坐标
第二行 · Q = 摄像机 y 坐标
第三行 · Q = 摄像机 z 坐标
4. 两个步骤组合起来 #
我们刚才得到两个步骤。
第一步,减去摄像机位置:
Q=X−P第二步,分别投影到摄像机三个轴:
xcyczc=RTUTDT(X−P)所以:
LookAt=RxUxDx0RyUyDy0RzUzDz00001100001000010−Px−Py−Pz1这正是图片中的形式。
因为使用列向量,所以矩阵从右向左作用:
世界坐标
↓
先乘 T(-P):让摄像机移动到原点
↓
再乘摄像机轴矩阵:换成摄像机坐标轴描述
↓
观察空间坐标
也就是:
Pcamera=Rview⋅T(−P)⋅Pworld(完)