Projection Transformation 投影变换
🏒

Projection Transformation 投影变换

Projection in Computer Graphics
  • 3D to 2D
  • Orthographic projection
  • Perspective projection
notion image
 

Perspective projection vs. orthographic projection

notion image

Orthographic Projection 正交投影

方法一

A simple way of understanding
  • Camera located at origin, looking at -Z, up at Y (looks familiar?)
  • Drop Z coordinate
  • Translate and scale the resulting rectangle to
notion image
💡
将坐标中的 z 扔掉,如何区分物体的前和后?
感兴趣可以参考 Catlikecoding Render 1 中 Orthographic Camera 部分。

方法二

In general, we want to map a cuboid [l, r] x [b, t] x [f, n] to the “canonical (正则、规范、标准)” cube
我们在 轴上定义左和右 (左比右小), 轴上定义下和上 (下比上小), 轴上定义远和近 (远比近小)。
不管 x, y 多大,都将其映射到 之间。这也是个约定俗成的事情,能方便计算。这样任何空间中的长方体,都可以映射成一个标准的立方体。
这也是标准化设备坐标(NDC)的定义。
💡
上面的左比右小是相对于 轴来说的,下比上小是相对于 轴说的,但 轴上不太直观,因为我们推导的 NDC 是右手坐标系,(相机)看的是 方向,因此一个面离我们远,说明 值更小。离我们近,说明 值更大。
notion image
💡
在标准化设备坐标系中 OpenGL 使用的是左手坐标系,因为左手系在这一点上会比较方便,其 值离相机越近越小,也就是 。但也会造成别的问题,
Slightly different orders (to the “simple way”)
  • Center cuboid by translating 移到原点
  • Scale into “canonical” cube 映射到 [-1, 1],也就是缩放
Translate (center to origin) first, then scale (length/width/height to 2) 因为 -1 到 1 的长度就是 2。
因此我们可以用一个平移矩阵和缩放矩阵来求出正交投影矩阵,先平移,再缩放:
 
 
💡
如果把长方体范围缩成立方体,物体不会被拉伸吗? 会,这就涉及到另外一个变换。在所有变换做完之后,还要做一个视口变换,还要做一次拉伸。

Perspective Projection 透视投影

  • Most common in Computer Graphics, art, visual system
  • Further objects are smaller
  • Parallel lines not parallel; converge to single point
notion image
notion image
平行线就是永不相交的两条线,但照片上铁轨是平行的,却交于一点。透视投影的情况下,一个平面相当于被投影到了另外一个平面上,这种情况下就不是平行线了。

Recall

  • Before we move on
  • Recall: property of homogeneous coordinates
    • all represent the same point (x, y, z) in 3D
      • 只要一个点乘于一个不为零的 k,那么它们还是一个点。那么我们还可以将其乘以 z,其表示的点还是空间中同样的点。下面我们会用到。
    • e.g. (1, 0, 0, 1) and (2, 0, 0, 2) both represent (1, 0, 0)
  • Simple, but useful

怎么做透视投影

How to do perspective projection
  • First “squish” the frustum into a cuboid
  • Do orthographic projection ( , already known!)
notion image
透视投影的视锥体中,远的平面比近的平面要大。
我们可以把远的平面往里“挤”,“挤”到同一高度且同近平面大小,“挤”成空间中的长方体,再做正交投影就解决了。
我们已经知道正交投影怎么做了,因此剩下的就是“挤”这个操作。
在这个过程中,需要规定:
  • 近平面上任何一个点不变。
  • Z 值不变
  • 远平面的中心也不会发生变化

求出任何一个点挤压后的

要做“挤”的操作,首先要知道任何一个点的 值是怎么变化的。因为我们任何一个面都要挤成近平面大小,我们也可以将投影到近平面上求出变换后的 值。对于 值来说,这种变换是线性的。
因此,在视锥体的上面一部分中,我们可以通过相似三角形求出变换后的 值。( 值不是线性变化的,后面会提到)
notion image
上图中, 为近平面的 为任何一个点中的 值。
挤压后的 值,我们可以通过相似三角形原理得出:
同理可得挤压后的 值:
在齐次坐标系中,对于变换后的 我们只剩下 未知。
这里给矩阵乘了 ,其表示的点还是空间中同样的点。
也就是说 经过 矩阵“挤压”后,会被映射到
根据上式,我们可以得出部分的 矩阵:
对于 ,我们不知道挤压后 会怎么变,我们只规定了近的平面上和远的平面上 不变。
Observation: the third row is responsible for z’
  • Any point on the near plane will not change
    • 近平面的点不变,对于任何 运算完了一定还是
  • Any point’s z on the far plane will not change
    • 远平面的点,虽然 会变化,但是 没有变。
    •  

求出任何一个点挤压后的

由“近平面的点不变,对于任何 运算完了一定还是 ”可得:
这里给矩阵乘了 n,其表示的点还是空间中同样的点。
因此 第三行一定是 的形式,因为:
由上式可得:
前面我们已经知道第三行前两个数是 0。
💡
我们前面已经规定了远平面的中心经过 变换后也不会发生变化。
另外一个等式可以用远平面可以用其特殊的中心点得出,给中心点再乘个 可得:
由上式可得:
根据两式可得
💡
平截头体(Frustum)被压缩成长方体以后,内部的点的 值是更偏向于近平面还是更偏向于远平面?
🕓
推导 z 值 (1)

定义视锥

前面提到了长方体近平面的 l, r, b, t (left, right, bottom, top),有没有更好的方法去定义这些呢?
vertical field-of-view (fovY) and aspect ratio
我们现实中相机有视角的定义,也就是可以看到的角度的范围,也就是 field of view。广角相机就是可视角度比较大,对于视锥体来说,就是张的比较开。
垂直的可视角度就是 fovY。而相机的长宽比就是 aspect ratio。
💡
我们也可以通过 fovY 和 aspect ratio,来推出水平的可视角度。
notion image
 
How to convert from fovY and aspect to l, r, b, t?
notion image
上图中,夹角为 ,红点坐标为 为屏幕高度的一半,那么根据三角函数的定义就可以得出:

完成推导正交投影矩阵

 
notion image
正交投影没有 fovY,在 Unity 中,正交投影的参数由 Camera 组件中的参数 Size, Near, Far(Viewport Rect 暂时忽略)和 Game 视图的横纵比(aspect ratio)共同决定。
这里的 Near 是近裁面的距离,也就是 ,Far 同理,等于
Size 属性用来更改视锥体竖直方向上高度的一半,也就是前面近平面的高度
由此可得正交投影近远平面的高度 为:
正交投影近远平面的宽度 为:
notion image
注意:这里的 轴上的,代表近裁面和远裁面的 值,值为负数。

完成推导透视投影矩阵

前面已经得出:
注意:这里的 轴上的,代表近裁面和远裁面的 值,值为负数。
通常我们透视投影的参数除了近裁面远裁面的距离外,还会有 ,且 ,因此整理公式可得:
 
对投影变换的两种变换的推导,大家可以用 n, f 代表近远平面的距离来再推一遍。