如何在光线追踪中移动相机?

6
我目前正在研究光线追踪技术,我认为我已经做得很好了,但是我还没有涉及到摄像机。
到目前为止,我使用的是平面片段作为视平面,位于(-宽度/2,高度/2,200)(宽度/2,-高度/2,200)之间[ 200只是z的固定数字,可以更改]。
除此之外,我主要在点e(0,0,1000)上使用相机,并使用透视投影。
我从点e向像素发送光线,并在计算出像素颜色后将其打印到图像的相应像素上。enter image description here 这是我创建的一张图片,希望您能通过查看图片猜测出眼睛和视平面的位置。
我的问题从这里开始。现在是移动我的相机的时候了,但我不知道如何将二维视平面坐标映射到规范化坐标。是否有用于此的转换矩阵?
我认为这种方法需要知道视平面上像素的三维坐标。我不确定这是否是使用的正确方法。那么,您有什么建议呢?

1
请参见此链接:http://stackoverflow.com/a/12892966/6782 - Alnitak
2个回答

18

有各种方法可以实现,以下是我的做法:

  1. 选择一个点来代表照相机位置 (camera_position)。
  2. 选择一个向量来表示照相机所看方向 (camera_direction)。 (如果你知道照相机所看的点,你可以通过将该点减去 camera_position 来计算这个方向向量。) 你可能想要规范化 (camera_direction),这样它也是图像平面的法向量。
  3. 选择另一个归一化的向量,从照相机的视角上看,它大致是"向上"的方向 (camera_up)。
  4. camera_right = Cross(camera_direction, camera_up)
  5. camera_up = Cross(camera_right, camera_direction) (这纠正了"向上"选择的任何偏差。)

camera_position + camera_direction 上可视化图像平面的"中心"。 上下和右向量位于图像平面内。

您可以选择图像平面的矩形部分与屏幕对应。这个矩形部分的宽度或高度与 camera_direction 的长度之比决定了视野。要缩放,请增加 camera_direction 或减小宽度和高度。要缩小请反之。

因此,给定像素位置 (i, j),您需要该像素在图像平面上的 (x, y, z)。从中可以减去 camera_position 得到一个射线向量(然后需要规范化)。

Ray ComputeCameraRay(int i, int j) {
  const float width = 512.0;  // pixels across
  const float height = 512.0;  // pixels high
  double normalized_i = (i / width) - 0.5;
  double normalized_j = (j / height) - 0.5;
  Vector3 image_point = normalized_i * camera_right +
                        normalized_j * camera_up +
                        camera_position + camera_direction;
  Vector3 ray_direction = image_point - camera_position;
  return Ray(camera_position, ray_direction);
}

这是为了说明而设计的,因此它并没有被优化。


1
是的,我本意使用规范化的i和j(在答案中进行了更正)。请注意,ray_direction只是在将其添加到image_point后立即从camera_position中减去,因此您可以简单地省略它,但我觉得这会掩盖逻辑。我不确定您所说的扭曲是什么样的。在非常广角的视野下,物体确实会在画面边缘附近变形(例如,球体看起来会变成椭圆形)。 - Adrian McCarthy
@AdrianMcCarthy 为什么我们需要校正斜率并重新设置相机方向?我不太明白,有什么参考资料可以查阅吗? - user1781626
1
@RdIP:如果你把像素想象成一个小的1x1正方形,那么你希望射线穿过它的中心,而不是角落。 - Adrian McCarthy
1
@binaryBigInt: 如果你只有相机的位置和它所指的方向,那么你并没有足够的信息来确定相机的朝向。如果你把相机对准某个人的脸,你可以沿着它所看的轴旋转相机,使得脸在图像中呈侧面或倒立状态。因此,我们选择一个“相机向上”向量来消除这种不确定性。从这个向量中,我们可以推导出“相机向右”的向量,结合“相机向上”,定义了世界空间中胶片或图像传感器的平面。 - Adrian McCarthy
1
@RdIP: 就像我说的,有很多种方法。对我来说,视野(FOV)不太直观,所以我更喜欢从焦距和相机模型的角度思考。最终都归结为相同的变换。 - Adrian McCarthy
显示剩余11条评论

4
对于栅格化渲染器,你通常需要一个变换矩阵,因为这是直接从3D坐标映射到屏幕2D坐标的方法。
对于光线追踪,这不是必需的,因为你通常是从已知的2D空间像素坐标开始的。
给定眼睛位置、屏幕中心的3D点以及“上”和“右”的向量,很容易计算出从眼睛位置通过指定像素的3D“射线”。
我之前在我的光线追踪器中发布了一些示例代码,链接在https://stackoverflow.com/a/12892966/6782

我在视野计算方面迷失了。您能否详细说明以下代码行:dir.add_scaled(right, m_tanf * m_aspect * x); dir.add_scaled(up, m_tanf * y); dir.normalise(); - hevele
v.add_scaled(d, n) 只是执行 v += (d * n),其中 d 是一个向量,n 是缩放因子。这两行代码计算了视平面上与像素 (x, y) 相交的点,其中 xy 的范围为 -1..1 - Alnitak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接