【问题标题】:Optimizing a pinhole camera rendering system优化针孔相机渲染系统
【发布时间】:2009-12-07 19:24:37
【问题描述】:

我正在为学校制作软件光栅化器,并且我正在使用一种不寻常的渲染方法而不是传统的矩阵计算。它基于pinhole camera。我在 3D 空间中有几个点,我通过获取它与相机之间的距离并对其进行归一化将它们转换为 2D 屏幕坐标

Vec3 ray_to_camera = (a_Point - plane_pos).Normalize();

这给了我一个朝向相机的方向向量。然后,我通过将光线的原点放在相机上并与略在相机后面的平面执行光线平面相交,将这个方向转换为光线。

Vec3 plane_pos = m_Position + (m_Direction * m_ScreenDistance);

float dot = ray_to_camera.GetDotProduct(m_Direction);
if (dot < 0)
{
   float time = (-m_ScreenDistance - plane_pos.GetDotProduct(m_Direction)) / dot;

   // if time is smaller than 0 the ray is either parallel to the plane or misses it
   if (time >= 0)
   {
      // retrieving the actual intersection point
      a_Point -= (m_Direction * ((a_Point - plane_pos).GetDotProduct(m_Direction)));

      // subtracting the plane origin from the intersection point 
      // puts the point at world origin (0, 0, 0)
      Vec3 sub = a_Point - plane_pos;

      // the axes are calculated by saying the directional vector of the camera
      // is the new z axis
      projected.x = sub.GetDotProduct(m_Axis[0]);
      projected.y = sub.GetDotProduct(m_Axis[1]);
   }
}

这很好用,但我想知道:算法可以更快吗?现在,对于场景中的每个三角形,我必须计算三个法线。

float length = 1 / sqrtf(GetSquaredLength());
x *= length;
y *= length;
z *= length;

即使使用快速倒数平方根近似 (1 / sqrt(x)) 也将非常苛刻。

我的问题是:
有没有近似三个法线的好方法?
这种渲染技术叫什么?
可以使用质心的法线来近似三个顶点吗? (((v0 + v1 + v2) / 3)

提前致谢。

附: “在接下来的七周内,您将在该领域专家的帮助下构建一个功能齐全的软件光栅化器。开始吧。”我喜欢我的教育。 :)

编辑:

Vec2 projected;

// the plane is behind the camera
Vec3 plane_pos = m_Position + (m_Direction * m_ScreenDistance);

float scale = m_ScreenDistance / (m_Position - plane_pos).GetSquaredLength();

// times -100 because of the squared length instead of the length
// (which would involve a squared root)
projected.x = a_Point.GetDotProduct(m_Axis[0]).x * scale * -100;
projected.y = a_Point.GetDotProduct(m_Axis[1]).y * scale * -100;

return projected;

这会返回正确的结果,但是模型现在独立于相机位置。 :(

虽然它更短更快!

【问题讨论】:

  • 很高兴在这里见到 IGAD 的同学们 :-)
  • 针孔相机模型通常使用齐次坐标的矩阵计算来实现。那你为什么不使用它呢?

标签: c++ optimization math rendering


【解决方案1】:

这被称为光线追踪器 - 第一门计算机图形课程的相当典型的作业* - 您可以在经典的 Foley/Van Damm 教科书 (Computer Graphics Principes and Practice) 中找到许多有趣的实现细节。我强烈建议您购买/借用这本教材并仔细阅读。

*等到您开始学习反射和折射...现在乐趣开始了!

【讨论】:

  • 我们在最后一个区块做了一个光线追踪器。你不会在光线追踪器中追踪从相机到世界的光线吗?
  • 你是对的,典型的光线追踪器是逐个像素而不是逐个顶点进行的。但我怀疑数学和可能的优化非常相似。
  • 一种可能的优化是使用 SSE 一次做四个倒数平方根,但我真的想在尝试之前先看看算法优化。
【解决方案2】:

很难准确理解您的代码在做什么,因为它似乎执行了很多冗余操作!但是,如果我理解你所说的你想要做什么,那么你是:

  • 寻找从针孔到点的向量
  • 规范化它
  • 沿归一化向量向后投影到“图像平面”(在针孔后面,天哪!)
  • 从图像平面上的中心点找到到该点的向量
  • 使用“轴”向量对结果进行点积以找到 x 和 y 屏幕坐标

如果上面的描述代表了你的意图,那么规范化应该是多余的——你根本不应该这样做!如果删除标准化会给您带来不好的结果,那么您可能正在做与您陈述的计划略有不同的事情......换句话说,您似乎和我一样混淆了自己,并且标准化步骤正在“修复”它它在您的测试用例中看起来足够好的程度,即使它可能仍然没有完全按照您的意愿行事。

我认为,总体问题是您的代码被大量过度设计:您将所有高级向量代数编写为要在内部循环中执行的代码。优化它的方法是在纸上计算出所有向量代数,为内部循环找到最简单的表达式,并在相机设置时为此预先计算所有必要的常数。针孔相机规格只是相机设置例程的输入。

不幸的是,除非我猜错了,否则这应该会将您的针孔相机减少到传统的、无聊的旧矩阵计算。 (光线追踪确实可以很容易地做一些很酷的非标准相机的东西——但你所描述的最终应该是完全标准的......)

【讨论】:

  • 哈!你是对的,标准化是相当多余的。 :P 这解决了我遇到的问题,但我一定会把它写在纸上。
【解决方案3】:

您的代码对我来说有点不清楚(plane_pos?),但您似乎可以省去一些不必要的计算。

与其对射线进行归一化(将其缩放为长度 1),不如对其进行缩放,以使 z 分量等于从相机到平面的距离——事实上,将 x 和 y 缩放这个因子,你不需要z。

浮动比例 = distance_to_plane/z; x *= 比例; y *= 比例;

这将给出平面上的 x 和 y 坐标,没有 sqrt(),没有点积。

【讨论】:

  • 如果需要,取消刻度以获得正确的倒置针孔效果
  • 另外,如果您不总是向下看 z 轴,您可以在相机指向的方向上创建一个单位向量,并通过该向量和点的点积的倒数进行缩放。伪代码:scale = distance_to_plane / (camera_direction . (x, y, z))
  • camera_direction = (0, 0, 1) 你得到上面的代码。这样做的好处是每次更改相机方向时只需要 1 次归一化,而不是为每个渲染的元素进行一次归一化。
  • plane_pos 只是平面的位置。因为它总是在相机后面固定距离,所以它的位置是 O + tD,其中 O 是相机位置,D 是相机方向的倒数,t 是一个常数。
  • 我已经更新了问题中的代码。它可以工作,只是它现在独立于相机位置。
【解决方案4】:

好吧,您可以在程序启动时计算每个三角形的法线。然后,当您实际运行时,您只需要访问法线即可。这种为以后节省成本而进行的启动计算往往在图形中发生很多。这就是为什么我们在很多视频游戏中都有大加载屏幕的原因!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 2014-07-15
    • 2012-02-11
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多