2011-05-10 65 views
10

我正在写一个光线跟踪器(主要是为了好玩),虽然我已经写了一个过去,并花了大量的时间搜索,没有教程似乎阐明了如何在透视投影中计算眼睛光线,而不使用矩阵。Raytracer - 计算的眼睛光线

我相信我最后一次做的是通过使用类Quaternion(可能)低效旋转相机方向矢量的眼矢量x/y度。这是用C++编写的,我正在用C#做这个,尽管这并不重要。

伪代码(假设V * Q =变换操作)

yDiv = fovy/height 
xDiv = fovx/width 

for x = 0 to width 
    for y = 0 to height 

     xAng = (x/2 - width) * xDiv 
     yAng = (y/2 - height) * yDiv 
     Q1 = up vector, xAng 
     Q2 = camera right vector, yAng 
     Q3 = mult(Q1, Q2) 

     pixelRay = transform(Q3, camera direction) 
     raytrace pixelRay 

    next 
next 

我认为与此实际的问题是,它模拟球形屏幕表面,而不是平坦的屏幕表面。

请注意,虽然我知道如何以及为什么要使用交叉产品,点积,矩阵等,但我真正的3D数学问题解决技能并不是很棒。

所以给出:

  • 摄像机位置,方向和上矢量
  • 视场
  • 屏幕像素和/或子采样划分

什么是实际的方法为光线跟踪器的x/y像素坐标产生一个眼睛光线?

为了澄清:我正是我想要计算的,我只是不太想拿出3D数学来计算它,并且我发现没有光线跟踪代码似乎有我需要的代码计算单个像素的眼睛光线。

enter image description here

回答

13

enter image description here

INPUT: camera_position_vec, direction_vec, up_vec, screen_distance 

right_vec = direction_vec x up_vec 
for y from 0 to 1600: 
    for x from 0 to 2560: 
     # location of point in 3d space on screen rectangle 
     P_3d = camera_position_vec + screen_distance*direction_vec 
       + (y-800)*-up_vec 
       + (x-1280)*right_vec 

     ray = Ray(camera_position_vec, P_3d) 
     yield "the eye-ray for `P_2d` is `ray`" 

x指叉积

编辑: 答案假设direction_vec是标准化的,因为它应该是。 right_vec在图片中(看起来应该在左边),但right_vec不是必需的,如果包含,应始终与-(up_vec x direction_vec)处于相同的方向。此外,图片暗示x坐标随着一个向右而增加,y坐标随着向下而增加。这些标志已经稍微改变以反映这一点。缩放可以通过将公式中的x和y项相乘或更有效地乘以矢量并使用scaled_up_vecscaled_right_vec来执行。然而,变焦是等同的(因为光圈无关紧要,这是一个完美的针孔摄像头),以改变视场(FoV),这是一个比任意“变焦”更好的处理量。有关如何实现FoV的信息,请参阅下面的注释。

+0

谢谢。对不起,我应该在这个问题上让自己更清楚。我的脑海里实际上已经有了这种实现。如果用一个视场角来计算屏幕距离,那么如果x是-0.5到0.5,纵横比不能承受? – 2011-05-10 02:08:28

+2

考虑当你改变'screen_distance'(焦距)时会发生什么。随着您移近它,图像变得更加宽广。因此,我们假设我们希望以度为单位的视角“FoV”。如果考虑右边中间的最大y值,它将形成一个三角形,意味着tan(FoV/2)= 800/screen_distance'。因此,如果我们设置'FoV'而不是'screen_distance',我们将'screen_distance'设置为'800/tan(FoV/2)'。当然,人们不会使用像2560和1600这样的固定值,但是你去了。 – ninjagecko 2011-05-10 02:14:48