优化针孔相机渲染系统

时间:2009-12-07 19:24:37

标签: c++ optimization math rendering

我正在为学校制作软件光栅化器,我正在使用一种不寻常的渲染方法而不是传统的矩阵计算。它基于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)

提前致谢。

P.S。 “在这个领域的专家的帮助下,你将在未来七周内构建一个功能齐全的软件光栅器。开始吧。”我喜欢我的教育。 :)

修改

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;

返回正确的结果,但模型现在独立于摄像机位置。 :(

虽然它更短更快!

4 个答案:

答案 0 :(得分:4)

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

*等到你开始反思和折射......现在好玩的开始了!

答案 1 :(得分:3)

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

不是将光线标准化(将其缩放到长度1),为什么不缩放它以使z分量等于从相机到平面的距离 - 事实上,按此因子缩放x和y,你不需要z。

float scale = distance_to_plane/z;
x *= scale;
y *= scale;

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

答案 2 :(得分:3)

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

  • 从针孔到点找到矢量
  • 规范化
  • 沿着归一化向量向后投射到“图像平面”(在针孔后面,自然!)
  • 从图像平面上的中心点找到此点的矢量
  • 使用“轴”向量对结果执行点积,以找到x和y屏幕坐标

如果上面的描述代表了您的意图,那么标准化应该是多余的 - 您根本不应该这样做!如果删除规范化会给你带来不好的结果,你可能会做一些与你所说的计划略有不同的东西...换句话说,你可能会把自己与我混淆,并且标准化步骤是“修复”它到它在你的测试用例中看起来足够好的程度,即使它可能仍然没有达到你想要的效果。

我认为整体问题是你的代码大量过度设计:你正在编写所有高级向量代数作为要在内循环中执行的代码。优化这种方法的方法是在纸上计算出所有向量代数,找到内循环可能的最简单表达式,并在摄像机设置时预先计算所有必要的常量。针孔摄像机规格只是摄像机设置程序的输入。

不幸的是,除非我错过了我的猜测,否则这应该会将你的针孔相机减少到传统的,无聊的旧矩阵计算。 (光线跟踪确实可以很容易地做出很酷的非标准相机 - 但你描述的内容应该完全符合标准......)

答案 3 :(得分:0)

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