【问题标题】:How to move a camera using in a ray-tracer?如何在光线追踪器中移动相机?
【发布时间】:2017-01-14 00:36:37
【问题描述】:

我目前正在研究光线追踪技术,我认为我做得很好;但是,我还没有涵盖相机。

到目前为止,我使用了一个平面片段作为视图平面,它位于 (-width/2, height/2, 200)(width/2, -height/2, 200) 之间 [200 只是 z 的固定数量,可以更改]。

除此之外,我主要在e(0, 0, 1000) 上使用相机,并使用透视投影。

我将光线从点e发送到像素,并在计算像素颜色后将其打印到图像的对应像素。

这是我创建的图像。希望您可以通过查看图像来猜测眼睛和视图平面的位置。

我的问题从这里开始。是时候移动我的相机了,但我不知道如何将 2D 视图平面坐标映射到规范坐标。是否有一个转换矩阵?

我认为该方法需要知道视图平面上像素的 3D 坐标。我不确定这是使用正确的方法。那么,你有什么建议呢?

【问题讨论】:

标签: c++ camera transformation raytracing


【解决方案1】:

有多种方法可以做到这一点。这是我的工作:

  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);
}

这只是说明性的,因此未进行优化。

【讨论】:

  • 这对我来说不太适用,但我想我明白了。在“Vector3 image_point = i * camera_right + j * camera_up + camera_position + camera_direction;”中你是说 normalized_i 和 normalized_j 吗?
  • 是的,我的意思是使用标准化的 i 和 j (在答案中更正)。请注意,ray_direction 只是在将camera_position 添加到image_point 后立即减去它,因此您可以简单地省略它,但我觉得这模糊了逻辑。我不确定你说的是哪种翘曲。在非常宽的视角下,物体在框架边缘附近确实会变形(例如,球体看起来是长方形的)。
  • @RdIP:如果您将像素视为一个 1x1 的小正方形,那么您希望光线穿过它的中间,而不是角落。
  • @binaryBigInt:如果您知道相机的位置和指向的方向,那么您没有足够的信息来了解相机的方向。如果您将相机对准某人的脸,您可以将相机沿其外观的轴转动,以使脸部在图像中侧向或倒置。所以我们选择一个camera_up 向量来消除这种歧义。由此,我们可以推导出camera_right,它与camera_up 一起定义了电影或图像传感器在世界空间中的平面。
  • @RdIP:正如我所说,有多种方法。对我来说,FOV 不是很直观,所以我更喜欢从焦距和相机型号的角度来考虑。这一切都归结为相同的转换。
【解决方案2】:

对于光栅化渲染器,您往往需要一个转换矩阵,因为这是您直接从 3D 坐标映射到屏幕 2D 坐标的方式。

对于光线追踪,这不是必需的,因为您通常从 2D 空间中的已知像素坐标开始

给定眼睛位置、屏幕中心 3 空间中的一个点以及“上”和“右”的向量,很容易计算从眼睛位置射出的 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();
  • v.add_scaled(d, n) 只执行v += (d * n),其中d 是向量,n 是比例因子。两条线计算视图平面中与(x, y) 处的像素相交的点,其中xy 位于-1..1 范围内
猜你喜欢
  • 2012-06-19
  • 2016-08-23
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 2022-10-02
  • 1970-01-01
  • 2019-02-26
  • 2021-04-30
相关资源
最近更新 更多