我正在为学校制作软件光栅化器,我正在使用一种不寻常的渲染方法而不是传统的矩阵计算。它基于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;
返回正确的结果,但模型现在独立于摄像机位置。 :(
虽然它更短更快!
答案 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)
很难准确理解你的代码在做什么,因为它似乎正在执行大量的冗余操作!但是,如果我理解你所说的你想做的事,那你就是:
如果上面的描述代表了您的意图,那么标准化应该是多余的 - 您根本不应该这样做!如果删除规范化会给你带来不好的结果,你可能会做一些与你所说的计划略有不同的东西...换句话说,你可能会把自己与我混淆,并且标准化步骤是“修复”它到它在你的测试用例中看起来足够好的程度,即使它可能仍然没有达到你想要的效果。
我认为整体问题是你的代码大量过度设计:你正在编写所有高级向量代数作为要在内循环中执行的代码。优化这种方法的方法是在纸上计算出所有向量代数,找到内循环可能的最简单表达式,并在摄像机设置时预先计算所有必要的常量。针孔摄像机规格只是摄像机设置程序的输入。
不幸的是,除非我错过了我的猜测,否则这应该会将你的针孔相机减少到传统的,无聊的旧矩阵计算。 (光线跟踪确实可以很容易地做出很酷的非标准相机 - 但你描述的内容应该完全符合标准......)
答案 3 :(得分:0)
嗯,蝙蝠,你可以在你的程序启动时计算每个三角形的法线。然后当你实际运行时,你只需要访问法线。为了节省成本,这种启动计算往往会在图形中发生很多。这就是我们在很多视频游戏中都有大量加载屏幕的原因!