Skip to content

相机和视平面 ​

简单的来说,光追干的事情是从每一个 pixel 向世界发送射线,然后进行反射折射等的计算,最终获得颜色来代表当前 pixel 所需要展示的颜色。

此篇聚焦在如何在各个空间中做变化,来从 0 开始向世界发出一条射线

不过实际上也非常的简单 —— 我们已经知道相机的位置,只需要知道要发射射线的那个像素的世界坐标即可

视平面 ​

从第三人称的视角来看 —— 我们假装在相机前面一个单位距离的地方放置了一个“视平面”,上面的每一个点即为我们要的 pixel

确定视平面 ​

那么先考虑第一个事情 —— 如何确定视平面在相机坐标系中的位置。

假设我们已经知道了 FOV 的角度(Vertical FOV),以及分辨率,那么由由于上一个 Block 说了,定义视平面距离相机位置为 1

所以

HalfHeight=tan⁡(FOV2)

然后我们又知道了长和高的比值 aspect ratio 所以可以快速的计算出对应宽度

那么现在的“照片”像素位置就可以完美确定下来了

确定 uv ​

现在的 pixel(x, y) 对于整数 Pixel Index, x∈[0,width−1],y∈[0,height−1] 这不赖,只是它们并没有什么特殊的含义,于是我们进行第一次的“压缩”,将当前的视平面空间进行一次归一化,使得 u,v∈[0,1]

这样处理的另一个好处在于,我们可以让之后的计算和分辨率解耦 —— 比如对于不同分辨率的图片来说,它们的中心点是不同的,但是在 UV 表示下,都是 (0.5,0.5)

那么计算也非常的简单

u=x+0.5width,v=y+0.5height

加上 0.5 的原因 —— 使得计算的当前点处于像素中心

中心点偏移 ​

上述压缩到 UV 已经很不错了,不过中心点是 (0.5,0.5),而在我们的相机坐标系下,视平面的中心是 (0,0),所以我们经过一次运算,使得原先的 [0,1] 的范围映射到 [−1,1] 的空间中,这样中心点就完美的处于(0,0)和视平面中心位置一致 —— 这样对于当前的 x′,y′ 来说,它的大小即为在屏幕空间中的“拉伸”度量

计算依旧十分简单

x′=2u−1;y′=1−2v

相机坐标系表示 ​

现在需要把归一化之后的坐标重新映射回屏幕坐标 ——

planeX=x′∗HalfWidthplaneY=y′∗HalfHeight

现在就是“绕了一圈”之后得到的视平面上的一个 pixel 在相机的局部坐标系下的表示了 ——

Pcamera=(planeX,planeY,1)

世界坐标 ​

现在把相机坐标系下的那个像素点映射到世界坐标即可

依旧十分甚至九分的简单 —— 此处的 (planeX,planeY) 表示了在空间中沿着 Camera 坐标系中,要沿着 Right 和 Up 两个基向量移动多少,所以直接把 Right 和 Up 基向量在世界坐标系中的表示代入即可

也就是 ——

Pworld=P0+planeX∗R+planeY∗U

其中 P0 表示视平面坐标中心的世界坐标表示,并且

P0=CameraCenterPosition+Forward

发射射线 ​

现在有了像素点在世界坐标系中的表示,也有了相机位置的坐标,于是发射的 Ray 水到渠成,其方向为

Normalize(Ppixel−CameraPosition)

然后起始点即 CameraPosition

总结 ​

当然,上述说的是一个理想化的针孔摄像机模型的计算链路,也就是所有的初始光线都从同一个 CameraPosition 出发,这样天然的会有透视等的效果。

不过对于不同的摄像机模型,会有不同的计算方式,不过大体的思路相通 —— 比如正交相机就可以是每个 Ray 的方向相同,诸如此类 —— 即找到一个合理的映射关系,使得 Pixel 的采样可以到一条 Ray

Released under the MIT License.