鼠标坐标到 3D 世界/投影以进行点碰撞

Posted

技术标签:

【中文标题】鼠标坐标到 3D 世界/投影以进行点碰撞【英文标题】:Mouse coordinates to 3D world/projection for point collision 【发布时间】:2015-08-22 16:43:16 【问题描述】:

我通过互联网了解到,将鼠标坐标(或触摸点)转换为 3D 世界并进行“选择 3d 元素”的正确方法是:

    模型、视图和投影相乘 计算逆矩阵 将鼠标坐标存储在具有 [-1,+1] 范围的 Vector 中 将鼠标向量与矩阵相乘 检查坐标作为碰撞检查(在我的例子中,我检查 x 和 y 何时在 [-1, +1] 之间)

当我进行平移、缩放甚至 Z 旋转时,它运行良好,但在我的测试中,它在 X 和 Y 旋转(可能还有其他 3D 扭曲)上失败。我尝试了不同的逆和乘法算法,但都给了我相同的结果。我做错了什么?

有关我的代码中发生的事情的更详细说明,我将尝试在此处解释这 5 个步骤中发生的事情: 最初我有 [-1, +1] 鼠标坐标,当我进行缩放时,我发现标准化的鼠标坐标应该除以缩放值。例如,如果鼠标在 (-0.8, 0.3) 上且矩阵的缩放比例为 0.5, 0.5, 0.5,则鼠标矢量的结果应该是 (-1.6, 0.6) 且没有碰撞点。有了这个,我有了使用逆矩阵的想法。之后我尝试了 X 和 Y 的旋转,从 2D 的角度来看,它与缩放相同:在 X 和 Y 上给出 PI/2,模型看起来像缩放了 0.5。但是将倒置矩阵与向量相乘得到 (-0.4, 0.15) 作为结果,每次使用 X/Y 旋转时都会给我一个误报。

如果您想深入了解我的问题,请随时download and try my code。为了简化阅读,它被精简到最低限度。

【问题讨论】:

【参考方案1】:

我查看了您的代码,但实际上我不确定您所讨论的缩放来自哪里?我看到的是单次旋转,仅此而已。

然而,为了正确地从窗口空间转换回 NDC 空间,您需要考虑透视划分(w,基本上是-z_eye)。绕z轴旋转永远不会改变z坐标;其他两个轴会,这会导致透视投影中的比例发生变化。

但这里最需要注意的是窗口空间w 实际上等于1/clip_w

这可以解释为什么您在此处讨论的缩放比例是倒置的:

例如,如果鼠标在 (-0.8, 0.3) 上且矩阵的缩放比例为 0.5, 0.5, 0.5,则鼠标矢量的结果应该是 (-1.6, 0.6) 且没有碰撞点。有了这个,我有了使用逆矩阵的想法。之后我尝试了 X 和 Y 的旋转,从 2D 的角度来看,它与缩放相同:在 X 和 Y 上给出 PI/2,模型看起来像缩放了 0.5。但是将倒置矩阵与向量相乘得到 (-0.4, 0.15) 作为结果,每次使用 X/Y 旋转时都会给我一个误报。

如果您将比例正确更改为 (1/0.5, 1/0.5, 1/0.5) = (2.0, 2.0, 2.0),那么数学运算就可以了。

【讨论】:

我在创建这篇文章的过程中已经尝试过:vOut.w = 1.0f / vOut.w; vOut.x *= vOut.w; vOut.y *= vOut.w; vOut.z *= vOut.w;但这并不能解决 X 和 Y 旋转的问题。是的,我观察到当向量的 Z 结果不同时,碰撞测试会返回误报,但即使使用 W 处理我也不知道如何解决它。在 -1.0 和 +1.0 之间使用 Z 进行光线跟踪碰撞检查会解决问题还是有其他方法? @user3040937:是的,您完全可以通过将光线从 z= -1.0 投射到 1.0 来解决这个问题(在 NDC 空间中——这个在大多数文档中将是 0.01.0,因为这通常使用窗口空间坐标完成)。但是,老实说,这不是你在这里所做的。你需要计算两个位置并射出一条穿过这两个位置的射线。 射线的使用是后来出现的想法。现在我正在尝试两点之间的交集(mouseX,mouseY,[-1.0,+1.0]),但同样没有成功。我还在以图形方式调试与发生碰撞时绘制到特定像素的函数的交集。 mega.nz/#!BwAgiIKB!YGWolqLTnNjcJFG-u1EYlIgMBrrfTcbzlLbuBV9g110

以上是关于鼠标坐标到 3D 世界/投影以进行点碰撞的主要内容,如果未能解决你的问题,请参考以下文章

电影坐标到世界坐标

unity3D鼠标坐标和世界坐标问题

世界空间逆投影透视

PNP的学习-EPNP

D3.js 世界地图(一)投影方式

关于Unity中坐标系的种类