Skip to content

齐次坐标 ​

非常神奇的做法, 把仿射变换和透视投影操作统一成了矩阵乘法操作. (虽然之前好像在 Games101 的笔记中简单稍微写了一点, 不过这次具体的再说说)

仿射变换 ​

对于一个三维坐标, 它的缩放 / 旋转 都可以使用一个矩阵乘法表示 ——

[x′y′z′]=M[xyz]

M 即我们构造的变换矩阵. 但是平移却只能使用加法实现 ——

[x′y′z′]=[xyz]+[txtytz]

这样虽然没有问题, 我们先写出一次变换的通用形式 ——

T(p)=Ap+t

那么对于组合变换来说, 就是一堆类似的操作嵌套. 假设我们在当前的框架下按照操作顺序楞算, 绝对是没有问题的, 但是如果拓展到空间中的所有点呢? 如果我们有大量的点都需要做同样的变换, 那么按照一个一个嵌套的来算, 我们没有任何一个中间结果可以拿去复用. 于是这条计算管线就会非常贵. 那么假设我们可以先把这个嵌套操作给展开, 之后它依旧是一个 T(p)=Ap+t 的形式, 那就非常的美丽. 然而如果在当前不统一的情况下, 这很贵 —— 因为每组合两次变换, 都会出现一个 A′t1+t2 这样的向量项需要计算.

此处的拦路虎是平移, 如果平移也可以使用矩阵乘法来实现的话, 我们就可以非常方便的左乘过去, 让最后的形式非常方便的写成 T(p)=Mp 的形式. 非常的好. 我们在渲染管线中, 让每个点从局部坐标系到世界坐标系, 再经过 View, Projection 等操作, 这样比较固定的管线就可以很棒的抽离出来, 进行加速运算.

于是对于每一个点, 我们将其拓展到四维的齐次坐标系下 ——

(x,y,z)→(x,y,z,1)

此时, 平移就可以写作 ——

[x′y′z′1]=[100tx010ty001tz0001][xyz1]

不赖.

那么对于一个方向向量来说, 我们会把它表示成 (x,y,z)→(x,y,z,0), 这也很有意思, 我们可以把这个表示待会平移表达中 —— 那么点经过这次乘法之后最后一位还是 1, 表示这是一个点. 而带入方向向量则经过平移之后还是原来的表示, 没有任何变化 —— 因为平移不会改变方向向量.

所以加入的 w 不仅统一了RTS操作, 也可以表明这是一个方向还是一个点.

不过值得注意的, 对于 (x,y,z,1), 它与(kx,ky,kz,k)表示同一个点 —— 因为在使用的时候, 我们会将 x,y,z 除 w —— 透视除法这块(

透视投影 ​

透视有一个非常核心的现象 —— 「近大远小」, 也就是在视觉上, 越远的东西看起来越小. 比如在一个简化的针孔摄像机的模型中(焦距 f=1), 那么屏幕坐标存在类似 —— (相似三角形)

xscreen=xz,yscreen=yz

假设在 View 的空间中存在两个三维点 (x1,y1,z1) 和 (x2,y2,z2) 那么我们要“降维打击”在屏幕上显示 —— 使用上述的简单模型, 可以得到新屏幕空间的坐标表示为

(x1z1,y1z1),(x2z2,y2z2)

假设x1=x2,y1=y2 —— 也就是两个点仅“深度”不同, 那么对于 z1<z2 —— 也就是第二个点更深, 那么它的点会更靠近屏幕中心, 也就是显得更小. 非常符合我们的透视关系 a

我们当然无法消去除法这个操作, 因为实际上矩阵乘法能做的仅是线性变换罢, 不过我们可以把“除法信息”压入一个矩阵, 也就是 Projection 矩阵来进行实现, 这样在最后仅需要做除 w 的操作即可,

还是先说上述的最简单的情况, f=1, 相机在原点朝着 −z 看, 并且近平面就是 z=−1, 对于一个空间坐标

(x,y,z)→(x−z,y−z,−1)

然后由于是二维平面, 所以舍去最后的 -1 即得到我们投影在投影面上的结果了.所以如果我们可以构造一个矩阵, 使得

(x,y,z,1)→(x′,y′,z′,w′)

让这个点就表示我们透影之后的点不就好了? —— 因为上文说过, 我们在真的使用一个点的时候会执行一次除 w 的“归一化”操作.

可以快速的得到, 此处构造出来的 Projection 为

P=[10000100001000−10]

也就是我们借助了一个 P 矩阵实现了把透视除法信息压入, 不赖. 不过实际上要复杂许多, 要考虑整个视锥体, 略复杂一些, 后面在计算机图形学中具体推导如何推导出那个情况下的 P 吧.

而且实际上情况下, 我们不会简单的让所有经过 P 的矩阵的 z 都为 -1, 这样会丢失掉深度信息, 导致之后深度测试/ early-z 之类的算法难于运作. 所以会构造一些更好的 P (实际上就是让乘法之后的 z′=Az+B)

Released under the MIT License.