2017-10-19 102 views
0

我有一个由右,上,前向和位置矢量组成的4x4相机矩阵。 RAYTRACE我用下面的代码,我在一个教程中的情景,但真的不完全理解它:什么是这个光线追踪公式的焦距和像面距离

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)

回答

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; 

这些公式计算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处的半图像平面的大小。只需绘制一个三角形来验证。请注意,此代码只能生成方形图像平面。如果你想允许长方形,你需要考虑边长的比例。