繁体   English   中英

如何处理 3D 透视投影中的负深度

[英]How to deal with negative depth in 3D perspective projection

背景

这个问题很相似, 这个问题问3年前。 基本上,我想重新创建一个基本的第一人称图形引擎作为学习体验。

因此,例如,我们在一个 3D 空间中,其中z代表深度 - xy映射到 2D 空间的xy坐标。 如果此坐标系的原点是相机,则(0, 0, 1)处的点将位于相机正前方, (0, 0, -1)处的点将位于相机正后方。

为该投影添加深度只需要我们将xy分量除以depth (在本例中为z )。 在实践中,这对我来说很有意义,而且似乎有效。

直到...

...深度变为负数。 如果深度为负数,并且将xy除以深度,则xy的符号将发生变化。 我们知道,从逻辑上讲,情况不应该是这样。

到目前为止,我已经尝试了几件事:

  • 使用depth的绝对值 - 这并不理想。 假设有一个点(1, 1, 4)(1, 1, -4) 这些点理论上将投影到同一位置。
  • 试图将负值近似为小数。 因此,如果我们有一个负深度,我们会尝试映射正十进制数(0 和 1 之间),允许我们的 x 和 y 坐标延伸到无穷大。 负数越大,我们计算的代表性正小数就越接近零。 我觉得这可能是一个潜在的解决方案,但我仍然在这个概念上有点挣扎。

那么,您如何处理透视投影中的负深度?

我对图形很陌生,所以如果我省略了回答这个问题所需的任何信息,请随时提问。 我想保持这个实现不可知,因为我觉得这个问题更倾向于透视投影的理论方面。

编辑

视频确定了我正在尝试解决的问题。 这是一个很棒的视频,也是我开始这个小项目的灵感来源 - 但我只是想知道是否有一种普遍“同意”的方式来处理这个特殊情况。

您正在进行点投影,这意味着您在 2D 中的投影点正是 3D 对象和 3D 相机之间的线将穿过画布的点。 对于正深度,该交点位于对象和相机之间。 对于负深度,交叉点超出相机。 但它仍然是同一条线,因此交换标志非常有意义。

当然,实际上绘制负深度的东西并没有多大意义,因为通常你不会看到相机后面的东西。 如果你这样做了,那么你就有了一些极广角镜头,所以假设画布是空间中的平面不再准确,你必须切换到更复杂的投影来模拟鱼眼镜头和类似镜头。

然而,您可能想要绘制三角形或其他几何图元,并且只有一个角具有负深度,而其他角具有正深度。 在这种情况下,通常的方法是将对象裁剪到截锥体,更具体地说是将其与截锥体的近平面相交,从而摆脱所有具有负深度的点。 通常您的图形管道可以处理这种剪辑。

我将尝试为任何感兴趣的人提供更数学化的答案。

这背后的数学理论称为射影几何 您从一个三维空间开始,然后将其拆分为等价类,其中两个点ab是等价的,如果存在因子f f*a == b 因此,例如(4, 4, 4)将与(1, 1, 1)属于同一类, (3, 6, 9)将与(100, 200, 300)属于同一类。 从几何上讲,您可以查看通过(0, 0, 0)的一组直线。

如果您从每个等价类中选择z == 1的点,您基本上会得到一个 2D 空间。 这正是“透视投影”的含义。 然而,像(1, 1, 0)这样的点的等价类没有这样的点。 所以你实际上得到的是一个 2D 空间 + 一些额外的“无穷远点”。

您可以将这些点视为围绕您的坐标系的圆,但具有无限半径。 此外,相反的点是相同的,所以从一端出去的东西会环绕并从另一侧回来。 这意味着直线实际上只是包含无穷远点的圆。

举一个具体的例子。 如果要渲染从(1, 1, 4)(1, 1, -4)的直线(1, 1, -4)首先将它们z == 1一化为z == 1 : (0.25, 0.25, 1)(-0.25, -0.25, 1) 但是现在当你在它们之间划线时,你需要“反过来”,即从一个方向离开屏幕,然后从另一侧回来。 (你可以跳过“回来”部分,因为它在相机后面。)

不幸的是,对于实现来说,将(1, 1, -4)映射到(inf, inf, 1)是不够的,因为这样就无法知道直线的斜率。 您可以通过使用非常大的数字而不是无穷大来伪造它,或者您可以正确地使用它并在整个代码中处理这些特殊情况。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM