这个光线追踪公式的焦距和图像平面距离是多少

What is the focal length and image plane distance from this raytracing formula

我有一个由右、上、前和位置向量组成的 4x4 相机矩阵。 我使用在教程中找到的以下代码对场景进行光线跟踪,但并不完全理解它:

for (int i = 0; i < m_imageSize.width; ++i)
{
    for (int j = 0; j < m_imageSize.height; ++j)
    {
        u = (i + .5f) / (float)(m_imageSize.width - 1) - .5f;
        v = (m_imageSize.height - 1 - j + .5f) / (float)(m_imageSize.height - 1) - .5f;

        Ray ray(cameraPosition, normalize(u*cameraRight + v*cameraUp + 1 / tanf(m_verticalFovAngleRadian) *cameraForward));

我有几个问题:

  1. 如何找到我的光线追踪相机的焦距?
  2. 我的图像平面在哪里?
  3. 为什么cameraForward需要乘以这个1/tanf(m_verticalFovAngleRadian)

焦距是 属性 的镜头系统。但是,此代码使用的相机型号是针孔相机,根本不使用镜头。所以,严格来说,相机并没有真正的焦距。相应的光学特性改为表示为视野(相机可以观察到的角度;通常是垂直的)。您可以使用以下公式计算具有等效视野的相机的焦距(参见 Wikipedia):

FOV = 2 * arctan (x / 2f)
FOV  diagonal field of view 
x    diagonal of film; by convention 24x36 mm -> x=43.266 mm
f    focal length

没有唯一的图像平面。任何垂直于观察方向的平面都可以看作像平面。事实上,投影图像仅在比例上有所不同。

关于你最后一个问题,让我们仔细看看代码:

u = (i + .5f) / (float)(m_imageSize.width - 1) - .5f;
v = (m_imageSize.height - 1 - j + .5f) / (float)(m_imageSize.height - 1) - .5f;

这些公式为每个像素计算 u/v 介于 -0.5 和 0.5 之间的坐标,假设整个图像适合介于 -0.5 和 0.5 之间的框。

u*cameraRight + v*cameraUp 

...只是将光线的 x/y 坐标放在像素上。

... + 1 / tanf(m_verticalFovAngleRadian) *cameraForward

... 正在定义光线的深度分量,并最终定义您正在使用的图像平面的深度。基本上,这会使光线更陡或更浅。假设你的视野很小,那么 1/tan(fov) 就是一个很大的数字。因此,图像平面距离很远,这恰好产生了这个小视野(当保持图像平面的大小不变时,因为您已经设置了 x/y 组件)。另一方面,如果视野大,则图像平面靠得更近。请注意,图像平面的概念只是概念性的。正如我所说,所有其他图像平面都同样有效,并且会产生相同的图像。指定射线的另一种方法(也许是更直观的方法)是

u * tanf(m_verticalFovAngleRadian) * cameraRight 
+ v * tanf(m_verticalFovAngleRadian) * cameraUp 
+ 1 * cameraForward));

如您所见,这是完全相同的光线(只是缩放)。这里的想法是将概念图像平面的深度设置为 1,并缩放 x/y 组件以适应图像平面的大小。 tan(fov)fov 为半视场)正好是深度为 1 的半图像平面的大小。只需画一个三角形来验证即可。请注意,此代码只能生成方形图像平面。如果要允许长方形的,需要考虑边长的比例。