这个光线追踪公式的焦距和图像平面距离是多少
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));
我有几个问题:
- 如何找到我的光线追踪相机的焦距?
- 我的图像平面在哪里?
- 为什么
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 的半图像平面的大小。只需画一个三角形来验证即可。请注意,此代码只能生成方形图像平面。如果要允许长方形的,需要考虑边长的比例。
我有一个由右、上、前和位置向量组成的 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));
我有几个问题:
- 如何找到我的光线追踪相机的焦距?
- 我的图像平面在哪里?
- 为什么
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 的半图像平面的大小。只需画一个三角形来验证即可。请注意,此代码只能生成方形图像平面。如果要允许长方形的,需要考虑边长的比例。