我有一个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)
相乘?答案 0 :(得分:1)
焦距是镜头系统的特性。然而,该代码使用的相机型号是针孔相机,根本不使用镜头。所以,严格来说,相机并没有真正的焦距。相应的光学特性反而表示为视场(摄像机可以观察的角度;通常是垂直角度)。您可以使用以下公式计算具有等效视野的相机的焦距(请参阅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;
这些公式计算每个像素的-0.5和0.5之间的u / v坐标,假设整个图像适合-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的半图像平面的大小。只需绘制一个三角形来验证。请注意,此代码只能生成方形图像平面。如果要允许矩形,则需要考虑边长的比率。